雙鏈表
雙鏈表屬於鏈表的一種,有兩個指針域,分別指向直接後繼和直接前驅。所有在遍歷雙向鏈表時,從任意一個節點開始,都可以很方便的訪問它的前驅節點和後繼節點。使用這種方式解決了單鏈表中不能使用反向遍歷的問題。
節點數據結構
在雙鏈表中,每個節點包含三個部分:
- 指向當前節點上一個節點的指針
- 當前節點存儲數據的數據域
- 指向當前節點下一個節點的指針
struct Node{
int data;
struct Node *previous,*next;
} *head=NULL;
節點的運算形式
基本的運算形式:增加、刪除、更新
插入節點到序列尾部
創建一個新的節點,通過遍序列表到序列末尾,讓後將節點插入到末尾。
插入過程
- 創建一個新節點並賦值,將Node的next指針設置爲NULL
- 檢查集合的頭節點是否爲空(head==NULL)
- 如果頭節點爲空,設置newNode->previous=NULL,head=newNode;
- 如果頭節點不爲空,定義一個臨時節點temp=head;
- 移動temp節點直到到達序列的尾部
- 設置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("插入末尾成功");
}
插入節點到頭部
創建一個新的節點,將頭節點替換爲新的節點,並更新指針的指向。
插入過程
- 創建一個新的節點newNode,並設置newNode->previous=NULL;
- 檢查是否head==NULL;
- 如果head==NULL,newNode->next=NULL,head=newNode;
- 如果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("插入成功");
}
插入節點到指定元素後
循環遍歷鏈表,創建一個新的節點,然後將其插入到鏈表中的指定位置
插入過程
- 創建一個新節點並賦值
- 檢查鏈表是否爲空(head==NULL)
- 如果(head==NULL),newNode->previous=NULL,newNode->next=NULL,head=newNode
- 定義一個temp=head
- 通過循環遍歷移動temp節點,指定找到我們需要插入的節點位置(for循環到position-1)
- 如果temp->next==NULL設置flag=0,表面我們要查找的目標元素未發現,終止循環
- 如果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");
}
}
從鏈表尾部刪除節點
通過循環遍歷到鏈表尾部,刪除尾部節點
從尾部刪除過程
- 檢查鏈表是否爲空(head==NULL)
- 如果爲空,拋出錯誤並終止程序
- 如果不爲空,定義一個temp=head;
- 檢查是否鏈表只存在一個節點(temp->previous=NULL和temp->next=NULL)
- 如果只存在一個節點,設置head=NULL並刪除temp節點
- 如果鏈表存在多個節點,移動temp節點直到到達鏈表尾部(temp->next!=NULL)
- 設置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刪除成功");
}
}
從鏈表頭部刪除節點
從鏈表頭部刪除節點
從頭部刪除過程
- 檢查鏈表是否爲空(head==NULL)
- 如果爲空,拋出異常並終止
- 如果不爲空,定義一個temp節點,且temp=head
- 檢查鏈表是否只有一個節點(temp->previous=temp->next)
- 如果鏈表只有一個節點,設置head=NULL並釋放free(temp)
- 否則,設置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刪除成功");
}
}
從鏈表指定位置刪除節點
遍歷鏈表到找到指定節點
從指定位置刪除過程
- 檢查鏈表是否爲空(head==NULL)
- 如果爲空,拋出錯誤並終止
- 如果不爲空,定義一個temp,且temp=head
- 移動temp節點,直到找到目標節點或者到達鏈表末尾
- 如果到達節點末尾,拋出未發現目標節點異常,並終止
- 如果到達目標節點,檢查是否只有一個節點
- 如果僅有一個節點,設置head=NULL並釋放free(temp)
- 如果鏈表有多個節點,檢查是否爲頭節點(temp==head)
- 如果爲頭節點(temp=head),將頭節點移動到下一個節點(head==head->next),設置head->previous=NULL並釋放內存free(temp)
- 如果temp!=head,檢查temp是否爲最後一個節點(temp->next==NULL)
- 如果爲最後一個節點,設置temp->previous->next=NULL並釋放free(temp)
- 如果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");
}
}
雙連邊的應用常見
- 瀏覽器的歷史紀錄 大多數主流瀏覽器都支持針對瀏覽歷史記錄的前進、後退,就是基於雙鏈表設計的
- 大多數算法
- 遊戲:卡牌遊戲,記錄牌的順序
更多內容,歡迎關注: