鏈表的專業術語:
首節點:存放第一個有效數據的節點
尾節點:存放最后一個有效數據的節點
頭結點:
1.頭結點的數據類型和首節點的數據類型是一模一樣的
2.頭結點是首節點前面的那個節點
3.頭結點並不存放有效數據
4.設置頭結點的目的是為了方便對鏈表的操作
頭指針:存放頭結點地址的指針變量
用一張圖片來展示鏈表的基本框架:
⭐尾節點的指針域為空,可以表示為NULL
⭐想要確定一個鏈表,需要最基本的信息是頭指針,之后的信息都可以通過頭指針找出來。
接下來編寫程序,只有用實際的例子,才能更全面的理解!
1 #include <stdio.h> 2 #include <stdlib.h> 3 struct Node //定義一個鏈表結構 4 { 5 int data; //鏈表節點的數據 6 struct Node * pNext; //鏈表節點指向下一個節點的指針 7 }; 8 int i; 9 struct Node * create_list(void); //創建鏈表的函數聲明 10 void traverse_list(struct Node *); //打印鏈表的函數聲明 11 int main() 12 { 13 struct Node * pHead = NULL; //先給頭指針賦值為NULL 14 pHead = create_list(); //調用鏈表創建函數,並將頭指針的值賦給pHead 15 traverse_list(pHead); //打印鏈表 16 return 0; 17 } 18 struct Node * create_list(void) //創建鏈表的函數 19 { 20 int len; //鏈表的節點數 21 int val; //鏈表節點中數據域的值 22 struct Node * pHead=(struct Node *)malloc(sizeof(struct Node)); //動態分配頭結點的內存 23 if(pHead == NULL) 24 { 25 printf("內存分配失敗,程序終止!\n"); 26 exit(-1); 27 } 28 struct Node * pTail = pHead; //定義一個尾節點指針,將pHead的值賦給它 29 pTail->pNext = NULL; //尾節點的指針域一定為空 30 printf("請輸入您需要生成的鏈表節點的個數:len ="); 31 scanf("%d",&len); 32 for (i=0;i<len;i++) 33 { 34 printf("請輸入第%d個節點的值:",i+1); 35 scanf("%d",&val); 36 struct Node * pNew=(struct Node *)malloc(sizeof(struct Node)); //動態分配新節點的內存 37 if(pNew== NULL) 38 { 39 printf("內存分配失敗,程序終止!\n"); 40 exit(-1); 41 } 42 pNew->data = val; //把輸入的值傳給*pNew數據域 43 pNew->pNext = NULL; // *pNew是新的尾節點,所以 pNew->pNext應該為空 44 pTail->pNext = pNew; //把*pNew的地址傳給pTail->pNext指針域,等效於*pTail.pNext=pNew 45 //第一次的pTail->pNext = pNew相當於把首節點的地址給了頭結點 46 47 pTail = pNew; 48 //執行此操作,*pNew就變成了新的*pTail 49 //之后的pTail = pNew則是讓最后一個與上一個節點連接上 50 } 51 return pHead; //返回 pHead的值 52 } 53 void traverse_list(struct Node * pHead) //遍歷鏈表 54 { 55 struct Node * p = pHead->pNext; //定義一個指向下一個節點的指針 56 while(p!=NULL) //尾節點的指針域一定是NULL,如果非NULL,則繼續打印 57 { 58 printf("%d\t",p->data); 59 p = p->pNext; //下一個節點的地址賦值給p 60 } 61 return; //循環結束 62 }
在這個程序中,我對44行和47行的代碼思考了很久
最開始總覺得有了44行代碼 pTail->pNext = pNew ,47行的代碼 pTail = pNew 重復了,刪去之后,發現不行,下面對兩者的區別進行畫圖解析:
第1步:*pTail的地址就是pHead,所以pHead指向*pTail,另外,新創建的*pNew還沒有賦值。
第2步:將val賦值給*pNew的數據域,NULL賦值給*pNew的指針域,並把*pNew的地址傳給*pTail的指針域
第3步:把*pNew的地址賦值給pTail,讓*pNew變成新的*pTail
整個過程大致就是如此,理解了,其實也不難,要掌握更多的知識,需要進一步學習數據結構。