朱有鵬C語言高階---4.9.7--單鏈表--刪除節點(7)
阿新 • • 發佈:2018-11-11
朱有鵬C語言高階---4.9.7--單鏈表--刪除節點(7)
(1)連結串列到底用來幹嘛的?
連結串列是用來存資料的,連結串列和陣列是一類東西!!
(2)為什麼要刪除節點?
有時候連結串列節點中的資料不想要了,因此要刪除這個節點。
(3)刪除節點的2個步驟
第一步:找到要刪除的節點
第二步:刪除這個節點。
(4)如何找到待刪除的節點
通過遍歷來查詢節點。從頭指標+頭結點開始,順著連結串列依次將各個節點拿出來,按照一定的方法比對,找到我們要刪除的那個節點。
(5)如何刪除一個節點
1、待刪除的節點不是尾節點的情況:
首先把待刪除的節點的前一個節點的pNext指標指向待刪除的節點的後一個節點的首地址(這樣就把這個節點從連結串列
中摘出來了),然後再將這個摘出來的節點free掉介面。
2、待刪除的節點是尾節點的情況:
首先把待刪除的尾節點的前一個節點的pNext指標指向NULL(這時候就相當於原來尾節點前面的一個節點變成了新的
尾節點),然後將摘出來的節點free掉。
(6)注意堆記憶體的釋放
當程式都結束了的情況下,那些沒有free的堆記憶體也被釋放了。
有時候我們的程式執行時間很久,這時候malloc的記憶體沒有free,會一直被佔用直到你free釋放它或者整個程式終止。
完整程式碼:(核心函式:delete_node())
#include <stdio.h> #include <strings.h> #include <stdlib.h> //構建一個連結串列節點 struct node { int data; //有效資料 struct node *pNext; //指向下一個節點的指標 }; //作用:建立一個連結串列的節點 //返回:指標,指標指向我們本函式新建立的一個節點的首地址 struct node * create_node(int data) { struct node *p = (struct node *)malloc(sizeof(struct node)); if (NULL == p) { printf("malloc error.\n"); return NULL; } //清理申請到的堆記憶體 bzero(p, sizeof(struct node)); //填充節點 p->data = data; p->pNext = NULL;//將來要指向下一個節點的首地址 //實際操作時將下一個節點malloc返回的指標複製給這個 return p; } //思路:由頭指標向後遍歷,直到走到原來的最後一個節點。原來最後一個節點裡面的pNext是NULL, //現在我們將它改成new就可以了。添加了之後新節點就變成了最後一個。 //pH:頭指標,有連結串列的頭指標才能找到連結串列。new是一個新的節點 //計算添加了新的節點後共有多少個節點,然後把這個數寫進頭結點中 void insert_tail(struct node *pH, struct node *new) { int cnt = 0; //分兩布來完成插入 //第一步,先找到連結串列中最後一個節點 struct node *p = pH; while (NULL != p->pNext) { p = p->pNext;//往後走一個節點 cnt++; } //第二部,將新節點插入到最後一個節點尾部 p->pNext = new; pH->data = cnt + 1; } //思路: void insert_head(struct node *pH, struct node *new) { //第1步: 新節點的next指向原來的第一個節點 new->pNext = pH->pNext; //第2部: 頭節點的next指向新節點的地址 pH->pNext = new; //第3步: 頭節點中的計數要加1 pH->data += 1; } //遍歷單鏈表,pH為指向單鏈表的頭指標,遍歷的節點資料打印出來 void bianli(struct node *pH) { //pH->data //頭節點的資料,不是連結串列的常規資料,不要算進去了 //struct node *p = pH;//錯誤,因為頭指標後面是頭節點,頭節點的資料域是節點個數 struct node *p = pH->pNext;//直接跨過了頭節點,p直接走到第一個節點 printf("-----開始遍歷-----\n"); while (NULL != p->pNext)//是不是最後一個節點 { printf("node data: %d.\n", p->data); p = p->pNext; //走到下一個節點,也就是迴圈增量 } printf("node data: %d.\n", p->data); printf("-----完了-----\n"); } //遍歷單鏈表,pH為指向單鏈表的頭指標,遍歷的節點資料打印出來 void bianli2(struct node *pH) { //pH->data //頭節點的資料,不是連結串列的常規資料,不要算進去了 struct node *p = pH;//錯誤,因為頭指標後面是頭節點,頭節點的資料域是節點個數 printf("-----開始遍歷-----\n"); while (NULL != p->pNext)//是不是最後一個節點 { p = p->pNext; //走到下一個節點,也就是迴圈增量 printf("node data: %d.\n", p->data); } printf("-----完了-----\n"); } // 從連結串列pH中刪除節點,待刪除的節點的特徵是資料區等於data // 返回值:當找到並且成功刪除了節點則返回0,當未找到節點時返回-1 int delete_node(struct node *pH, int data)//引數:頭指標,節點的資料 { //找到這個待刪除的節點,通過遍歷連結串列來查詢 struct node *p = pH; //頭指標後面是頭節點,用來指向當前節點 struct node *pPrev = NULL; //用來指向當前節點的前一個節點 while (NULL != p->pNext) //是不是最後一個節點 { pPrev = p; //在p走向下一個節點前先將其儲存 p = p->pNext; //走到下一個節點,也就是迴圈增量 //判斷這個節點是不是我們要找的那個節點 if (p->data == data) { // 找到了節點,處理這個節點 // 分為2種情況,一個是找到的是普通節點,另一個是找到的是尾節點 // 刪除的節點的困難點在於:通過連結串列的遍歷依次訪問各個節點,找到這個節點 // 後p指向了這個節點,但是要刪除這個節點關鍵要操作前一個節點,但是這 // 時候已經沒有指標指向前一個節點了,所以沒法操作。解決方案就是增加 // 一個指標指向當前節點的前一個節點 if (NULL == p->pNext) { //尾節點 pPrev->pNext = NULL; //原來尾節點的前一個節點變成新尾節點 free(p); //釋放原來的尾節點的記憶體 } else { //普通節點 //要刪除的節點的前一個節點和它的後一個節點相連,這樣就把要刪除的節點給摘出來了 pPrev->pNext = p->pNext; free(p); } // 處理完成之後退出程式 return 0; } } // 到這裡還沒找到,說明連結串列中沒有我們想要的節點 printf("沒找到這個節點.\n"); return -1; } int main(void) { //不能指向NULL,因為尾插法時首先會判斷頭指標的值p->pNext //struct node *pHeader = NULL; //定義頭指標,建立頭節點。頭節點的資料域傳的是節點的個數 struct node *pHeader = create_node(0);//資料定義0表示沒放資料 insert_head(pHeader, create_node(11)); insert_head(pHeader, create_node(12)); insert_head(pHeader, create_node(13)); insert_head(pHeader, create_node(12)); bianli2(pHeader); delete_node(pHeader, 12); printf("-----刪除後-----\n"); bianli2(pHeader); return 0; }