【資料結構】雙鏈表和迴圈連結串列的相關操作--建立-插入-刪除-查詢
阿新 • • 發佈:2021-01-20
文章目錄
雙鏈表與迴圈連結串列
雙鏈表
單鏈表 VS 雙鏈表
- 單鏈表:無法逆向檢索,有時候不太方便
- 雙鏈表:可進可退,儲存密度更低一點
- 總結:單鏈表結點中,只有一個指向其後繼的指標,使得單鏈表只能從頭結點依次順序地向後遍歷。要訪問某個結點的前驅結點(插入、刪除操作時),只能從頭開始遍歷,訪問後繼結點的時間複雜度為O(1),訪問前驅結點的時間複雜度為O(n)。為了克服單鏈表此缺點,引入了雙鏈表,雙鏈表結點兩個指標分別指向其前驅結點和後繼結點。
雙鏈表的初始化(帶頭結點)
typedef struct DNode { ElemType data; struct DNode *prior,*next; }DNode,*DLinklist; //初始化雙鏈表 bool InitDLinklist (DLinklist &L) { L = (DNode *)malloc(sizeof(DNode)); //分配一個頭結點 if (L == NULL) { //記憶體不足,分配失敗 return false; } L -> prior = NULL; //頭結點的prior永遠指向NULL L -> next = NULL; //頭結點之後暫時沒有結點 return true; } //判斷雙鏈表是否為空(帶頭結點) bool Empty(DLinklist L) { if (L -> next == NULL) { return true; }else { return false; } }
雙鏈表的插入
- 因為雙鏈表在單鏈表的基礎上,為結點增加了前驅結點指標,故在進行插入操作時,也要根據鏈的變化對前驅結點指標進行修改,關鍵是保證在修改的過程中不斷鏈。
//雙鏈表的插入操作 //在p結點之後插入s結點 bool InsertNextDNode (DNode *p, DNode *s) { if (p == NULL || s == NULL) { //非法引數 return false; } s -> next = p -> next; if (p -> next != NULL) { //若p結點有後繼結點 p -> next -> prior = s; } s -> prior = p; p -> next = s; return true; }
- 前插操作:由於雙鏈表的結點有兩個指標,分別指向該結點的前驅結點和後繼結點,故要進行前插操作時,只需找到其前驅結點,並對其前驅結點實施後插操作,即可達到對結點的前插操作。
雙鏈表的刪除
//雙鏈表的刪除
//刪除p結點的後繼結點
bool DeleteNextDNode (DNode *p) {
if (p == NULL) {
return false;
}
DNode *q = p -> next; //找到p的後繼結點q
if (q == NULL) {
return false; //p沒有後繼結點
}
p -> next = q -> next;
if (q -> next != NULL) { //q結點不是最後一個結點
q -> next -> prior = p;
}
free(q); //釋放結點空間
return true;
}
//銷燬一個雙鏈表
void Destory (DLinklist &L) {
//迴圈釋放各個資料結點
while (L -> next != NULL) {
DeleteNextDNode(L);
}
free(L); //釋放頭結點
L = NULL; //頭結點指向NULL
}
雙鏈表的遍歷
//後向遍歷
while (p != NULL) {
//對結點p作相應處理
p = p -> next;
}
//前向遍歷
while (p != NULL) {
//對結點p做相應處理
p = p -> prior;
}
//前向遍歷(跳過頭結點)
while (p -> prior != NULL) {
//對結點p做相應處理
p = p -> prior;
}
迴圈連結串列
迴圈單鏈表
- 迴圈單鏈表:將單鏈表尾結點的next指標指向NULL改為指向單鏈表的頭結點
- 從一個結點出發可以找到其他任何一個結點
typedef struct LNode { //定義單鏈表結點型別
ElemType data; //每個結點存放一個數據元素
struct LNode *next; //指標指向下一個結點
}LNode,*LinkList; //強調為結點和強調為單鏈表
//初始化一個空的迴圈單鏈表
bool InitLink(LinkList &L) {
L = (LNode *)malloc(sizeof(LNode)); //分配一個頭結點
if(L == NULL) { //記憶體不足,分配失敗
return false;
}
L->next = L; //頭結點next指標指向頭結點
return true;
}
//判斷迴圈單鏈表是否為空
bool Empty(LinkList L) {
if(L->next == L) {
return true;
}else {
return false;
}
}
//判斷結點p是否為迴圈單鏈表的表尾結點
bool isTail(LinkList L, LNode *p) {
if(p->next == L) {
return true;
}else {
return false;
}
}
迴圈雙鏈表
- 將雙鏈表表尾結點的next指向頭結點,將頭結點的prior指向表尾結點,形成了迴圈
typedef struct DNode {
ElemType data;
struct DNode *prior,*next;
}DNode,*DLinklist;
//初始化雙鏈表
bool InitDLinklist (DLinklist &L) {
L = (DNode *)malloc(sizeof(DNode)); //分配一個頭結點
if (L == NULL) { //記憶體不足,分配失敗
return false;
}
L -> prior = L; //頭結點的prior指向頭結點
L -> next = L; //頭結點的next指向頭結點
return true;
}
//判斷雙鏈表是否為空(帶頭結點)
bool Empty(DLinklist L) {
if (L -> next == L) {
return true;
}else {
return false;
}
}
靜態連結串列
靜態連結串列的建立
- 靜態連結串列藉助陣列來描述線性表的鏈式儲存結構,結點也有資料域data和指標域next,與之前的連結串列指標不同的是,今天連結串列的指標是結點的相對地址(陣列下標),又稱作遊標。和順序表一樣,靜態連結串列也要預先分配一塊連續的記憶體空間。
#define MaxSize 50 //靜態連結串列的最大長度
typedef struct { //靜態連結串列結構型別的定義
ElemType data; //儲存資料元素
int next; //下一個元素的陣列下標
}SLinkList [MaxSize];
#define MaxSize 50 //靜態連結串列的最大長度
struct Node { //靜態連結串列結構型別的定義
ElemType data; //儲存資料元素
int next; //下一個元素的陣列下標
};
typedef struct Node SLinkList [MaxSize];