手撕算法——链表

发布于:2025-03-24 ⋅ 阅读:(25) ⋅ 点赞:(0)

算法基础——链表-CSDN博客

一、排队顺序

题⽬来源:洛⾕

题⽬链接:B3630 排队顺序 - 洛谷

难度系数:★

1. 题目描述

2. 算法原理

        本题相当于告诉了我们每⼀个点的后继,使⽤静态链表的存储⽅式能够很好的还原这个队列。

        数组 [1, n的下标可以当做据域,根据题意修指针域即可。

 

注意:可以不需要 e[N] 数组,输出下标即可 

3. 参考代码 

#include <iostream>

using namespace std;

const int N = 1e6 + 10;

int n, h;
int ne[N];

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> ne[i];
    cin >> h;
    
    // 遍历链表
    for(int i = h; i; i = ne[i])
    {
        cout << i << " ";
    }

    return 0;
}

二、单向链表

题⽬来源:洛⾕

题⽬链接:B3631 单向链表 - 洛谷

难度系数:★

1. 题目描述

2. 算法原理

        链表模板题,直接实现⼀个单链表即可。

3. 参考代码

#include <iostream>

using namespace std;

const int N = 1e5 + 10, M = 1e6 + 10;

// 链表
int h, id, e[N], ne[N];
int mp[M]; // mp[i] 用来标记 i 这个元素存在什么位置

int main()
{
    int q; cin >> q;

    // 初始化
    id++;
    e[id] = 1;
    mp[1] = id;

    while(q--)
    {
        int op, x, y;
        cin >> op >> x;
        int p = mp[x]; // x 存的位置

        if(op == 1) // x 后面插入
        {
            cin >> y;

            id++;
            e[id] = y;
            ne[id] = ne[p];
            ne[p] = id;

            mp[y] = id; // 标记 y 这个元素存的位置
        }
        else if(op == 2) // 查询 x 后面的元素
        {
            cout << e[ne[p]] << endl;
        }
        else // 删除 x 后面的元素
        {
            ne[p] = ne[ne[p]];
        }
    }

    return 0;
}

三、队列安排

题⽬来源:洛⾕

题⽬链接:P1160 队列安排 - 洛谷

难度系数:★★

1. 题目描述

2. 算法原理

        频繁的在某⼀个位置之前和之后插⼊元素,因此可以⽤双向循环的链表来模拟。

3. 参考代码

#include <iostream>

using namespace std;

const int N = 1e5 + 10;

// 双向链表
int h, pre[N], ne[N];
bool st[N]; // st[x] 表示 x 这个元素是否已经被删除

int n, m;

int main()
{
    cin >> n;
    // 初始化
    pre[1] = h;
    ne[h] = 1;

    for(int i = 2; i <= n; i++)
    {
        int k, p; cin >> k >> p;
        if(p == 0)
        {
            // i 放在 k 的左边
            ne[i] = k;
            pre[i] = pre[k];
            ne[pre[k]] = i;
            pre[k] = i;
        }
        else
        {
            // i 放在 k 的右边
            pre[i] = k;
            ne[i] = ne[k];
            pre[ne[k]] = i;
            ne[k] = i;
        }
    }

    cin >> m;
    while(m--)
    {
        int x; cin >> x;
        // 将 x 删除
        if(st[x] == true) continue;

        ne[pre[x]] = ne[x];
        pre[ne[x]] = pre[x];
        st[x] = true; // 标记 x 已经被删除
    }

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


    return 0;
}

四、约瑟夫问题

题⽬来源:洛⾕

题⽬链接:P1996 约瑟夫问题 - 洛谷

难度系数:★

1. 题目描述

2. 算法原理

        使⽤循环链表模拟即可。

3. 参考代码

#include <iostream>

using namespace std;

const int N = 110;

int n, m;
int ne[N];

int main()
{
    cin >> n >> m;
    // 创建循环链表
    for(int i = 1; i < n; i++) ne[i] = i + 1;
    ne[n] = 1;

    // 模拟约瑟夫游戏的过程
    int t = n;
    for(int i = 1; i <= n; i++) // 执行 n 次出圈操作
    {
        for(int j = 1; j < m; j++) // 让 t 向后移动 m - 1 次
        {
            t = ne[t];
        }

        cout << ne[t] << " ";
        ne[t] = ne[ne[t]];
    }

    return 0;
}

网站公告

今日签到

点亮在社区的每一天
去签到