数组模拟单链表 ← 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

相关推荐
ankleless20 小时前
C语言(11)—— 数组(超绝详细总结)
c语言·零基础·数组·二维数组·自学·一维数组
梁辰兴2 天前
数据结构:串、数组与广义表
开发语言·数据结构·c··数组·广义表
没有bug.的程序员7 天前
《常见高频算法题 Java 解法实战精讲(1):链表与数组》
java·算法·链表·数组
意法半导体STM3218 天前
STM32CubeMX 生成时钟获取函数的分析
mcu·stm32cubemx·数组·st·意法半导体·hal 时钟获取函数
Alfred king18 天前
Leetcode 四数之和
算法·leetcode·职场和发展·数组·排序·双指针
Alfred king19 天前
面试150 不同路径Ⅱ
矩阵·动态规划·数组
SoveTingღ19 天前
【C语言】数组和指针一样吗?
c语言·unix·指针·数组·嵌入式软件
Alfred king22 天前
面试150 搜索二维矩阵
线性代数·矩阵·二分查找·数组
Alfred king22 天前
面试150 IPO
面试·职场和发展·贪心·数组··排序
Alfred king23 天前
面试150 建立四叉树
矩阵··数组·分治