1. 单链表

单链表常用于写邻接表,而邻接表的主要应用是用于存储图和树。

算法题的c/c++中,new一块地址空间的操作非常慢,当我们需要对非常大的数据进行链表操作时,可以使用数组模拟链表,即静态操作。

1.1. 数组模拟邻接表

使用两个数组e[]ne[]分别存储链表元素和next下标,并且利用一个指针idx指向当前可用下标,初始为0。

当在第k+1个位置处插入一个节点时,都相当于在e[idx]处存储当前数值,而ne[idx]处存储ne[k]的值,而ne[k]处存储idx值。

当要将第k个位置的值删除时,仅需令ne[k]处修改为ne[ne[k]]即可,无需考虑内存泄露问题,因为算法题主要是为了快。

1.2. 例题

1.2.3.826. 单链表 -AcWing题库

#include <iostream>

using namespace std;

const int N = 100010;

// head 表示头节点下标
// e[i] 表示节点i的值
// ne[i] 表示节点i的next指针是多少
// idx 存储当前已经用到了哪个点
int head, e[N], ne[N], idx;

//初始化
void init()
{
    head = -1;
    idx = 0;
}

// 头插法:将x插入头节点
void add_to_head(int x)
{
    e[idx] = x;
    ne[idx] = head;
    head = idx;
    idx++; 
}

// 将x插入下标为k的节点后面
void add(int k, int x)
{
    e[idx] = x;
    ne[idx] = ne[k];
    ne[k] = idx;
    idx++;
}

// 将下标为k的节点后面的节点删掉
void remove(int k)
{
    ne[k] = ne[ne[k]]; 
}

int main()
{
    int m;
    cin >> m;
    
    init();
    
    while(m --)
    {
        int k, x;
        char op;
        
        cin >> op;
        
        if(op == 'H')
        {
            cin >> x;
            add_to_head(x);
        }
        else if(op == 'D')
        {
            cin >> k;
            if(!k) head = ne[head];
            remove(k - 1);
        }
        else if(op == 'I')
        {
            cin >> k;
            cin >> x;
            add(k-1, x);
        }
    }
    
    for(int i = head; i != -1; i = ne[i]) cout << e[i] << " ";
    cout << endl;
    
    return 0;
}

2. 双链表

2.1. 数组模拟邻接表

使用三个数组e[]l[]r[]分别存储链表元素和当前元素的前一个元素下标和当前元素的后一个元素下标,并且利用一个指针idx指向当前可用下标,初始为0。

2.2. 例题

2.2.1.827.双链表 -AcWing题库

#include <iostream>

using namespace std;

const int N = 100010;

int m;
int e[N], l[N], r[N], idx;

// 初始化
void init()
{
    // 使用0表示左端点,1表示右端点,
    // 因为0和1已经被使用了,idx从2开始
    r[0] = 1;
    l[1] = 0;
    idx = 2;
}

// 在下标为k的节点后面插入x
void add(int k, int x)
{
    e[idx] = x;
    l[idx] = k;
    r[idx] = r[k];
    l[r[k]] = idx;
    r[k] = idx;
    idx++;
}

// 删除下标为k的节点
void remove(int k)
{
    r[l[k]] = r[k];
    l[r[k]] = l[k];
}


int main()
{
    ios::sync_with_stdio(false);
    cin >> m;

    init();

    while(m--)
    {
        string op;
        cin >> op;
        int k, x;
        if(op=="R")
        {
            cin >> x;
            //!   0和 1 只是代表 头和尾  所以   最右边插入 只要在  指向 1的 那个点的右边插入就可以了
            add(l[1], x); 
        }
        //! 同理  最左边插入就是 在指向 0的数的左边插入就可以了   也就是可以直接在 0的 有右边插入
        else if(op=="L")
        {
            cin >> x;
            add(0, x);
        }
        else if(op=="D")
        {
            cin >> k;
            remove(k + 1);
        }
        else if(op=="IL")
        {
            cin >> k >> x;
            add(l[k + 1], x);
        }
        else
        {
            cin >> k >> x;
            add(k + 1, x);
        }    
    }
    for(int i = r[0]; i != 1; i = r[i]) cout << e[i] << ' ';
        
    return 0;
}
本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:[email protected]