C語言實現單鏈表,主要功能為空鏈表創建,鏈表初始化(頭插法),鏈表元素讀取,按位置插入,(有序鏈表)按值插入,按位置刪除,按值刪除,清空鏈表,銷毀鏈表。
關鍵思路:(1)將結點創建結構體;(2)鏈表中添加頭結點,以便統一操作;(3)使用結點一級指針和二級指針的異同點;(4)鏈表的最小操作單位是結點;(5)操作的起始位置是頭結點還是第一個結點,及起始索引是0還是1.

1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <time.h> 4 5 //涉及到結構體自引用 6 typedef struct Node{ 7 int data; 8 struct Node *next; 9 }Node; 10 11 //創建空鏈表 12 //必須用二級指針,涉及到頭指針的創建 13 int iniList(Node **List){ 14 *List = (Node *)malloc(sizeof(Node)); 15 if (NULL == *List){ 16 return 0; 17 } 18 19 (*List)->next = NULL; //創建頭結點 20 return 1; 21 } 22 23 //初始化鏈表(頭插法) 24 //必須二級指針 25 int iniListHead(Node **List, int n){ 26 *List = (Node *)malloc(sizeof(Node)); 27 if (NULL == *List){ 28 return 0; 29 } 30 (*List)->next = NULL; 31 srand(time(0)); 32 33 int i = 0; 34 while (i < n){ 35 Node *tmpNode = (Node *)malloc(sizeof(Node)); 36 if (NULL == tmpNode){ 37 return 0; 38 } 39 tmpNode->data = rand() % 100 + 1; 40 tmpNode->next = (*List)->next; 41 (*List)->next = tmpNode; 42 43 44 ++i; 45 } 46 return 1; 47 } 48 49 //初始化鏈表(尾插法) 50 //必須二級指針 51 //需要借助輔助變量pCurrent,將每次尾插的新元素當做當前元素 52 int iniListTail(Node **List, int n){ 53 *List = (Node *)malloc(sizeof(Node)); 54 if (NULL == *List){ 55 return 0; 56 } 57 (*List)->next = NULL; 58 srand(time(0)); 59 60 Node *pCurrent = *List; 61 62 int i = 0; 63 while (i < n){ 64 Node *tmpNode = (Node *)malloc(sizeof(Node)); 65 if (NULL == tmpNode){ 66 return 0; 67 } 68 tmpNode->data = rand() % 100 + 1; 69 tmpNode->next = NULL; 70 pCurrent->next = tmpNode; 71 pCurrent = tmpNode; 72 73 ++i; 74 } 75 return 1; 76 } 77 78 //清空鏈表(不刪除頭結點) 79 //一級,二級指針均可 80 //首先找到鏈表地址,然后移動至表尾 81 //判斷條件為指針域是否為空,即到達結尾 82 int deleteList(Node *List){ 83 84 //這種方法無法刪除尾結點 85 //Node *p= List; 86 //Node *q = NULL; 87 // 88 //while (p->next){ 89 // q = p; 90 // free(p); 91 // p = q->next; 92 //} 93 94 Node *p = List->next; 95 Node *q = NULL; 96 97 while (p){ 98 q = p->next; 99 free(p); 100 p = q; 101 } 102 103 List->next = NULL; 104 return 1; 105 } 106 107 //銷毀鏈表 108 //必須使用二級指針,銷毀頭結點和頭指針 109 //最后將鏈表頭指針置空 110 int desrotyList(Node **List){ 111 112 Node *p = *List; 113 Node *q = NULL; 114 115 //如果為空鏈表,直接刪除頭結點 116 //如果不是空鏈表,從頭結點開始刪除 117 while (p){ 118 q = p->next; 119 free(p); 120 p = q; 121 } 122 (*List) = NULL; 123 124 //下面是從第一個結點開始刪除 125 //最后釋放掉頭結點 126 //Node *p = (*List)->next; 127 //Node *q = NULL; 128 // 129 //while (p){ 130 // q = p->next; 131 // free(p); 132 // p = q; 133 //} 134 //free(*List); 135 //(*List) = NULL; 136 137 return 1; 138 } 139 140 //鏈表獲取元素 141 //一級,二級指針均可 142 //頭結點無意義,從第一個結點開始遍歷,i從1開始 143 //每次都指向下一結點,到pos-1即可 144 int getList(Node *List, int pos, int *element){ 145 Node *p = List->next; 146 147 int i = 1; 148 while (p && i < pos){ 149 p = p->next; 150 ++i; 151 } 152 *element = p->data; 153 return 1; 154 } 155 156 //鏈表按位置插入 157 //一級,二級指針均可 158 //從頭結點開始,有可能插入在第一個位置,遍歷從1開始 159 int insertListPos(Node *List, int pos, int value){ 160 Node *p = List; 161 162 int i = 1; 163 while (p && i < pos){ 164 p = p->next; 165 ++i; 166 } 167 Node *tmpNode = (Node *)malloc(sizeof(Node)); 168 tmpNode->data = value; 169 tmpNode->next = p->next; 170 p->next = tmpNode; 171 return 1; 172 } 173 174 //有序鏈表,按值插入 175 //一二級指針均可 176 int insertListValue(Node *List, int value){ 177 Node *pCur = List->next; 178 Node *pPer = List; 179 while (pCur && pCur->data < value){ 180 pPer = pCur; 181 pCur = pCur->next; 182 } 183 184 Node *tmpNode = (Node *)malloc(sizeof(Node)); 185 if (NULL == tmpNode){ 186 return 0; 187 } 188 tmpNode->data = value; 189 tmpNode->next = pPer->next; 190 pPer->next = tmpNode; 191 return 1; 192 } 193 194 //鏈表按位置刪除 195 //一二級指針均可 196 //記得釋放結點內存 197 //如果刪除第一個結點,需要操縱頭結點 198 int deleteListPos(Node *List, int pos){ 199 Node *p = List; 200 201 int i = 1; 202 while (p && i < pos){ 203 p = p->next; 204 ++i; 205 } 206 if (NULL == p->next) 207 return 0; 208 209 Node *tmpNode = p->next; 210 p->next = p->next->next; 211 212 free(tmpNode); 213 return 1; 214 } 215 216 //鏈表按值刪除元素 217 //一二級指針均可 218 //從第一個結點開始 219 int deleteListValue(Node *List, int value){ 220 Node *pCur = List->next; 221 Node *pPer = List; 222 223 while (pCur && pCur->data != value){ 224 pPer = pCur; 225 pCur = pCur->next; 226 } 227 if (pCur == NULL){ //空鏈表不刪除任何結點 228 return 0; 229 } 230 else{ 231 pPer->next = pCur->next; 232 free(pCur); 233 } 234 return 1; 235 } 236 237 int main(){ 238 239 Node *testList = NULL; 240 iniList(&testList); 241 //iniListHead(&testList, 3); 242 //iniListTail(&testList, 3); 243 244 245 insertListPos(testList, 1, 2); 246 insertListPos(testList, 2, 4); 247 insertListPos(testList, 3, 5); 248 insertListPos(testList, 4, 10); 249 //insertListPos(testList, 1, 1); 250 insertListValue(testList, 1); 251 252 //deleteListPos(testList, 1); 253 //deleteListValue(testList, 4); 254 255 //deleteList(testList); 256 257 //printf("%d\n", testList); 258 //desrotyList(&testList); 259 //printf("%d\n", testList); 260 261 Node * tmpNode = testList->next; 262 while (tmpNode){ 263 printf("%d\n", tmpNode->data); 264 tmpNode = tmpNode->next; 265 } 266 267 printf("----------------------\n"); 268 269 int a = 0; 270 getList(testList, 2, &a); 271 printf("%d\n", a); 272 273 system("pause"); 274 275 return 0; 276 }
通過C++實現C語言的鏈表,主要區別:(1)struct可以不通過typedef,直接使用Node;(2)將malloc和free更換為new和delete

