Bootstrap

第三章 链表和list 双向链表部分

第三章 链表和list 双向链表部分

该部分与单链表部分基本相同,但是增加了prev指针域,即双向链表。

实现方式

依旧采用静态实现。双向链表就是在单链表的基础上加上一个前驱指针,增加一个数组充当前驱指针。

本部分与上部分基本相同,将单链表理解透彻后,双向链表就不难理解了。

基本定义

const int N = 100010;

int h;       /* 头指针 */
int e[N];    /* 数据域 */
int ne[N];   /* 指针域 */
int id;      /* 分配地址给新结点 */

int prev[N]; /* 新增:前驱指针 */
int mp[N];   /* 标记各值位置的数组 */

头插

void push_front(int x) {
    id++;
    e[id] = x;
    mp[x] = id;
    ne[id] = ne[h];
    prev[id] = h;
    prev[ne[h]] = id;
    ne[h] = id;
}

时间复杂度:O(1)

遍历链表

这里无需prev数组,与单链表相同。

void print() {
    for (int i = ne[h]; i ; i = ne[i]) {
        cout << e[i] << " ";
    } 
}

时间复杂度:O(n)

按值查找

直接利用标记数组即可。

int find(int x) {
    return mp[x];  
}

时间复杂度:O(1)

在任意位置后插入元素

void insert_back(int p, int x) {
    id++;
    e[id] = x;
    mp[x] = id;
    ne[id] = ne[p];
    prev[id] = p;
    prev[ne[p]] = id; 
    ne[p] = id;
}

时间复杂度:O(1)

在任意位置前插入元素

void insert_front(int p, int x) {
    id++;
    e[id] = x;
    mp[x] = id;
    ne[id] = p;
    prev[id] = prev[p];
    ne[prev[p]] = id;
    prev[p] = id; 
}

时间复杂度:O(1)

删除任意位置的元素

void del(int p) {
    if (p) {
        mp[e[p]] = 0;
        prev[ne[p]] = prev[p];
        ne[prev[p]] = ne[p];
    } 
}

时间复杂度:O(1)

在此再次提醒,无论是e[]还是ne[]抑或是prev[],括号内的内容即下标代表的都是结点的物理地址,而不是逻辑地址。

;