資料結構-雙鏈表
阿新 • • 發佈:2021-01-21
雙鏈表
單鏈表結點中只有一個只指向後繼的指標,使得單鏈表只能從頭結點開始一次順序的先後遍歷。要訪問某個結點的前驅結點(插入刪除操作時),只能從頭開始遍歷,訪問後繼節點的時間複雜度為O(1),訪問前驅結點的時間複雜度為O(n)。
為了克服單鏈表的上述缺點,引入了雙鏈表,雙鏈表結點中有兩個指標prior 和 next,分別指向其前驅結點和後繼結點。
定義
雙鏈表中結點型別描述:
typedef struct DNode{
ElemType data;
struct DNode *prior, *next;
}DNode, *DLinkList;
在雙鏈表中,按位查詢和按值查詢的操作和單鏈表中的相同。但在插入和刪除上有著較大的不同。因為雙鏈表有prior指標,可以很方便地找到其前驅結點,因此插入,刪除結點的時間複雜度為O(1)。
前插操作
將結點s 插入到指標p所指結點b之前:
bool DLinkList_Insert(DLinkList& L,ElemTyep c){
DNode* p;
/* 先檢查位置是否合法... */
DNode* s = (DNode*)malloc(sizeof(DNode));
s->data = c;
//第一步:結點s的prior指標指向左邊的結點
s->prior = p->prior;
//第二步:結點b的前驅結點(也就是左邊的結點)的next指標指向結點s
p->prior->next = s;
//第三步:結點s的next指標指向結點b
s->next = p;
//第四步:結點b的prior指標指向結點s
p->prior = s;
return true;
}
注意:第一,二步必須在第四步之前,否則*p的前驅結點的指標就會丟失,導致插入失敗。
後插操作
將結點s 插入到指標p所指的節點b 之後(如上圖,假設後面的結點是d):
bool DLinkList_Insert(DLinkList& L,ElemType c){
DNode* p;
DNode* s = (DNode*)malloc(sizeof(DNode));
s->data = c;
//第一步:將結點s 的next指標指向後繼結點
s->next = p->next;
//第二步;將後繼結點的prior指標指向結點s
p->next->prior = s;
//第三步:將結點s的prior指標指向結點b
s->prior = p;
//第四步:將結點b的next指標指向結點s
p->next = s;
return true;
}
同樣的,前插操作和後插其實沒區別,注意第四步即可,大家不清楚可以在草稿紙上面畫出來,畫出來了就一目瞭然了。
刪除操作
刪除指標p指向的結點b:
bool DLinkList_Delete(DLinkList& L){
DNode* p;
//第一步:將結點b的前驅結點的next指標指向結點c
p->prior->next = p->next;
//第二步:將結點c的prior指標指向結點b的前驅結點
p->next->prior = p->prior;
//釋放結點空間
free(p);
}
如果是刪除指標p指向的結點的後繼結點,指標q指向後繼結點,也就是後刪:
bool DLinkList_Delete(DLinkList& L){
DNode *p,*q;
p->next = q->next;
q->next->prior = p;
free(q);
}
如果覺得本文對你有幫助的話,不妨關注作者一波,小小的關注其實對我很重要。更多高質量內容與資料請訪問:資料結構簡單學,個人主頁:修心的小屋
如果喜歡的話,不妨關注一波,謝謝啦。