1、用於存放聲明的標頭檔
#define _CRT_SECURE_NO_WARNINGS#pragma once#include <stdio.h>#include <assert.h>#include <malloc.h>typedef int DataType;typedef struct SListNode{ DataType data; //鏈表中存放的資料 struct SListNode *pNextNode; //指向下一節點的指標}SListNode, *PSListNode;// 初始化單鏈表(對於無頭結點單鏈表,該函數沒有意義)void InitList(PSListNode* pHead);// 銷毀單鏈表void DestroyList(PSListNode* pHead);// 尾插void PushBack(PSListNode* pHead, DataType data);// 尾出void PopBack(PSListNode* pHead);// 頭插void PushFront(PSListNode* pHead, DataType data);// 頭出void PopFront(PSListNode* pHead);// 在鏈表中尋找元素dataPSListNode Find(PSListNode pHead, DataType data);// 刪除pos位置的結點(注意不能用那種替換形式)void Erase(PSListNode* pHead, PSListNode pos);// 在鏈表的pos位置插入元素datavoid Insert(PSListNode* pHead, PSListNode pos, DataType data);//列印鏈表存放的資料void PrintList(PSListNode pHead);
2、用於實現聲明的.c檔案
#include "SListNode.h"//這兒的參數是二級指標,因為要對結構體指標的內容進行修改,所以必須傳該指標的地址(即一個二級指標)//傳一級指標的話相當於是值傳遞,不會對實參有改變void InitList(PSListNode* pHead){ assert(pHead); *pHead = NULL;}PSListNode ByeNode(DataType data){ PSListNode pNewNode = (PSListNode)malloc(sizeof(struct SListNode)); if (NULL != pNewNode) { pNewNode->data = data; //注意使開闢的新節點的指向為空白 pNewNode->pNextNode = NULL; } return pNewNode;}void PushBack(PSListNode* pHead, DataType data){ PSListNode pNode = NULL; PSListNode pNewNode = NULL; assert(pHead); if (NULL == (*pHead)) { //此時可以不對ByeNode函數是否成功開闢空間做檢測,因為即使它沒有開闢成功空間, //那麼使頭結點頭結點等於NULL邏輯一樣正確 *pHead = ByeNode(data); } else { pNode = *pHead; //找到尾節點 while (NULL != pNode->pNextNode) { //儲存尾節點 pNode = pNode->pNextNode; } pNewNode = ByeNode(data); //當開闢空間失敗,說明向鏈表裡插入了一個null 指標 pNode->pNextNode = pNewNode; }}void PopBack(PSListNode* pHead){ PSListNode pPerNode = NULL; PSListNode pCurNode = NULL; assert(pHead); if (NULL == (*pHead)) { printf("鏈表中沒有資料節點。\n"); } else { pCurNode = *pHead; //注意迴圈結束的條件 while (NULL != pCurNode->pNextNode) { pPerNode = pCurNode; pCurNode = pCurNode->pNextNode; } //把要刪除的結點從鏈表中斷開(讓該節點的上一個結點指向該結點的下一個結點) pPerNode->pNextNode = NULL; //刪除該結點 free(pCurNode); pCurNode = NULL; }}void PushFront(PSListNode* pHead, DataType data){ assert(pHead); if (NULL == (*pHead)) { //此時可以不對ByeNode函數是否成功開闢空間做檢測,因為即使它沒有開闢成功空間, //那麼使頭結點頭結點等於NULL邏輯一樣正確 *pHead = ByeNode(data); } else { PSListNode pNewNode = ByeNode(data); if (NULL == pNewNode) { printf("開闢節點空間失敗。\n"); } else { //使指向頭結點的指標指向新開闢的節點,新開闢的節點指向鏈表中原來的頭結點 pNewNode->pNextNode = *pHead; *pHead = pNewNode; } }}void PopFront(PSListNode* pHead){ assert(pHead); if (NULL == (*pHead)) { printf("鏈表中沒有資料節點。\n"); } else { PSListNode pNode = *pHead; //直接使頭結點指向鏈表中第三個節點,即可做到頭刪的目的 *pHead = (*pHead)->pNextNode; free(pNode); pNode = NULL; }}PSListNode Find(PSListNode pHead, DataType data){ PSListNode pNode = pHead; while (NULL != pNode) { if (pNode->data == data) { return pNode; } else { pNode = pNode->pNextNode; } } //沒有找到對應的結點 return NULL;}void Erase(PSListNode* pHead, PSListNode pos){ //更簡單的方法(pos指向的結點在鏈表中): //直接交換pos指向的節點和pos指向的節點的下一個結點的資料,然後使pos指向的節點的下一個結點為它的下下一個結點 PSListNode pCurNode = *pHead; PSListNode pPerNode = *pHead; assert(pHead); if (NULL == pos) { return; } //要是傳的參數沒有在鏈表中,那麼刪除就顯得沒有意義了,因此對pos的檢測(pos是否是鏈表中的某個節點)可有可無 while ((pCurNode != pos) && (pCurNode != NULL)) { pPerNode = pCurNode; pCurNode = pCurNode->pNextNode; } //使當前結點的上一個結點指向當前結點的下一個結點,然後釋放當前結點的空間,即可做到刪除當前結點 pPerNode->pNextNode = pPerNode->pNextNode->pNextNode; free(pCurNode); pCurNode = NULL;}void Insert(PSListNode* pHead, PSListNode pos, DataType data){ //更簡單的方法(pos指向的結點在鏈表中): //直接交換pos指向的節點和新插入的節點的的資料,然後使新插入的結點的下一個結點為pos指向的節點的下一個結點, //pos指向的節點的下一個結點為新插入的結點 PSListNode pTempNode = *pHead; PSListNode pNode = *pHead; assert(pHead); //pTempNode!=NULL是為了避免pos是一個建立的孤結點,它沒有插入到鏈表中 while ((pTempNode != pos) && (pTempNode != NULL)) { pNode = pTempNode; pTempNode = pTempNode->pNextNode; } if ((pTempNode == NULL) && (pos != NULL)) { printf("鏈表中不存在該結點!\n"); return; } else { PSListNode pNewNode = ByeNode(data); if (NULL == pNewNode) { printf("開闢空間失敗。\n"); } else { pNewNode->pNextNode = pNode->pNextNode; pNode->pNextNode = pNewNode; } }}void PrintList(PSListNode pHead){ PSListNode pNode = pHead; //當pHead指向空時,說明此時鏈表中沒有資料,那麼不會進入列印資料的迴圈,而是等到函數結束返回 while (NULL != pNode) { printf("%d ", pNode->data); pNode = pNode->pNextNode; } printf("\n");}void DestroyList(PSListNode* pHead){ PSListNode pCurNode = NULL; PSListNode pPerNode = *pHead; assert(pHead); while (NULL != pCurNode) { //每次銷毀鏈表最前面那個結點的空間 pPerNode = pCurNode->pNextNode; free(pCurNode); //不會出現野指標 pCurNode = pPerNode; }}
3、用於測試函數正確性的Test.c檔案
#include "SListNode.h"//Test PushBack() / PopBack()void TestFun1(){ PSListNode pHead = NULL; InitList(&pHead); PushBack(&pHead, 0); PushBack(&pHead, 1); PushBack(&pHead, 2); PushBack(&pHead, 3); PrintList(pHead); PopBack(&pHead); PopBack(&pHead); PrintList(pHead);}//Test PushFront() / PopFront()void TestFun2(){ PSListNode pHead = NULL; InitList(&pHead); PushFront(&pHead, 0); PushFront(&pHead, 1); PushFront(&pHead, 2); PushFront(&pHead, 3); PrintList(pHead); PopFront(&pHead); PopFront(&pHead); PrintList(pHead);}//Test Find() / Erase() / Insert()void TestFun3(){ PSListNode pHead = NULL; PSListNode pRetNode = NULL; InitList(&pHead); PushBack(&pHead, 0); PushBack(&pHead, 1); PushBack(&pHead, 2); PushBack(&pHead, 3); PrintList(pHead); pRetNode = Find(pHead, 2); printf("%d\n", pRetNode->data); Erase(&pHead, Find(pHead, 1)); PrintList(pHead); Insert(&pHead, Find(pHead, 2), 1); PrintList(pHead);}//Test DestroyList()void TestFun4(){ PSListNode pHead = NULL; InitList(&pHead); PushBack(&pHead, 0); PushBack(&pHead, 1); PushBack(&pHead, 2); PushBack(&pHead, 3); DestroyList(&pHead); PrintList(pHead);}int main(){ //TestFun1(); //TestFun2(); //TestFun3(); TestFun4(); system("pause"); return 0;}