重學資料結構(二)雙鏈表
阿新 • • 發佈:2018-11-08
這次是系列二,雙鏈表,具體的說明就不太詳細說了,註釋都加到Code中去了,很詳細,特此記錄~
還是先簡單說一下雙鏈表:
以下是維基百科中對雙鏈表的定義:
雙向連結串列,又稱為雙鏈表,是連結串列的一種,它的每個資料結點中都有兩個指標,分別指向直接後繼和直接前驅。所以,從雙向連結串列中的任意一個結點開始,都可以很方便地訪問它的前驅結點和後繼結點。一般我們都構造雙向迴圈連結串列。
再看直觀圖:
其實迴圈雙鏈表只是將一個鏈變成了一個環,他們都可以從任意一個位置開始,訪問鏈上的任意一個元素,迴圈連結串列的尾節點的next
指標指向了頭結點,而頭節點的prior指標則是指向了尾節點.
接下來就是雙鏈表的一些基本功能,而迴圈列表就需要進一步的拓展了,這裡不再贅述:
首先是DLinkList.h:
#include <stdio.h>
#include <malloc.h>
#ifndef DLNODE_DLINKLIST_H
#define DLNODE_DLINKLIST_H
#define TRUE 1
#define ERROR 0
//雙鏈表
typedef struct DLNode {
int data;
struct DLNode *prior;
struct DLNode *next;
} DLinkList;
/**
* 頭插法建立雙鏈表
* @param L 雙鏈表
* @param a 連結串列元素
* @param n 連結串列長度
* @return 返回的是生成的連結串列的首節點的地址
*/
DLinkList * CreateListByHead(DLinkList *L, int a[], int n) {
DLinkList *s;
L->prior = L->next = NULL;
for (int i = 0; i < n; ++i) {
s = (DLinkList *) malloc(sizeof(DLinkList));
s->data = a[i];
s->next = L->next;
if (L->next != NULL)
L->next->prior = s;
L->next = s;
s->prior = L;
}
return L;
}
/**
* 尾插法建立雙鏈表
* @param L 雙鏈表
* @param a 連結串列元素
* @param n 連結串列長度
* @return 返回的是生成的連結串列的首節點的地址
*/
DLinkList * CreateListByRoil(DLinkList *L, int a[], int n) {
DLinkList *r = L, *s; //r指標用來指向L的尾節點,s 是每次產生的新的節點
for (int i = 0; i < n; ++i) {
s = (DLinkList *) malloc(sizeof(DLinkList));
s->data = a[i];
r->next = s;
s->prior = r;
r = s;//r始終指向連結串列的尾節點
}
r->next = NULL;
return L;
}
/**
* 在雙鏈表某邏輯位置上插入值為e的元素
* @param L 傳入的雙鏈表
* @param i 邏輯位置
* @param e 插入的元素
* @return 插入成功返回TRUE(1),失敗返回ERROR(0)
*/
int ListInsert(DLinkList *L, int i, int e) {
DLinkList *r = L, *s;
int j = 0;
while (r != NULL && j < i - 1) {//找到第i-1個位置
j++;
r = r->next;
}
if (r == NULL)
return ERROR;
else {
s = (DLinkList *) malloc(sizeof(DLinkList));
s->data = e;
s->next = r->next;
//可能在最後一個節點之後插入,此時最後一個節點的next為NULL,不包含指標
if (r->next != NULL)
r->next->prior = s;
r->next = s;
s->prior = r;
return TRUE;
}
}
/**
* 刪除雙鏈表上邏輯位置的元素
* @param L 雙鏈表
* @param i 邏輯位置
* @return 成功返回TRUE(1),失敗返回ERROR(0)
*/
int ListDelete(DLinkList *L, int i) {
DLinkList *p = L, *q;
int j = 0;
//首先找到邏輯位置第i-1個元素,防止指標斷鏈
//跟下標沒有關係,因為j<i最後出來的是移動次數
while (p != NULL && j < i - 1) {
j++;
p = p->next;
}
if (p == NULL)
return ERROR;
else {
q = p->next;
//刪除位置為空
if (q == NULL) {
return ERROR;
}
p->next = q->next;
//這裡其實要分成兩種情況,但是最後提取了一下程式碼
//可能刪除的是最後一個節點
if (q->next != NULL)
q->next->prior = p;
free(q);
return TRUE;
}
}
/**
* 輸出雙鏈表
*/
void OutputLink(DLinkList *L){
//輸出前i-1個元素
while (L->next != NULL){
printf("%d<=>",L->data);
L = L->next;
}
printf("%d",L->data);
}
#endif //DLNODE_DLINKLIST_H
main函式:
#include <stdio.h>
#include "DLinkList.h"
#define MAX_SIZE 5
int main() {
DLinkList *L = (DLinkList *) malloc(sizeof(DLinkList));
int a[MAX_SIZE];
for (int i = 0; i < MAX_SIZE; ++i) {
a[i] = i+1;
}
//頭插法建立雙鏈表
printf("\n頭插法建立的雙鏈表為: ");
OutputLink(CreateListByHead(L, a, MAX_SIZE));
//尾插法建立雙鏈表
printf("\n尾插法建立的雙鏈表為: ");
OutputLink(CreateListByRoil(L, a, MAX_SIZE));
//在特定位置插入(注意,此時的L為尾插法建立的連結串列)
int k = ListInsert(L, 6, 9);
if (k == 0)
printf("\nERROR!");
else
printf("\n在第六個位置插入後的雙鏈表為: "); OutputLink(L);
//刪除特定位置元素(注意,此時的L為尾插法建立的連結串列)
int z = ListDelete(L, 6);
if (z == 0)
printf("\nERROR!");
else
printf("\n刪除第六個位置的元素後的雙鏈表為: ");OutputLink(L);
return 0;
}