雙鏈表(Double Linked LIst)

雙鏈表


雙鏈表屬於鏈表的一種,有兩個指針域,分別指向直接後繼和直接前驅。所有在遍歷雙向鏈表時,從任意一個節點開始,都可以很方便的訪問它的前驅節點和後繼節點。使用這種方式解決了單鏈表中不能使用反向遍歷的問題。

節點數據結構


在雙鏈表中,每個節點包含三個部分:

  • 指向當前節點上一個節點的指針
  • 當前節點存儲數據的數據域
  • 指向當前節點下一個節點的指針
struct Node{
    int data;
    struct Node *previous,*next;
} *head=NULL;

節點的運算形式


基本的運算形式:增加、刪除、更新

插入節點到序列尾部


創建一個新的節點,通過遍序列表到序列末尾,讓後將節點插入到末尾。

插入過程

  1. 創建一個新節點並賦值,將Node的next指針設置爲NULL
  2. 檢查集合的頭節點是否爲空(head==NULL)
  3. 如果頭節點爲空,設置newNode->previous=NULL,head=newNode;
  4. 如果頭節點不爲空,定義一個臨時節點temp=head;
  5. 移動temp節點直到到達序列的尾部
  6. 設置newNode=temp->next和temp=newNode->previous;
void insertAtENd(int value){
    struct Node *newNode;
    newNode=(struct Node*)malloc (sizeof(struct Node));
    newNode->data=value;
    newNode->next=NULL;
    if (head==NULL){
        newNode->previous=NULL;
        head=newNode;
    }else{
         struct Node *temp = head;
      while(temp -> next != NULL)
         temp = temp -> next;
      temp -> next = newNode;
      newNode -> previous = temp;
    }
    printf("插入末尾成功");
}

插入節點到頭部


創建一個新的節點,將頭節點替換爲新的節點,並更新指針的指向。

插入過程

  1. 創建一個新的節點newNode,並設置newNode->previous=NULL;
  2. 檢查是否head==NULL;
  3. 如果head==NULL,newNode->next=NULL,head=newNode;
  4. 如果head!=NULL,newNode->next=head,head=newNode;
void insertAtBeginning(int value){
    struct  Node *newNode;
    newNode=(struct Node*)malloc(sizeof(struct Node));
    newNode->data=value;
    newNode->previous=NULL;
    if (head==NULL){
        newNode->next=NULL;
        head=newNode;
    }else{
        newNode->next=head;
        head->previous=newNode;
        head=newNode;
    }
    printf("插入成功");
}

插入節點到指定元素後


循環遍歷鏈表,創建一個新的節點,然後將其插入到鏈表中的指定位置

插入過程

  1. 創建一個新節點並賦值
  2. 檢查鏈表是否爲空(head==NULL)
  3. 如果(head==NULL),newNode->previous=NULL,newNode->next=NULL,head=newNode
  4. 定義一個temp=head
  5. 通過循環遍歷移動temp節點,指定找到我們需要插入的節點位置(for循環到position-1)
  6. 如果temp->next==NULL設置flag=0,表面我們要查找的目標元素未發現,終止循環
  7. 如果flag=1,設置newNode->next=temp->next,temp->next->previous=newNode,temp->next=newNode和newNode->previous=temp;
void insertAfter(int value, int pos)
{
   int i, flag = 1;
   struct Node *newNode, *temp = head;
   newNode = (struct Node*)malloc(sizeof(struct Node));
   newNode -> data = value;
   if(head == NULL)
   {
      newNode -> previous = newNode -> next = NULL;
      head = newNode;
   }
   else
   {
    for (i = 0; i < pos - 1; i++) {
        temp = temp -> next;
        if (temp -> next == NULL) {
            flag = 0;
            break;
        }
    }

    if (flag) {
        newNode -> next = temp -> next;
        temp -> next -> previous = newNode;
        temp -> next = newNode;
        newNode -> previous = temp;
        printf("\nInsertion successful\n");
    }
    else
        printf("Number of elements is less than position entered");
   }
}

