1. 程式人生 > >(C/C++學習)18.C語言雙向連結串列

(C/C++學習)18.C語言雙向連結串列

說明:陣列提供了連續記憶體空間的訪問和使用,而連結串列是對記憶體零碎空間的有效組織和使用。連結串列又分為單向連結串列和雙向連結串列,單向連結串列僅提供了連結串列的單方向訪問,相比之下,雙向連結串列則顯得十分方便。


一.單向連結串列的節點

如下程式碼所示,雙向連結串列的節點包含兩個指向關係和一個數據空間,兩個指向分別連線該節點的上一個和下一個節點,資料型別可以是一個結構體型別,也可以是其他型別。

  1 typedef struct node
  2 {
  3   int data;
  4   struct node *pre;
  5   struct node *next;
  6
}Node;



二.雙向連結串列的建立

頭插法和尾插法只看程式碼比較難以與理解,建議畫出插入節點時的連結串列變化圖則會非常容易理解,另外,個人認為頭插法較優,因為其插入邏輯一步到位,不像尾插法還需在後面完成雙向連結串列的環狀連線。

1.頭插法

  1 Node * creatList()
  2 {
  3    Node * head = (Node*)malloc(sizeof(Node));
  4    Node * cur = NULL;
  5    head->next = head;
  6    head->pre = head;
  7    int data;
  8
scanf("%d",&data); 9 while(data) 10 { 11 cur = (Node*)malloc(sizeof(Node)); 12 cur->data = data; 13 cur->next = head->next; 14 cur->pre = head; 15 head->next = cur; 16 cur->next->pre = cur; 17 scanf("%d",&data); 18
} 19 return head; 20 }


2.尾插法

  1 Node * creatList()
  2 {
  3   Node * head = (Node*)malloc(sizeof(Node));
  4   Node * phead = head;
  5   Node * cur = NULL;
  6   phead->next = NULL;
  7   phead->pre = NULL;
  8   int data;
  9   scanf("%d",&data);
 10   while(data)
 11   {
 12      cur = (Node*)malloc(sizeof(Node));
 13      cur->data = data;
 14      phead->next = cur;
 15      cur->pre = phead;
 16      phead = cur;
 17      scanf("%d",&data);
 18   }
 19 //完成迴環
 20   cur->next = head;
 21   head->pre = cur;
 22   return head;
 23 }



三.雙向連結串列的元素插入(頭插法)

插入方法:先讓插入的節點有所指向,再考慮指向它的指標,具體插入如下:

  1 void insertList(Node * head)
  2 {
  3    printf("intsert new node:");
  4    int data;
  5    scanf("%d",&data);
  6    Node * cur;
  7    cur = (Node*)malloc(sizeof(Node));
  8    cur->data = data;
  9    cur->next = head->next;
 10    cur->pre = head;
 11    head->next = cur;
 12    cur->next->pre = cur;
 13 }



四.雙向連結串列的查詢

既然是雙向連結串列,其查詢方式也應該是是雙向查詢,比起單向連結串列的單向查詢,雙向查詢同時從兩個方向進行查詢,加快了查詢的速度。

  1 Node * searchList(Node * head,int find)
  2 {
  3    Node * pClock = head->next;
  4    Node * pAntiClock = head->pre;
  5    while (pAntiClock != pClock->pre)
  6    {
  7        if(pClock->data == find)
  8        return pClock;
  9        if(pAntiClock->data == find)
 10        return pAntiClock;
 11        if(pClock == pAntiClock)
 12        return NULL;
 13        pClock = pClock->next;
 14        pAntiClock = pAntiClock->pre;
 15 }
 16    return NULL;
 17 }



五.刪除某個節點

  1 void deleteList(Node * pfind)
  2 {
  3    if(pfind == NULL)
  4    return;
  5    else
  6     {
  7       pfind->pre->next = pfind->next;
  8       pfind->next->pre = pfind->pre;
  9       free(pfind);
 10     }
 11 }



六.連結串列排序(按值排序)

  1 void sortList(Node * head,int n)
  2 {
  3     Node * p,*q;
  4     for(int i=0; i<n-1; i++)
  5     {
  6       p = head->next;
  7       q = p->next;
  8       for(int j=0; j<n-1-i; j++)
  9       {
 10         if(p->data > q->data)
 11         {
 12           p->data = p->data ^ q->data;
 13           q->data = p->data ^ q->data;
 14           p->data = p->data ^ q->data;
 15         }
 16       p = p->next;
 17       q = q->next;
 18       }
 19     }
 20 }



七.連結串列的銷燬

  1 void destroyList(Node * head)
  2 {
  3    head->pre->next = NULL;
  4    Node * pre = head;
  5    while(head != NULL)
  6    {
  7      head = head->next;
  8      free(pre);
  9      pre = head;
 10    }
 11 }


說明:連結串列的操作還有如求長度、列印以及交換指標排序等,由於相對較為簡單,此處就不再例舉。重要提醒:連結串列的某些操作較難理解,最好畫圖加以輔助理解。