1 #include<iostream> 2 #include<ctime> 3 4 using namespace std; 5 6 struct Node{ 7 int data; 8 Node *next; 9 }; 10 11 //創建空鏈表 12 //必須用二級指針,涉及到頭指針的創建 13 int iniList(Node **List){ 14 *List = new Node; 15 16 (*List)->next = NULL; //創建頭結點 17 return 1; 18 } 19 20 //初始化鏈表(頭插法) 21 //必須二級指針 22 int iniListHead(Node **List, int n){ 23 *List = new Node; 24 25 (*List)->next = NULL; 26 srand(time(0)); 27 28 int i = 0; 29 while (i < n){ 30 Node *tmpNode = new Node; 31 32 tmpNode->data = rand() % 100 + 1; 33 tmpNode->next = (*List)->next; 34 (*List)->next = tmpNode; 35 36 ++i; 37 } 38 return 1; 39 } 40 41 //初始化鏈表(尾插法) 42 //必須二級指針 43 //需要借助輔助變量pCurrent,將每次尾插的新元素當做當前元素 44 int iniListTail(Node **List, int n){ 45 *List = new Node; 46 47 (*List)->next = NULL; 48 srand(time(0)); 49 50 Node *pCurrent = *List; 51 52 int i = 0; 53 while (i < n){ 54 Node *tmpNode = new Node; 55 56 tmpNode->data = rand() % 100 + 1; 57 tmpNode->next = NULL; 58 pCurrent->next = tmpNode; 59 pCurrent = tmpNode; 60 61 ++i; 62 } 63 return 1; 64 } 65 66 //清空鏈表(不刪除頭結點) 67 //一級,二級指針均可 68 //首先找到鏈表地址,然后移動至表尾 69 //判斷條件為指針域是否為空,即到達結尾 70 int deleteList(Node *List){ 71 72 //這種方法無法刪除尾結點 73 //Node *p= List; 74 //Node *q = NULL; 75 // 76 //while (p->next){ 77 // q = p; 78 // free(p); 79 // p = q->next; 80 //} 81 82 Node *p = List->next; 83 Node *q = NULL; 84 85 while (p){ 86 q = p->next; 87 delete p; 88 p = q; 89 } 90 91 List->next = NULL; 92 return 1; 93 } 94 95 //銷毀鏈表 96 //必須使用二級指針,銷毀頭結點和頭指針 97 //最后將鏈表頭指針置空 98 int desrotyList(Node **List){ 99 100 Node *p = *List; 101 Node *q = NULL; 102 103 //如果為空鏈表,直接刪除頭結點 104 //如果不是空鏈表,從頭結點開始刪除 105 while (p){ 106 q = p->next; 107 delete p; 108 p = q; 109 } 110 (*List) = NULL; 111 112 //下面是從第一個結點開始刪除 113 //最后釋放掉頭結點 114 //Node *p = (*List)->next; 115 //Node *q = NULL; 116 // 117 //while (p){ 118 // q = p->next; 119 // free(p); 120 // p = q; 121 //} 122 //free(*List); 123 //(*List) = NULL; 124 125 return 1; 126 } 127 128 //鏈表獲取元素 129 //一級,二級指針均可 130 //頭結點無意義,從第一個結點開始遍歷,i從1開始 131 //每次都指向下一結點,到pos-1即可 132 int getList(Node *List, int pos, int *element){ 133 Node *p = List->next; 134 135 int i = 1; 136 while (p && i < pos){ 137 p = p->next; 138 ++i; 139 } 140 *element = p->data; 141 return 1; 142 } 143 144 //鏈表按位置插入 145 //一級,二級指針均可 146 //從頭結點開始,有可能插入在第一個位置,遍歷從1開始 147 int insertListPos(Node *List, int pos, int value){ 148 Node *p = List; 149 150 int i = 1; 151 while (p && i < pos){ 152 p = p->next; 153 ++i; 154 } 155 Node *tmpNode = new Node; 156 tmpNode->data = value; 157 tmpNode->next = p->next; 158 p->next = tmpNode; 159 return 1; 160 } 161 162 //有序鏈表,按值插入 163 //一二級指針均可 164 int insertListValue(Node *List, int value){ 165 Node *pCur = List->next; 166 Node *pPer = NULL; 167 while (pCur && pCur->data < value){ 168 pPer = pCur; 169 pCur = pCur->next; 170 } 171 172 Node *tmpNode = new Node; 173 if (NULL == tmpNode){ 174 return 0; 175 } 176 tmpNode->data = value; 177 tmpNode->next = pPer->next; 178 pPer->next = tmpNode; 179 return 1; 180 } 181 182 //鏈表按位置刪除 183 //一二級指針均可 184 //記得釋放結點內存 185 //如果刪除第一個結點,需要操縱頭結點 186 int deleteListPos(Node *List, int pos){ 187 Node *p = List; 188 189 int i = 1; 190 while (p && i < pos){ 191 p = p->next; 192 ++i; 193 } 194 Node *tmpNode = p->next; 195 p->next = p->next->next; 196 197 delete tmpNode; 198 return 1; 199 } 200 201 //鏈表按值刪除元素 202 //一二級指針均可 203 //從第一個結點開始 204 int deleteListValue(Node *List, int value){ 205 Node *pCur = List->next; 206 Node *pPer = List; 207 208 while (pCur && pCur->data != value){ 209 pPer = pCur; 210 pCur = pCur->next; 211 } 212 if (pCur == NULL){ 213 return 0; 214 } 215 else{ 216 pPer->next = pCur->next; 217 delete pCur; 218 } 219 return 1; 220 }
結點結構體
將結點創建為結構體,其中包含數據域和指針域成員,指針域涉及結構體自引用。指針域成員之所以為結點類指針,一是為了編譯時能明確結構體大小,二是為了指向下一個結點,因此初始化時不用開辟內存,只需要賦值為NULL即可。當然了,開辟內存也是可以的,這樣在刪除結點,及清空鏈表時需要記得將其釋放,多此一舉,不提倡。
1 //涉及到結構體自引用 2 typedef struct Node{ 3 int data; 4 struct Node *next; 5 }Node;
空鏈表創建(二級指針)
空鏈表創建時,建議創建頭結點。在插入和刪除第一個位置的元素時,需要用結點的二級指針移動頭指針,但普通結點的插入和刪除並不需要移動頭指針。為了便於操作的統一(指插入和刪除操作),這里先創建頭結點。
另外,在創建空鏈表時,需要傳入二級指針,主要是為了操作頭指針,只要涉及操作頭指針的都需要使用二級指針。
1 //創建空鏈表 2 //必須用二級指針,涉及到頭指針的創建 3 int iniList(Node **List){ 4 *List = (Node *)malloc(sizeof(Node)); 5 if (NULL == *List){ 6 return 0; 7 } 8 9 (*List)->next = NULL; //創建頭結點,將其指針域置空 10 return 1; 11 }
鏈表初始化(二級指針)
鏈表初始化,即是創建空鏈表,並對鏈表中的n個元素進行賦值。一般來說,有頭插法、尾插法兩種,頭插法是在頭結點后插入,尾插法是在鏈表尾插入。
頭插法
頭插法一般思路:(1)創建帶頭結點的空鏈表;(2)創建新結點,對新結點賦值;(3)新結點指向頭結點的下一個結點,頭結點指向新結點。
1 //初始化鏈表(頭插法) 2 //必須二級指針 3 int iniListHead(Node **List, int n){ 4 *List = (Node *)malloc(sizeof(Node)); 5 if (NULL == *List){ 6 return 0; 7 } 8 (*List)->next = NULL; 9 srand(time(0)); 10 11 int i = 0; 12 while (i < n){ 13 Node *tmpNode = (Node *)malloc(sizeof(Node)); 14 if (NULL == tmpNode){ 15 return 0; 16 } 17 tmpNode->data = rand() % 100 + 1; 18 tmpNode->next = (*List)->next; 19 (*List)->next = tmpNode; 20 21 22 ++i; 23 } 24 return 1; 25 }
尾插法
尾插法一般思路:(1)創建帶頭結點的空鏈表;(2)創建新結點,對新結點數據域賦值,指針域置空;(3)建立臨時變量指向頭結點,頭結點指向新結點;(4)將臨時變量往后移動,指向新結點。
1 //初始化鏈表(尾插法) 2 //必須二級指針 3 //需要借助輔助變量pCurrent,將每次尾插的新元素當做當前元素 4 int iniListTail(Node **List, int n){ 5 *List = (Node *)malloc(sizeof(Node)); 6 if (NULL == *List){ 7 return 0; 8 } 9 (*List)->next = NULL; 10 srand(time(0)); 11 12 Node *pCurrent = *List; 13 14 int i = 0; 15 while (i < n){ 16 Node *tmpNode = (Node *)malloc(sizeof(Node)); 17 if (NULL == tmpNode){ 18 return 0; 19 } 20 tmpNode->data = rand() % 100 + 1; 21 tmpNode->next = NULL; 22 pCurrent->next = tmpNode; 23 pCurrent = tmpNode; 24 25 ++i; 26 } 27 return 1; 28 }
鏈表元素讀取(一、二級指針)
鏈表元素讀取,需要涉及到索引位置。我們知道頭結點的數據域沒有意義,因此起始位置從第一個結點開始,遍歷值從1開始,到pos-1為止,此時p指向pos結點。
1 //鏈表獲取元素 2 //一級,二級指針均可 3 //頭結點無意義,從第一個結點開始遍歷,i從1開始 4 //每次都指向下一結點,到pos-1即可 5 int getList(Node *List, int pos, int *element){ 6 Node *p = List->next; 7 8 int i = 1; 9 while (p && i < pos){ 10 p = p->next; 11 ++i; 12 } 13 *element = p->data; 14 return 1; 15 }
按位置插入(一、二級指針)
插入時,需要考慮任意位置,由於頭結點的設立,我們不需要單獨考慮第一個位置的結點插入。
一般思路:(1)起始位置從頭結點開始,遍歷值從1開始,到pos-1為止,此時指向pos-1結點;(2)創建新結點,給新結點數據域賦值;(3)新結點指向pos位置的下一結點,pos位置指向新結點。
1 //鏈表按位置插入 2 //一級,二級指針均可 3 //從頭結點開始,有可能插入在第一個位置,遍歷從1開始 4 int insertListPos(Node *List, int pos, int value){ 5 Node *p = List; 6 7 int i = 1; 8 while (p && i < pos){ 9 p = p->next; 10 ++i; 11 } 12 Node *tmpNode = (Node *)malloc(sizeof(Node)); 13 tmpNode->data = value; 14 tmpNode->next = p->next; 15 p->next = tmpNode; 16 return 1; 17 }
有序鏈表按值插入(一、二級指針)
有序鏈表中涉及到按值插入,按值刪除時,需要建立兩個臨時變量,不同於按位置插入,我們可以在pos前一個停止遍歷,按值插入,我們需要遍歷找到插入位置,操作插入位置的前一個結點。
一般思路:(1)從第一個結點開始遍歷;(2)創建per變量標記當前結點的前一結點;(3)創建新結點,操作per結點;(4)常規插入操作。
1 //有序鏈表,按值插入 2 //一二級指針均可 3 int insertListValue(Node *List, int value){ 4 Node *pCur = List->next; 5 Node *pPer = NULL; 6 while (pCur && pCur->data < value){ 7 pPer = pCur; 8 pCur = pCur->next; 9 } 10 11 Node *tmpNode = (Node *)malloc(sizeof(Node)); 12 if (NULL == tmpNode){ 13 return 0; 14 } 15 tmpNode->data = value; 16 tmpNode->next = pPer->next; 17 pPer->next = tmpNode; 18 return 1; 19 }
按位置刪除(一、二級指針)
刪除時,由於頭結點的設立,因此不需要特殊考慮第一個位置的操作和頭指針的移動。需要設置臨時變量是釋放p->next后,后面還會使用p->next的結點,這樣會造成訪問出錯。
一般思路:(1)起始位置從頭結點開始,遍歷從1開始,到pos-1為止,此時指向pos-1結點;(2)創建臨時變量,指向pos結點;(3)將pos-1結點指向pos的下一結點,釋放掉pos結點。
1 //鏈表按位置刪除 2 //一二級指針均可 3 //記得釋放結點內存 4 //如果刪除第一個結點,需要操縱頭結點 5 int deleteListPos(Node *List, int pos){ 6 Node *p = List; 7 8 int i = 1; 9 while (p && i < pos){ 10 p = p->next; 11 ++i; 12 } 13 Node *tmpNode = p->next; 14 p->next = p->next->next; 15 16 free(tmpNode); 17 return 1; 18 }
按值刪除(一、二級指針)
按值刪除與按值插入一樣,需要兩個臨時變量。
一般思路:(1)起始位置從第一個結點開始,(2)設立per結點指針保存當前結點的上一結點;(3)常規刪除操作。
1 //鏈表按值刪除元素 2 //一二級指針均可 3 //從第一個結點開始 4 int deleteListValue(Node *List, int value){ 5 Node *pCur = List->next; 6 Node *pPer = List; 7 8 while (pCur && pCur->data != value){ 9 pPer = pCur; 10 pCur = pCur->next; 11 } 12 if (pCur == NULL){ //空鏈表不刪除任何結點 13 return 0; 14 } 15 else{ 16 pPer->next = pCur->next; 17 free(pCur); 18 } 19 return 1; 20 }
清空鏈表(一、二級指針)
清空鏈表,只是將鏈表中的結點刪除,並釋放掉結點空間,保留頭結點,並將頭結點的指針域置空。
一般思路:(1)起始位置從第一個結點開始;(2)設置臨時變量q指向當前結點p的下一結點,釋放掉當前結點p,將臨時變量q賦給p;(3)最后將頭結點的指針置空。
1 //清空鏈表(不刪除頭結點) 2 //一級,二級指針均可 3 //首先找到鏈表地址,然后移動至表尾 4 //判斷條件為指針域是否為空,即到達結尾 5 int deleteList(Node *List){ 6 7 //這種方法無法刪除尾結點,當p->next是尾結點上一節點時,走一遍程序 8 //Node *p= List; 9 //Node *q = NULL; 10 // 11 //while (p->next){ 12 // q = p; 13 // free(p); 14 // p = q->next; 15 //} 16 17 Node *p = List->next; 18 Node *q = NULL; 19 20 while (p){ 21 q = p->next; 22 free(p); 23 p = q; 24 } 25 26 List->next = NULL; 27 return 1; 28 }
銷毀鏈表(二級指針)
銷毀鏈表,是在清空鏈表的基礎上,刪除頭結點,將頭指針置空,涉及到頭指針的操作,需要二級指針。
思路一:(1)與清空鏈表操作相同,從第一個結點開始刪除;(2)最后釋放掉頭結點,將頭指針置空
思路二:(1)起始位置從頭結點開始刪除;(2)將頭指針置空
1 //銷毀鏈表 2 //必須使用二級指針,銷毀頭結點和頭指針 3 //最后將鏈表頭指針置空 4 int desrotyList(Node **List){ 5 6 Node *p = *List; 7 Node *q = NULL; 8 9 //如果為空鏈表,直接刪除頭結點 10 //如果不是空鏈表,從頭結點開始刪除 11 while (p){ 12 q = p->next; 13 free(p); 14 p = q; 15 } 16 (*List) = NULL; 17 18 //下面是從第一個結點開始刪除 19 //最后釋放掉頭結點 20 //Node *p = (*List)->next; 21 //Node *q = NULL; 22 // 23 //while (p){ 24 // q = p->next; 25 // free(p); 26 // p = q; 27 //} 28 //free(*List); 29 //(*List) = NULL; 30 31 return 1; 32 }
二級指針和一級指針插入解析
-------------------------------------------------------------------------------------------------------------
如果上面的資料對你有啟發,麻煩點個推薦,讓更多人的人看到哦。
關注公眾號【兩猿社】,懂點互聯網,懂點IC的程序猿,帶你豐富項目經驗哦。