[數據結構]C語言鏈表實現

[數據結構]C語言鏈表實現http://www.cnblogs.com/racaljk/p/7822311.html

我學數據結構的時候也是感覺很困難,當我學完後我發現了之所以困難時因爲我沒有系統的進行學習,而且很多教授都只是注重數據結構思想,而忽略了代碼方面,爲此我寫了這些博文給那些試圖自學數據結構的朋友,希望你們少走彎路


我嘗試用最簡單的語言與代碼來描述鏈表,事實上它本身也很簡單

靜態單鏈表實現


下面一部分的討論都將圍繞上面這幅圖片展開,既然是逐步實現,我不考慮在開頭就讓這個單鏈表完美實現,它將只有兩個部分:鏈表的創建&遍歷鏈表輸出

首先我們要知道一些簡單的概念,一個鏈表是由節點構成,而每個節點又是又一個數據域和一個指向下一個節點的指針構成,因此我們可以很容易寫出下面的結構

  1. struct node//節點  
  2. {  
  3.     int data;//數據域,這裏我們選擇存儲int型  
  4.     struct node *next;//指針域,指向下一個節點,因此被定義爲struct *NODE  
  5. };  

然後再認真觀察一下上面的圖會發現似乎還有一個頭指針沒有用(head pointer),頭指針的作用就是在浩瀚的內存中指向這個鏈表的第一個節點,然後我們由第一個節點(通常稱之爲頭結點)的next指針指向下面一個,因此很容易就能想到,只要有了頭指針我們就能很容易的對鏈表進行各項操作。

於是我們可以繼續寫代碼了:

  1. int main(){  
  2.     //創建上圖的鏈表  
  3.     node *head;//一個頭指針。用來指向這個鏈表的第一個節點  
  4.     node *f=new node;//對應上圖第一個節點first node,這種奇葩命名法不是我要讓你們學會的,另我使用了new而不是malloc主要是因爲惰性  
  5.     node *s=new node;//對應上圖第二個節點second node  
  6.     node *t=new node;//對應上圖第三個節點third node  
  7.     f->data=8;//第一個node的值  
  8.     f->next=s;//第一個節點next指針指向第二個節點  
  9.     s->data=7;//第二個node的值  
  10.     s->next=t;//第二個節點next指針指向第三個節點  
  11.     t->data=9;//第三個節點值  
  12.     t->next=NULL;//從上圖得知第三個節點後沒有節點了,所以指向NULL,通常稱這個節點爲尾節點  
  13.     head=f;//頭指針指向第一個節點,至於爲什麼前面已經說了//打印這個鏈表裏面儲存的元素  
  14.     std::cout<<"鏈表數據:"<<"\n";  
  15.    node *print_ptr=head;//爲什麼這裏要new一個print_ptr?因爲我們可能還要利用head進行其他操作,如果直接用head進行下面的操作,就意味着head指向的位置已經改變了  
  16.    while(print_ptr!=NULL){  
  17.            std::cout<<print_ptr->data<<"\n";//通過頭結點迭代打印每個節點的值  
  18.            print_ptr=print_ptr->next;//更新,讓當前指針指向下一個節點  
  19.    }  
  20.    //輸出節點的個數,雖然我們已經知道了是3個  
  21.    node *length_ptr=head;//同上面的  
  22.    print_ptrint k=0;  
  23.    while(length_ptr!=NULL){  
  24.            k++;length_ptr=length_ptr->next;  
  25.    }  
  26.    std::cout<<"鏈表節點個數:"<<"\n"<<k<<"\n";//插入一個節點,這裏我選擇在第一個節點與第二個節點之間插入一個新節點ins_node  
  27.    node *ins_node=new node;//爲即將插入的節點從堆上分配點內存  
  28.    ins_node->data=14;//賦值  
  29.    ins_node->next=s;//讓新節點的next指向第二個節點  
  30.    f->next=ins_node;//然後讓第一個節點的next指向新節點,這就完成了插入//刪除之前插入的節點  
  31.    ins_node=f->next;//讓第一個節點next指向新插入的節點,這裏你可能會感到疑惑,我建議你畫圖或者再看看上面的圖就能理解,當然你也可以看下面  
  32.   f->next=ins_node->next;//第一個節點的next指向新節點的next,因爲新節點的next相當於指向了第二個節點,所以這裏也等價於第一個節點指向第二個節點f->next=f-next->next  
  33.    system("pause");  
  34. }  
上面就完成了使用尾插法創建的一個鏈表及其簡單操作包括創建/輸出/插入/刪除,不過如你所見它也存在許多不足,比如命名的拙計,new後沒有delete,以及全部在main中執行沒有考慮使用函數等等缺陷,不過這沒關係,因爲我們會一步步修改最終讓他成爲一個不錯的鏈表


可能你關於上面插入與刪除你沒有搞清楚,這裏我再特意講一下


上圖我們需要把儲存14這個數據的node插入到一和二之間,於是我們就需要更改next指針,所以之前f->next=s;就不能用了,


你可能會想到讓第一個指向新節點,然後再讓新節點指向第三個,如:

  1. f->next=ins_node;  
  2. ins_node->next=f->next;  

