1. 程式人生 > >重學資料結構(二)雙鏈表

重學資料結構(二)雙鏈表

這次是系列二,雙鏈表,具體的說明就不太詳細說了,註釋都加到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;
}
最後的結果圖:

結果圖