朱有鵬C語言高階---4.9.6--單鏈表--遍歷節點(6)
阿新 • • 發佈:2018-11-11
朱有鵬C語言高階---4.9.6--單鏈表--遍歷節點(6)
什麼是遍歷
(1)遍歷就是把單鏈表中的各個節點挨個拿出來,就叫遍歷。
(2)遍歷的要點:一是不能遺漏、二是不能重複、追求效率。
如何遍歷單鏈表
單鏈表的特點就是由很多個節點組成,頭指標+頭節點為整個連結串列的起始,最後一個節點的特徵是它內部的pNext指標值為NULL。從起始到結尾中間由各個節點內部的pNext指標來掛接。由起始到結尾的路徑有且只有一條。
遍歷方法:從頭指標+頭節點開始,順著連結串列掛接指標依次訪問連結串列的各個節點,取出這個節點的資料,然後再往下一個節點,直到最後一個節點,結束返回。
程式設計實戰
寫一個連結串列遍歷的函式,void bianli(struct node * pH ),下面的程式碼bianli()函式和bianli2()函式都可以用來遍歷。
下面的程式碼,如果沒有頭結點,只能像bianli()函式這樣遍歷,不完美醜陋。如果有頭結點,就可以想bianli2()函式這樣完美遍歷它。所以如果沒有頭結點,連結串列的演算法不會完美。
#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"); } 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)); /* pHeader = create_node(1); //將本節點和它前面的頭指標關聯起來 pHeader->pNext = create_node(2); //將本節點和它前面的頭指標關聯起來 pHeader->pNext->pNext = create_node(3); //將來要指向下一個節點的首地址 //至此建立了一個有1個頭指標+3個完整節點的連結串列 */ //下面是4.9.3節的程式碼 //訪問連結串列的各個節點的有效資料,這個訪問必須注意不能使用p,p1,p2,而只能使用pHeader //訪問連結串列頭結點的有效資料 printf("header node data: %d.\n", pHeader->data);//pHeader->data等同於p->data bianli2(pHeader); /* //訪問連結串列第1個節點的有效資料 printf("node1 data: %d.\n", pHeader->pNext->data); //訪問連結串列第2個節點的有效資料 printf("node2 data: %d.\n", pHeader->pNext->pNext->data); //訪問連結串列第3個節點的有效資料 printf("node3 data: %d.\n", pHeader->pNext->pNext->pNext->data); return 0; */ }