1. 程式人生 > >雙向鏈表基礎

雙向鏈表基礎

復雜度 後繼 turn ini malloc 元素 刪除結點 span 新的

定義雙向鏈表

雙向鏈表只是在原來的單鏈表中加入了一個前驅指針,因此,在雙鏈表中執行按值查找和循秩查找與單鏈表是相同的。但在插入和刪除操作中和單鏈表有著較大的不同。此外雙鏈表還能很方便的找到其前驅結點,因此,除了找到插入結點外,插入和刪除結點的時間復雜度僅為\(O(1)\)

typedef struct DNode {
    ElemType data;  //數據域
    struct DNode *pred, *succ;  //前驅和後繼域
}DNode, *DLinkList;

雙向鏈表的尾插法初始化:

//尾插法
void InitList(DLinkList &L, int n)
{
    DNode *p, *q;
    L = (DNode*)malloc(sizeof(DNode));
    if(!L) exit(0);
    L->succ = L->pred = NULL;
    p = L;
    for(int i = 1; i <= n; ++i) {
        q = (DNode*)malloc(sizeof(DNode));
        q->data = i;
        if(!q) exit(0);
        q->succ = NULL;
        p->succ = q;
        q->pred = p;
        p = q;
    }
}

雙向鏈表中的插入操作

在雙向鏈表中第i個位置插入節點s的算法:

//在第i個位置之後插入新的元素
bool InsertDNode(DLinkList &L, int i, int e)
{
    int j = 1;
    DNode *p, *q, *s;
    p = L;
    while(p && j < i) {
        p = p->succ;
        j++;
    }
    if(!p || j > i) return false;
    s = (DNode*)malloc(sizeof(DNode));
    s->data = e;
    s->pred = p;  //第一步
    s->succ = p->succ; //第二步
    p->succ->pred = s; //第三步
    p->succ = s;  //第四步
}

上述的語句順序不是唯一的,但也不是任意的,一二步必須在第四步之前,否則*p的後繼結點的指針就丟掉了,導致插入失敗。


雙向鏈表的刪除操作

刪除雙向鏈表中第i個位置的後繼節點q的算法:只需要越過結點i處理i的前驅結點和後繼節點即可。

bool DeleteDNode(DLinkList &L, int i, int &e)
{
    int j = 1;
    DNode *p, *q, *s;
    p = L;
    while(p && j <= i) {  //找到結點i所在位置
        p = p->succ;
        j++;
    }
    if(!p || j > i + 1) return false;
    p->pred->succ = p->succ;
    p->succ->pred = p->pred;
    free(p);
    return true;
}

總結

雙向鏈表相對於單鏈表來說,要更復雜一些,因為它多了前驅指針,所以在插入和刪除操作時要格外小心,另外,由於它每個結點都要記錄兩份指針,所以略占空間,不過,由於它良好的對稱性,使得對某個結點的前後結點的操作帶來了方便,可以有效提高算法的時間性能,說白了就是用空間置換時間。

雙向鏈表基礎