Problem5792--学习系列——链表 I——单向链表

5792: 学习系列——链表 I——单向链表

[Creator : ]
Time Limit : 1.000 sec  Memory Limit : 256 MiB

Description

【知识点】
链表是数据结构之一,其中的数据呈线性排列。在链表中,数据的添加和删除都较为方便,就是访问比较耗费时间。
我们把链表中的数据量记成 $n$。访问数据时,我们需要从链表头部开始查找(线性查找),如果目标数据在链表最后的话,需要的时间就是 $O(n)$。
另外,添加数据只需要更改两个指针的指向,所以耗费的时间与 $n$ 无关。如果已经到达了添加数据的位置,那么添加操作只需花费 $O(1)$ 的时间。删除数据同样也只需 $O(1)$ 的时间。
【什么是链表】
链表 是由一个个 结点 组成,每个 结点 之间通过 链接关系 串联起来,每个 结点 都有一个 后继节点,最后一个 结点 的 后继结点 为 空结点。如下图所示:

一个结点包含的两部分如下图所示:


这就是链表的概念图。Blue、Yellow、Red 这 $3$ 个字符串作为数据被存储于链表中。每个数据都有 $1$ 个“指针”,它指向下一个数据的内存地址。
在链表中,数据一般都是分散存储于内存中的,无须存储在连续空间内。

【顺序访问】
因为数据都是分散存储的,所以如果想要访问数据,只能从第 $1$ 个数据开始,顺着指针的指向一一往下访问(这便是顺序访问)。比如,想要找到 Red 这一数据,就得从 Blue 开始访问。这之后,还要经过 Yellow,我们才能找到 Red。
【添加数据】
如果想要添加数据,只需要改变添加位置前后的指针指向就可以,非常简单。比如,在 Blue 和 Yellow 之间添加 Green。

将 Blue 的指针指向的位置变成 Green,然后再把 Green 的指针指向 Yellow,数据的添加就大功告成了。

尾插法

头插法

【删除】
数据的删除也一样,只要改变指针的指向就可以,比如删除 Yellow。

这时,只需要把 Green 指针指向的位置从 Yellow 变成 Red,删除就完成了。虽然 Yellow 本身还存储在内存中,但是不管从哪里都无法访问这个数据,所以也就没有特意去删除它的必要了。今后需要用到 Yellow 所在的存储空间时,只要用新数据覆盖掉就可以了。




【单向链表实现】
在真正使用的时候,我们会在链表前面加上一个头结点,该结点用于表示单向链表的头位置。
对于单项链表,实现方法有两种。
【STL 的 list】


【数组模拟】
和 STL 的 list 类相比,使用数组模拟链表速度更快,但是代码量不大。这点代价我们还是可以接受的。
使用一个一维数组来模拟链表,注意元素只是增加不会减少。所以定义 MAXN  的时候需要使用 $2$ 倍的容量。
需要实现的操作有插入元素,删除元素。


【链表的定义】
const int MAXN=2e6+10; //数组元素个数
LL e[MAXN];                   //保存链表的结点。e[i] 表示第 i 个链表的数据为 e[i]
LL ne[MAXN];                 //保存链表的下一个结点索引。ne[i] 表示第 i 个链表的下一个结点为 ne[i],其中 ne[0] 保存头结点位置
LL idx;                           //用到数组的索引。
【链表的初始化】
void init() {
    ne[0]=-1;//头结点
    idx=1;     //链表头结点已经使用
}
【插入元素】
在单向链表中插入元素,可以在头结点位置插入,也可以在指定的 $pos$ 位置插入。
void add(LL val, LL pos=-1) {
    e[idx]=val;//插入数据
    if (pos<0) {
        //插入头结点
        ne[idx]=ne[0];//修改指针
        ne[0]=idx++;//长度增加
    } else {
        //插入到pos位置
        ne[idx]=ne[pos];
        ne[pos]=idx++;
    }
}

【删除元素】
删除指定 $pos$ 位置后面的数据。
void remove(LL pos) {
    ne[pos]=ne[ne[pos]];//删除指针
}

【遍历链表】
//遍历链表
for (LL i=ne[0]; i!=-1; i=ne[i]) {
    cout<<e[i]<<" ";
}
cout<<"\n";

这样,我们就实现了使用数组模拟链表。

【任务】
给定一个 $N$ 次操作,每次操作为下列操作之一。
操作 $1\ x$:表示向链表头插入一个数 $x$。
操作 $2\ k$:表示删除第 $k$ 个位置的后面的数(当 $k$ 为 $0$ 时,表示删除头结点)。
操作 $3\ k\ x$:表示在第 $k$ 个位置的后面插入一个数 $x$(此操作中 $k$ 均大于 $0$)。

Input

第一行两个整数 $N\ (N ≤ 1,000)$,含义见试题描述。
接下来 $N$ 行,表示有 $N$ 个操作,具体操作参看题目描述。

Output

输出包括 $N$ 组,每组输出包括三行。
第一行输出:op:x,其中 $x$ 表示第几次操作。具体看样例输出。
第二行若干个数,将整个链表从左到右输出。
第三行为一个空行。

Sample 1 Input

10
1 9
3 1 -100
2 1
2 0
1 6
3 3 65
3 4 523
3 4 -5
3 3 -4
2 6

Sample 1 Output

op:1
9 

op:2
9 -100 

op:3
9 

op:4


op:5
6 

op:6
6 65 

op:7
6 65 523 

op:8
6 65 -5 523 

op:9
6 -4 65 -5 523 

op:10
6 -4 65 -5 

Source/Category

数据结构 2.1.链表