事實通常證明第一感覺是錯誤的,仔細看看上面代碼你就會發現加入f->next=ins_node,那麼第二條就相當於ins_node->next=ins_node;它指向了自己!所以我們需要反過來思考,先讓新節點指向第二個,然後再讓第一個指向新節點,就如上面的代碼了,至於刪除我沒有弄出圖片,我只是簡單講一下,刪除是直接讓第一個節點的next指向需要刪除的節點,然後再讓第一個節點的next指向需要刪除的節點的next,你可能會思考爲什麼不直接讓第一個節點next指向第二個呢?這個疑問你可以自己解答比較好

動態單鏈表實現

到這裏一個簡單的鏈表就已經實現了,但是我們還需要繼續改進,因爲我們有時候不知道每個節點儲存的數據,所以我們就需要一個動態鏈表了,下面這個將實現把用戶輸入的數據以鏈式結構儲存,也就是動態鏈表


  1. #include <iostream>  
  2.   
  3. struct node  
  4. {  
  5.     int data;  
  6.     struct node *next;  
  7. };  
  8.   
  9.   
  10. node *create_linklist();  
  11. void print_linklist(node *head);  
  12.   
  13. node *create_linklist(){  
  14.     node *head=new node;  
  15.     node *new_node,*current;//一個新節點作爲當前節點  
  16.     current=head;//頭結點複製給當前節點  
  17.     int k;  
  18.     printf("輸入節點個數:");  
  19.     scanf("%d",&k);  
  20.     for (int i = 0; i < k; ++i)  
  21.     {  
  22.         new_node=new node;  
  23.         if(i==0)//這裏也就是創建第一個節點的情況  
  24.         {  
  25.             head=new_node;//把頭指針指向第一個節點  
  26.         }  
  27.         printf("輸入節點數據:");  
  28.         scanf("%d",&new_node->data);  
  29.         current->next=new_node;//注意這裏由於創建了一個新節點,而當前節點還是開始的head的那個位置,所以就需要更新一下,讓當前節點next等於new_node的位置  
  30.         new_node->next=NULL;//當前節點的next=NULL表示當前節點就是最後一個節點了  
  31.         current=new_node;//然後把new_node節點複製給當前節點,以便繼續後面的節點添加  
  32.     }  
  33.     return head;  
  34. }  
  35.   
  36. void print_linklist(node *head)//參數傳入一個頭指針用來指向第一個節點  
  37. {  
  38.     node *phead=head;  
  39.     while(phead!=NULL)  
  40.     {  
  41.         printf("%d", phead->data);  
  42.         phead=phead->next;  
  43.     }  
  44. }  
  45.   
  46. int main(){  
  47.     node *h=create_linklist();  
  48.     print_linklist(h);  
  49.     system("pause");  
  50. }  

雙向鏈表實現

再想想上面圖片,下面要介紹的就是雙向鏈表,雙向鏈表與單項鍊表的區別就在於它有一個指向前一個節點的指針,於是我們就應該定義這樣的結構體
  1. typedef struct NODE  
  2. {  
  3.     int data;  
  4.     struct NODE *next;  
  5.     struct NODE *pre;  
  6. }node;  
由於雙向鏈表不可避免有些操作需要從後向前遍歷,於是我們就應該添加一個概念,尾指針,也就是指向尾節點的指針,如下就實現了一個雙向鏈表,它有三個節點abc,並有兩種輸出方式
  1. #include <iostream>  
  2.   
  3. typedef struct NODE  
  4. {  
  5.     int data;  
  6.     struct NODE *next;  
  7.     struct NODE *pre;  
  8. }node;  
  9.   
  10. int main(){  
  11.     node *a=new node,*b=new node,*c=new node;  
  12.     node *head=a;  
  13.     node *tail=c;  
  14.     a->data=9;  
  15.     a->next=b;  
  16.     a->pre=NULL;  
  17.   
  18.     b->data=17;  
  19.     b->next=c;  
  20.     b->pre=a;  
  21.   
  22.     c->data=6;  
  23.     c->next=NULL;  
  24.     c->pre=b;  
  25.     //輸出  
  26.     /*node *print_head=head; 
  27.     while(print_head!=NULL){ 
  28.         std::cout<<print_head->data<<"\n"; 
  29.         print_head=print_head->next; 
  30.     }*/  
  31.     /*node *print_head=tail; 
  32.     while(print_head!=NULL){ 
  33.         std::cout<<print_head->data<<"\n"; 
  34.         print_head=print_head->pre; 
  35.     }*/  
  36.     system("pause");  
  37. }  

雙向鏈表的難點不是創建輸出而是插入與刪除,我沒有製作圖片,所以這需要讀者認真去思考一下,建議畫圖,也很容易理解,下面代碼是在上面創建了abc的基礎上實現的在ab間插入一個k,然後再刪除它

  1. //插入  
  2. node *k=new node;  
  3. k->data=698;  
  4. k->pre=a;  
  5. k->next=a->next;  
  6. k->next->pre=a;  
  7. a->next=k;  
  8. //刪除  
  9. k->pre->next=k->next;  
  10. k->next->pre=k->pre;  

循環單鏈表

循環鏈表我不考慮講,因爲它就是把尾巴節點指向了頭節點從而形成一個環,所以說循環鏈表不叫loop linked list而叫circular linked list


作者:racaljk


發佈了7 篇原創文章 · 獲贊 139 · 訪問量 38萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章