AcWing学习——链表

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题库

c++ 复制代码
#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题库

c++ 复制代码
#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;
}
相关推荐
董董灿是个攻城狮1 小时前
AI视觉连载8:传统 CV 之边缘检测
算法
blasit8 小时前
笔记:Qt C++建立子线程做一个socket TCP常连接通信
c++·qt·tcp/ip
AI软著研究员9 小时前
程序员必看:软著不是“面子工程”,是代码的“法律保险”
算法
FunnySaltyFish9 小时前
什么?Compose 把 GapBuffer 换成了 LinkBuffer?
算法·kotlin·android jetpack
颜酱10 小时前
理解二叉树最近公共祖先(LCA):从基础到变种解析
javascript·后端·算法
地平线开发者1 天前
SparseDrive 模型导出与性能优化实战
算法·自动驾驶
董董灿是个攻城狮1 天前
大模型连载2:初步认识 tokenizer 的过程
算法
地平线开发者1 天前
地平线 VP 接口工程实践(一):hbVPRoiResize 接口功能、使用约束与典型问题总结
算法·自动驾驶
罗西的思考1 天前
AI Agent框架探秘:拆解 OpenHands(10)--- Runtime
人工智能·算法·机器学习
HXhlx1 天前
CART决策树基本原理
算法·机器学习