1. 程式人生 > >【C/C++】連結串列的理解與使用

【C/C++】連結串列的理解與使用

轉載自:http://blog.csdn.NET/xubin341719/article/details/7091583/

最近不是太忙,整理些東西,工作也許用得到。

1,為什麼要用到連結串列

陣列作為存放同類資料的集合,給我們在程式設計時帶來很多的方便,增加了靈活性。但陣列也同樣存在一些弊病。如陣列的大小在定義時要事先規定,不能在程式中進行調整,這樣一來,在程式設計中針對不同問題有時需要3 0個大小的陣列,有時需要5 0個數組的大小,難於統一。我們只能夠根據可能的最大需求來定義陣列,常常會造成一定儲存空間的浪費。

我們希望構造動態的陣列,隨時可以調整陣列的大小,以滿足不同問題的需要。連結串列就是我們需要的動態陣列。它是在程式的執行過程中根據需要有資料儲存就向系統要求申請儲存空間,決不構成對儲存區的浪費。

連結串列是一種複雜的資料結構,其資料之間的相互關係使連結串列分成三種:單鏈表、迴圈連結串列、雙向連結串列,下面將逐一介紹。

2,單向連結串列

單鏈表有一個頭節點head,指向連結串列在記憶體的首地址。連結串列中的每一個節點的資料型別為結構體型別,節點有兩個成員:整型成員(實際需要儲存的資料)和指向下一個結構體型別節點的指標即下一個節點的地址(事實上,此單鏈表是用於存放整型資料的動態陣列)。連結串列按此結構對各節點的訪問需從連結串列的頭找起,後續節點的地址由當前節點給出。無論在表中訪問那一個節點,都需要從連結串列的頭開始,順序向後查詢。連結串列的尾節點由於無後續節點,其指標域為空,寫作為NULL

如圖所示

上圖還給出這樣一層含義,連結串列中的各節點在記憶體的儲存地址不是連續的,其各節點的地址是在需要時向系統申請分配的,系統根據記憶體的當前情況,既可以連續分配地址,也可以跳躍式分配地址。

3,單向連結串列程式的實現

(1),連結串列節點的資料結構定義

  1. struct node  
  2. {  
  3. int num;  
  4. struct node *p;  
  5. } ;  

在連結串列節點的定義中,除一個整型的成員外,成員p是指向與節點型別完全相同的指標。

在連結串列節點的資料結構中,非常特殊的一點就是結構體內的指標域的資料型別使用了未定義成功的資料型別。這是在C中唯一規定可以先使用後定義的資料結構。

(2),連結串列的建立、輸出步驟

單鏈表的建立過程有以下幾步:

1 ) 定義連結串列的資料結構;

2 ) 建立一個空表;

3 ) 利用malloc ( )函式向系統申請分配一個節點;

4 ) 將新節點的指標成員賦值為空。若是空表,將新節點連線到表頭;若是非空表,將新

節點接到表尾;

5 ) 判斷一下是否有後續節點要接入連結串列,若有轉到3 ),否則結束;

單鏈表的輸出過程有以下幾步

1) 找到表頭;

2) 若是非空表,輸出節點的值成員,是空表則退出;

3 ) 跟蹤連結串列的增長,即找到下一個節點的地址;

4) 轉到2 ).

(3),程式程式碼例子:

建立一個存放正整數單鏈表,輸入0或小於0的數,結束建立連結串列,並打印出連結串列中的值,程式如下:

  1. #include <stdlib.h> /*含ma l l o c ( ) 的標頭檔案*/
  2. #include <stdio.h>
  3.  //①定義連結串列資料結構
  4. struct node  
  5. {  
  6.     int num;  
  7.     struct node *next;  
  8. };  
  9. //函式宣告
  10. struct node *creat();   
  11. void print();  
  12. main( )  
  13. {  
  14.     struct node *head;  
  15.     head=NULL;    //②建一個空表
  16.     head=creat(head);/*建立單鏈表*/
  17.     print(head);/*列印單鏈表*/
  18. }  
  19. /******************************************/
  20. struct node*creat(struct node *head)/*返回的是與節點相同型別的指標*/
  21. {  
  22.     struct node*p1,*p2;  
  23.     int i=1;  
  24. //③利用malloc ( )函式向系統申請分配一個節點
  25.     p1=p2=(struct node*)malloc(sizeof(struct node));/*新節點*/
  26.     printf("請輸入值,值小於等於0結束,值存放地址為:p1_ADDR= %d\n",p1);  
  27.     scanf("%d",&p1->num);/*輸入節點的值*/
  28.     p1->next=NULL;/*將新節點的指標置為空*/
  29.     while(p1->num>0)/*輸入節點的數值大於0*/
  30.     {  
  31. //④將新節點的指標成員賦值為空。若是空表,將新節點連線到表頭;若是非空表,將新節點接到表尾; 
  32.         if(head==NULL)  
  33.             head=p1;/*空表,接入表頭*/
  34.         else
  35.             p2->next=p1;/*非空表,接到表尾*/
  36.         p2=p1;  
  37.         p1=(struct node*)malloc(sizeof(struct node));/*下一個新節點*/
  38.         i=i+1;  
  39.         printf("請輸入值,值小於等於0結束,值存放地址為:p%d_ADDR= %d\n",i,p2);  
  40.         scanf("%d",&p1->num);/*輸入節點的值*/
  41. //⑤判斷一下是否有後續節點要接入連結串列,若有轉到3 ),否則結束; 
  42.     }  
  43. //==============原來程式更正部分:(多謝@daling_datou提醒)================================
  44.     free(p1);  //申請到的沒錄入,所以釋放掉  
  45.     p1=NULL;   //使指向空  
  46.     p2->next = NULL; //到表尾了,指向空  
  47.     printf("連結串列輸入結束(END)\n");    
  48. //==============================================
  49.     return head;/*返回連結串列的頭指標*/
  50. }  
  51. /*******************************************/
  52. void print(struct node*head)/*出以head為頭的連結串列各節點的值*/
  53. {  
  54.     struct node *temp;  
  55.     temp=head;/*取得連結串列的頭指標*/
  56.     printf("\n\n\n連結串列存入的值為:\n");  
  57.     while(temp!=NULL)/*只要是非空表*/
  58.     {  
  59.         printf("%6d\n",temp->num);/*輸出連結串列節點的值*/
  60.         temp=temp->next;/*跟蹤連結串列增長*/
  61.     }  
  62.     printf("連結串列列印結束!!");  
  63. }  



在連結串列的建立過程中,連結串列的頭指標是非常重要的引數。因為對連結串列的輸出和查詢都要從連結串列的頭開始,所以連結串列建立成功後,要返回一個連結串列頭節點的地址,即頭指標。