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

相关推荐
A懿轩A4 小时前
C/C++ 数据结构与算法【数组】 数组详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·数组
Moshow郑锴4 天前
Spring Boot中CollectionUtils怎么用
springboot·数组·collectionutil
LuckyLay5 天前
Golang学习笔记_13——数组
笔记·学习·golang·数组·array
暂时先用这个名字8 天前
PHP开发日志 ━━ 基础知识:四种不同的变量返回方式该如何调用
android·开发语言·缓存·php·框架·变量·数组
DogDaoDao12 天前
leetcode 面试经典 150 题:移除元素
算法·leetcode·面试·数组·双指针·快慢指针·数据结构与算法
繁星璀璨G15 天前
Lua语言入门 - Lua 数组
开发语言·lua·数组
软件架构师笔记15 天前
深入浅出 Go 语言:数组与切片
数据结构·算法·go·数组·切片
三月微暖寻春笋18 天前
【和春笋一起学C++】OpenCV中数组和指针运用实例
opencv·指针·数组·二值化·遍历像素
Lumos_yuan22 天前
Lumos学习王佩丰Excel第十八讲:LOOKUP函数与数组
学习·excel·数组·lookup函数
IronmanJay24 天前
【LeetCode每日一题】——189.轮转数组
数据结构·算法·leetcode·数组·189.轮转数组