C語言單鏈表基本操作總結
連結串列是一種常見的資料結構。它與常見的陣列是不同的,使用陣列時先要指定陣列包含元素的個數,即為陣列的長度,但是如果向這個陣列中加入的元素超過了陣列的大小時,便不能將內容全部儲存。
連結串列這種儲存方式,其元素個數是不受限定的,當進行新增元素的時候儲存的個數就會隨之改變。
在連結串列中有一個頭指標變數,這個指標變數儲存一個地址,通過這個地址來找到這個連結串列,頭指標節點指向第一個節點,在連結串列中每個節點包含兩個部分:資料部分和指標部分。雖然結構體不能含有與本身型別相同的結構,但是可以含有之相同型別結構的指標,這種定義是連結串列的基礎,連結串列中每一項都包含在何處能找到下一項的資訊。而最後一個節點的指標指向必須為空NULL,從連結串列的原理來看不用擔心連結串列的長度會超出範圍這種問題。
建立節點(結構體)
typedef struct Node { int num; struct Node* next; }pnote;
定義全域性變數(鏈錶頭尾指標) 方便呼叫
ponte* head = NULL;
pnote* end = NULL;
連結串列的建立
void AddListTill(int n) { pnote* pnode; for (int i = 0; i < n; i++) { pnode = (pnote*)malloc(sizeof(pnote)); srand(time(NULL)); pnode->num = rand() % 100; if (i == 0) head = end = pnode; else { end->next = pnode; pnode->next = NULL; end = pnode; } } }
該函式的功能是在尾新增的方式在鏈錶尾部增加一個節點,首先建立一個節點並申請一個節點的記憶體,然後對傳入節點的資料進行賦值,注意尾新增的新節點的指標應指向空。此時分為兩種情況:1.鏈錶無節點,那麼這個節點既是頭結點也是尾節點;2.已經有節點,那麼新增加的節點將成為最後一個節點,而之前的節點成為倒數第二個節點,所以它的指標應該指向新新增的節點,之後全域性變數應指向當前節點。(操作先後順序不變)
遍歷鏈錶
void ScanList() { pnote* temp = head; while(temp) { printf("%d\n", temp->num); temp = temp->next; } }
該函式的功能是遍歷輸出這個鏈錶,首先定義一個用於遍歷的臨時指標,用while迴圈實現遍歷輸出的操作
查詢指定節點(遍歷)
pnote* FindNode(int a) { pnote* temp = head; while(temp) { if(a = temp->num) return temp; temp = temp->next; } //沒找到 return NULL; }
該函式的功能是遍歷陣列,對每個節點進行一一判斷,若找到則返回該節點,沒找到則返回NULL。
鏈錶清空(全部刪除)
void FreeList() { pnote* temp = head; while(temp) { pnote* pt = temp; temp = temp->next; free(pt);//釋放當前 } //頭尾清空 head = NULL; end = NULL; }
該函式的功能是一個一個的將節點記憶體釋放,最後達到全部刪除的效果。要注意的是最後應將頭尾節點至NULL,否則下次的頭節點就接著0x10。
在指定位置插入節點
void AddListRand(int index, int a) { if(head == NULL) { printf("No nodes in the linked list.\n"); return; } pnote* pt = FindNote(index); if(pt == NULL) //無此節點 { printf("No nodes in the linked list.\n"); return; } //有此節點 //建立節點,申請記憶體 pnote* temp = (pnote*)malloc(sizeof(pnote)); temp->num = a; temp->next = NULL; //兩種情況:1.節點在尾部;2.節點在中間 if(pt = end) { end->next = temp; end = temp; } else { temp->next = pt->next; pt->next = temp; } }
此函式關鍵在於兩種情況的判斷,要注意的是若插入的節點位置在中間,那麼要先連後面再連前面。
尾刪除
void DeleteLiseTail() { if(end == NULL) { printf("The linked list is empty, no need to delete.\n"); return; } //鏈錶不為空 if(head == end) { free(head); head = NULL; end = NULL; } else { pnote* temp = head; while(temp->next != end) temp = temp->next; free(end); end = temp; end->next = NULL; } }
尾刪除應先判斷鏈錶是否為空或者只有一個節點,若只有一個節點則直接置NULL,若不為空,則遍歷找到倒數第二個節點,將最後一個節點釋放記憶體,再將倒數第二個節點設定為end,然後將它的指標指向NULL。
頭刪除
void DeleteLiseHead() { pnote* temp = head; if(head == NULL) { printf("The linked list is empty, no need to delete.\n"); return; } head = head->next; free(temp); }
先定義一個臨時變數指向舊頭指標,將第二個節點記為新的頭指標head,之後將舊頭指標釋放。
刪除指定節點
void DeleteListRand(int a) { if (head == NULL) { printf("No nodes in the linked list./n"); return; } pnote* temp = FindNode(a); if (temp == NULL) { printf("Nothing found.\n"); return; } if (head == end)//只有一個節點 { free(head); head = NULL; end = NULL; } else if (head->next == end)//有兩個節點 { if (head == temp) DeleteListHead(); else if(end == temp) DeleteListTail(); } else { pnote* pt = head; while (temp->next != temp) { pt = pt->next; } pt->next = temp->next; free(temp); } }
分為三種情況:1.只有一個節點;2.有兩個節點;3.有多個節點。三個步驟與前面的思路相似,這裡就不再贅述
測試主函式
void main() { pnote* pFind; int i; //建立5個節點 AddListTill(5); // AddListRand(4,14); //在指定位置4增加節點14 // DeleteListTail(); //刪除一個尾結點 DeleteListRand(4); //刪除4節點 ScanList(); //便利輸出連結串列 FreeList(); //刪除連結串列 /* pFind = FindNode(5); //查詢5節點 if (pFind != NULL) { printf("找到%d\n",pFind->a); //找到節點並且輸出該節點資料 } else { printf("No Find!\n"); } */ }
有關無空頭的單鏈表的基本操作就總結到這裡