從鏈表尾部刪除節點


通過循環遍歷到鏈表尾部,刪除尾部節點

從尾部刪除過程

  1. 檢查鏈表是否爲空(head==NULL)
  2. 如果爲空,拋出錯誤並終止程序
  3. 如果不爲空,定義一個temp=head;
  4. 檢查是否鏈表只存在一個節點(temp->previous=NULL和temp->next=NULL)
  5. 如果只存在一個節點,設置head=NULL並刪除temp節點
  6. 如果鏈表存在多個節點,移動temp節點直到到達鏈表尾部(temp->next!=NULL)
  7. 設置temp->previous->next=NULL並釋放temp佔用內存(free(temp))
void deleteEnd()
{
   if(head == NULL)
      printf("鏈表爲空");
   else
   {
      struct Node *temp = head;
      if(temp -> previous == temp -> next)
      {
         head = NULL;
         free(temp);
      }
      else{
         while(temp -> next != NULL)
            temp = temp -> next;
         temp -> previous -> next = NULL;
         free(temp);
      }
      printf("\n刪除成功");
   }
}

從鏈表頭部刪除節點


從鏈表頭部刪除節點

從頭部刪除過程

  1. 檢查鏈表是否爲空(head==NULL)
  2. 如果爲空,拋出異常並終止
  3. 如果不爲空,定義一個temp節點,且temp=head
  4. 檢查鏈表是否只有一個節點(temp->previous=temp->next)
  5. 如果鏈表只有一個節點,設置head=NULL並釋放free(temp)
  6. 否則,設置temp->next=head,head->previous=NULL並釋放free(temp)
void deleteBeginning()
{
   if(head == NULL)
      printf("鏈表爲空");
   else
   {
      struct Node *temp = head;
      if(temp -> previous == temp -> next)
      {
         head = NULL;
         free(temp);
      }
      else{
         head = temp -> next;
         head -> previous = NULL;
         free(temp);
      }
      printf("\n刪除成功");
   }
}

從鏈表指定位置刪除節點


遍歷鏈表到找到指定節點

從指定位置刪除過程

  1. 檢查鏈表是否爲空(head==NULL)
  2. 如果爲空,拋出錯誤並終止
  3. 如果不爲空,定義一個temp,且temp=head
  4. 移動temp節點,直到找到目標節點或者到達鏈表末尾
  5. 如果到達節點末尾,拋出未發現目標節點異常,並終止
  6. 如果到達目標節點,檢查是否只有一個節點
  7. 如果僅有一個節點,設置head=NULL並釋放free(temp)
  8. 如果鏈表有多個節點,檢查是否爲頭節點(temp==head)
  9. 如果爲頭節點(temp=head),將頭節點移動到下一個節點(head==head->next),設置head->previous=NULL並釋放內存free(temp)
  10. 如果temp!=head,檢查temp是否爲最後一個節點(temp->next==NULL)
  11. 如果爲最後一個節點,設置temp->previous->next=NULL並釋放free(temp)
  12. 如果temp不是第一個節點也不是最後一個節點,設置temp->previous-next=temp->next,temp->next->previous=temp->previous並釋放free(temp)
void deleteSpecific(int delValue)
{
   if(head == NULL)
      printf("List is Empty");
   else
   {
      struct Node *temp = head;
      while(temp -> data != delValue)
      {
         if(temp -> next == NULL)
         {
            printf("\nGiven node is not found in the list");
         }
         else
         {
            temp = temp -> next;
         }
      }
      if(temp == head)
      {
         head = NULL;
         free(temp);
      }
      else
      {
         temp -> previous -> next = temp -> next;
         free(temp);
      }
      printf("\nDeletion successful");
   }
}

雙連邊的應用常見


  1. 瀏覽器的歷史紀錄 大多數主流瀏覽器都支持針對瀏覽歷史記錄的前進、後退,就是基於雙鏈表設計的
  2. 大多數算法
  3. 遊戲:卡牌遊戲,記錄牌的順序

更多內容,歡迎關注:


在這裏插入圖片描述

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