鏈表在數據結構和算法中的重要性不言而喻。這裡我們要用C來實現鏈表(單鏈表)中的基本操作。對於鏈表的基本概念請參考《數據結構與算法之鏈表》這篇博客。
(1)定義單鏈表的節點類型
typedef int elemType ; // 定義單鏈表結點類型 typedef struct ListNode{ elemType element; //數據域 struct ListNode *next; //地址域 }Node;(2)初始化線性表
// 1.初始化線性表,即置單鏈表的表頭指針為空 void initList(Node *pNode){ pNode = NULL; printf("%s函數執行,初始化成功\n",__FUNCTION__); }當聲明一個頭結點後,把該頭結點設置為空,即把數據域和地址域都設為空,即可完成該鏈表的初始化。
(3)創建線性表
// 2.創建線性表,此函數輸入負數終止讀取數據 Node *creatList(Node *pHead){ Node *p1;//表頭節點,始終指向頭結點 Node *p2;//表尾節點,始終指向鏈表的最後一個元素 p1 = p2 = (Node *)malloc(sizeof(Node)); //申請新節點,分配空間 if(p1 == NULL || p2 == NULL){ printf("內存分配失敗\n"); exit(0); } memset(p1,0,sizeof(Node)); scanf("%d",&p1->element); //輸入新節點的值 p1->next = NULL; //新節點的指針置為空 while(p1->element > 0){ //輸入的值大於0則繼續,直到輸入的值為負 if(pHead == NULL){ //空表,接入表頭 pHead = p1; //直接把p1作為頭結點,也可以理解為把pHead頭結點指向p1 }else{ p2->next = p1; //非空表,接入表尾 } p2 = p1; //p1插入後,p1就是尾結點,所以p2要指向尾結點 p1 = (Node *)malloc(sizeof(Node)); //再重申請一個節點 if(p1 == NULL || p2 == NULL){ printf("內存分配失敗\n"); exit(0); } memset(p1,0,sizeof(Node)); scanf("%d",&p1->element); p1->next = NULL; } printf("%s函數執行,鏈表創建成功\n",__FUNCTION__); return pHead; //返回鏈表的頭指針 }我這裡使用手動的方式輸入元素,直到輸入0或者負數停止。
(4)打印鏈表
// 3.打印鏈表,鏈表的遍歷 void printList(Node *pHead){ if(NULL == pHead){ //鏈表為空 printf("%s函數執行,鏈表為空\n",__FUNCTION__); }else{ while(NULL != pHead){ printf("%d ",pHead->element); pHead = pHead->next; } printf("\n"); } }使用地址域順序打印即可。
(5)清空鏈表
// 4.清除線性表L中的所有元素,即釋放單鏈表L中所有的結點,使之成為一個空表 void clearList(Node *pHead){ Node *pNext; //定義一個與pHead相鄰節點,理解為當前節點的下一個節點 if(pHead == NULL){ printf("%s函數執行,鏈表為空\n",__FUNCTION__); } while(pHead->next != NULL){ pNext = pHead->next;//保存下一結點的指針 free(pHead); //釋放當前節點 pHead = pNext; //指向下一個節點 } printf("%s函數執行,鏈表已經清除\n",__FUNCTION__); }想要檢驗是否清空成功,可以使用(4)中的鏈表打印檢驗即可。
(6)計算鏈表長度
// 5.返回單鏈表的長度 int sizeList(Node *pHead){ int size = 0; while(pHead != NULL){ size++; pHead = pHead->next; } printf("%s函數執行,鏈表長度 %d \n",__FUNCTION__,size); return size; //鏈表的實際長度 }也就是計算有多少個節點。
(7)判斷鏈表是否為空
// 6.檢查單鏈表是否為空,若為空則返回1,否則返回0 int isEmptyList(Node *pHead){ if(pHead == NULL){ printf("%s函數執行,鏈表為空\n",__FUNCTION__); return 1; } printf("%s函數執行,鏈表非空\n",__FUNCTION__); return 0; }
// 7.返回單鏈表中第pos個結點中的元素,若pos超出范圍,則停止程序運行 void getElement(Node *pHead, int pos){ int i = 0; if(pos < 1){ printf("%s函數執行,pos值非法\n",__FUNCTION__); } if(pHead == NULL){ printf("%s函數執行,鏈表為空\n",__FUNCTION__); } while(pHead != NULL){ i++; if(i == pos){ break; } pHead = pHead->next; //移到下一結點 } if(i < pos){ //pos值超過鏈表長度 printf("%s函數執行,pos值超出鏈表長度\n",__FUNCTION__); } printf("%s函數執行,位置 %d 中的元素為 %d\n",__FUNCTION__,pos,pHead->element); }
// 8.從單鏈表中查找具有給定值x的第一個元素,若查找成功則返回該結點data域的存儲地址,否則返回NULL elemType* getElemAddr(Node *pHead, elemType x){ if(NULL == pHead){ printf("%s函數執行,鏈表為空\n",__FUNCTION__); return NULL; } while((pHead->element != x) && (NULL != pHead->next)) {//判斷是否到鏈表末尾,以及是否存在所要找的元素 pHead = pHead->next; } if((pHead->element != x) && (pHead != NULL)){ //當到達最後一個節點 printf("%s函數執行,在鏈表中未找到x值\n",__FUNCTION__); return NULL; } if(pHead->element == x){ printf("%s函數執行,元素 %d 的地址為 0x%x\n",__FUNCTION__,x,&(pHead->element)); } return &(pHead->element);//返回元素的地址 }
(10)修改某個節點的值
// 9.把單鏈表中第pos個結點的值修改為x的值,若修改成功返回1,否則返回0 int modifyElem(Node *pNode,int pos,elemType x){ int i = 0; if(NULL == pNode){ printf("%s函數執行,鏈表為空\n",__FUNCTION__); return 0; } if(pos < 1){ printf("%s函數執行,pos值非法\n",__FUNCTION__); return 0; } while(pNode != NULL){ i++; if(i == pos){ break; } pNode = pNode->next; //移到下一結點 } if(i < pos) { //pos值大於鏈表長度 printf("%s函數執行,pos值超出鏈表長度\n",__FUNCTION__); return 0; } pNode->element = x; printf("%s函數執行\n",__FUNCTION__); return 1; }(11)表頭插入一個節點(頭節點)
// 10.向單鏈表的表頭插入一個元素 int insertHeadList(Node **pNode,elemType insertElem){ Node *pInsert; pInsert = (Node *)malloc(sizeof(Node)); memset(pInsert,0,sizeof(Node)); pInsert->element = insertElem; pInsert->next = *pNode; *pNode = pInsert; //頭節點*pNode指向剛插入的節點,注意和上一行代碼的前後順序; printf("%s函數執行,向表頭插入元素成功\n",__FUNCTION__); return 1; }(12)表尾插入一個節點
// 11.向單鏈表的末尾添加一個元素 int insertLastList(Node **pNode,elemType insertElem){ Node *pInsert; Node *pHead; pHead = *pNode; pInsert = (Node *)malloc(sizeof(Node)); //申請一個新節點 memset(pInsert,0,sizeof(Node)); pInsert->element = insertElem; while(pHead->next != NULL){ pHead = pHead->next; } pHead->next = pInsert; //將鏈表末尾節點的下一結點指向新添加的節點 printf("%s函數執行,向表尾插入元素成功\n",__FUNCTION__); return 1; }(13)測試函數
int main(int argc, const char * argv[]) { Node *pList; //聲明頭結點 initList(pList); //鏈表初始化 printList(pList); //遍歷鏈表,打印鏈表 pList = creatList(pList); //創建鏈表 printList(pList); sizeList(pList); //鏈表的長度 printList(pList); isEmptyList(pList); //判斷鏈表是否為空鏈表 getElement(pList,3); //獲取第三個元素,如果元素不足3個,則返回0 printList(pList); getElemAddr(pList,5); //獲得元素5的內存地址 modifyElem(pList,4,1); //將鏈表中位置4上的元素修改為1 printList(pList); insertHeadList(&pList,5); //表頭插入元素5 printList(pList); insertLastList(&pList,10); //表尾插入元素10 printList(pList); clearList(pList); //清空鏈表 printList(pList); return 0; }