数组模拟单链表 ← C++

【题目来源】
https://www.acwing.com/problem/content/828/

【题目描述】
实现一个单链表,链表初始为空,支持三种操作:

  1. 向链表头插入一个数;
  2. 删除第 k 个插入的数后面的数;
  3. 在第 k 个插入的数后插入一个数。

现在要对该链表进行 M 次操作,进行完所有操作后,从头到尾输出整个链表。

注意:++题目中第 k 个插入的数并不是指当前链表的第 k 个数++ 。例如操作过程中一共插入了 n 个数,则按照插入的时间顺序,这 n 个数依次为:第 1 个插入的数,第 2 个插入的数,...第 n 个插入的数。

【输入格式】
第一行包含整数 M,表示操作次数。
接下来 M 行,每行包含一个操作命令,操作命令可能为以下几种:

  1. H x,表示向链表头插入一个数 x。
  2. D k,表示删除第 k 个插入的数后面的数(当 k 为 0 时,表示删除头结点)。
  3. I k x,表示在第 k 个插入的数后面插入一个数 x(此操作中 k 均大于 0)。

【输出格式】
共一行,将整个链表从头到尾输出。

【数据范围】
1≤M≤100000
所有操作保证合法。

【输入样例】
10
H 9
I 1 1
D 1
D 0
H 6
I 3 6
I 4 5
I 4 5
I 3 4
D 6

【输出样例】
6 4 6 5

【算法分析】
本题利用数组模拟实现单链表。利用数组模拟单链表常见的核心操作代码如下所示:

cpp 复制代码
// head   头结点的下标
// e[i]   结点i的值
// ne[i]  结点i的next指针
// idx    当前可用结点的下标,可看做指针

int head, e[N], ne[N], idx;

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

void add_to_head(int x) { //将x插入到首元结点
    e[idx]=x;
    ne[idx]=head;  // idx指向head指向的结点
    head=idx++;     // head指向idx
}

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

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

学习过链式前向星(https://blog.csdn.net/hnjzsyjyj/article/details/126474608)的会发现这些模拟单链表的变量及数组很熟悉。这是因为,链式前向星也是用数组模拟单链表,不过是要模拟多个单链表。链式前向星常见的核心操作代码如下所示:
其中:
val[idx] 表示第 idx 条边的权值。
e[idx] 表示第 idx 条边的终点。
ne[idx] 表示与第 idx 条边同起点的最近一次被添加的边的编号。
h[a] 表示以结点 a 为起点的最近一次被添加的边的编号。这个表述是在使用 ne[idx]=h[a] 时,也即使用 h[a]=idx++ 更新 h[a] 之前而言的。要特别注意这个语境。
很明显,h[a] 中存储的是以 a 为起点的所有边中编号最大的那个。且在遍历时,把这条边作为以 a 为起点的所有边中的第一条边进行遍历。即边的遍历顺序与输入顺序恰好是相反的。而网上常见的表述"e[idx] 表示第 idx 条边的终点,ne[idx] 表示与第 idx 条边同起点的**++下一条边++** 的存储位置,h[a] 表示以 a 为起点的++第一条边++的存储位置",是按边的遍历顺序进行表述的。
在上述约定下,则有:
● 链式前向星的核心代码如下:

cpp 复制代码
void add(int a,int b) {
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

如果是有权图,需多设置一个数组 val[] 存储权值。有权图的链式前向星的核心代码如下:

cpp 复制代码
void add(int a,int b,int w) {
    val[idx]=w,e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

● 基于链式前向星的深度优先搜索(DFS)的核心代码如下:

cpp 复制代码
void dfs(int u) {
    cout<<u<<" ";
    st[u]=true;
    for(int i=h[u]; ~i; i=ne[i]) { //~i; equivalent to i!=-1;
        int j=e[i];
        if(!st[j]) {
            dfs(j);
        }
    }
}

● 基于链式前向星的广度优先搜索(BFS)的核心代码如下:

cpp 复制代码
void bfs(int u) {
    queue<int>q;
    st[u]=true;
    q.push(u);
    while(!q.empty()) {
        int t=q.front();
        q.pop();
        cout<<t<<" ";
        for(int i=h[t]; ~i; i=ne[i]) { //~i; equivalent to i!=-1;
            int j=e[i];
            if(!st[j]) {
                q.push(j);
                st[j]=true; //need to be flagged immediately after being queued
            }
        }
    }
}

【算法代码】

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

const int N=1e5+5;

// head   头结点的下标
// e[i]   结点i的值
// ne[i]  结点i的next指针
// idx    当前可用结点的下标,可看做指针

int head, e[N], ne[N], idx;

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

void add_to_head(int x) { //将x插入到首元结点
    e[idx]=x;
    ne[idx]=head;  // idx指向head指向的结点
    head=idx++;     // head指向idx
}

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

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

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

    init();
    while(T--) {
        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 {
            cin>>k>>x;
            add(k-1,x);
        }
    }

    for(int i=head; i!=-1; i=ne[i]) cout<<e[i]<<" ";

    return 0;
}


/*
in:
10
H 9
I 1 1
D 1
D 0
H 6
I 3 6
I 4 5
I 4 5
I 3 4
D 6

out:
6 4 6 5
*/ 

【参考文献】
https://www.acwing.com/blog/content/2141/
https://blog.csdn.net/hnjzsyjyj/article/details/126474608

相关推荐
WenGyyyL2 天前
力扣每日一题——数组能够形成多少对
算法·leetcode·职场和发展·集合·数组·哈希表
水蓝烟雨6 天前
[数组基础] 0073. 矩阵置零
算法·leetcode·数组
IronmanJay12 天前
【LeetCode每日一题】——1791.找出星型图的中心节点
数据结构·算法·leetcode··数组··1791.找出星型图的中心节点
一直学习永不止步17 天前
LeetCode题练习与总结:拼接最大数--321
java·leetcode·贪心·数组··双指针·单调栈
CHENWENFEIc20 天前
数据结构之顺序表详解:从原理到C语言实现
c语言·数据结构·学习·算法·程序员创富·数组·改行学it
一直学习永不止步1 个月前
LeetCode题练习与总结:生命游戏--289
java·数据结构·算法·leetcode·矩阵·模拟·数组
小码狐1 个月前
力扣【2187-完成旅途的最少时间】【数组-C语言实现】
c语言·算法·leetcode·二分查找·数组
一直学习永不止步1 个月前
LeetCode题练习与总结:H 指数--274
java·数据结构·算法·leetcode·数组·排序·计数排序
一丝晨光1 个月前
不同语言的注释和数组
java·开发语言·javascript·c++·c·注释·数组
IronmanJay1 个月前
【LeetCode每日一题】——LCP 51.烹饪料理
数据结构·算法·leetcode·回溯·数组·递归·lcp 51.烹饪料理