模板例题的内容
实现一个单链表,链表初始为空,支持三种操作: 向链表头插入一个数; 删除第 k 个插入的数后面的数; 在第 k 个插入的数后插入一个数。 现在要对该链表进行 M 次操作,进行完所有操作后,从头到尾输出整个链表。 注意:题目中第 k 个插入的数并不是指当前链表的第 k 个数。例如操作过程中一共插入了 n 个数,则按照插入的时间顺序,这 n 个数依次为:第 1 个插入的数,第 2 个插入的数,…第 n 个插入的数。 输入格式 第一行包含整数 M,表示操作次数。 接下来 M 行,每行包含一个操作命令,操作命令可能为以下几种: H x,表示向链表头插入一个数 x。 D k,表示删除第 k 个插入的数后面的数(当 k 为 0 时,表示删除头结点)。 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 原题链接:https://www.acwing.com/problem/content/828/
参考代码(C++版本)
#include <iostream> using namespace std; const int N = 100010; //head 表示头结点的下标 //e[i] 表示结点i的值 //ne[i] 表示i的next指针 // idx 记录当前已经用到的结点数 int head , e[N],ne[N],idx; //初始化 void init() { head = -1; idx = 0; } //将x插入到头结点 void add_to_head(int x) { e[idx] = x; ne[idx] = head; head= idx++; } //将x插入到下标是k的结点的后面 void add(int k ,int x) { e[idx] = x; ne[idx] = ne[k]; ne[k] = idx++; } //将下标是k的结点的后面结点删掉 void remove(int k) { ne[k] = ne[ne[k]]; } int main() { int m; cin >> m; init(); //m次询问 while(m--) { 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] <<' '; cout << endl; return 0; }
为什么用数组来模拟链表
在竞赛中,使用new结构体的方式来实现链表在数据过于庞大的时候,会超时,也就是所谓的TLE(Time Limit Exceeded)
参数的理解
结构体实现单链表中指针思想在这里同样适用。
- head是头结点的下标。表示该单链表从数组中的起始位置
- . e[N]数组是存放每一个结点对应的值。e[6]就代表第六个结点的值(e是element的缩写)
- . ne[N]数组存放下一个结点的位置,相当于结构体单链表中的指针。在静态链表中采用了另外开一个数组ne[N]来存储下一个节点的下标的方式达到指针的效果(ne是next element的缩写)
- . idx 记录现在是第几个结点要进行操作
各个板块的分析
初始化
因为数组的索引都是从0开始的。故,用头指针指向-1来代表指向空
void init() { head = -1; idx = 0; }
在头结点插入
1. 将要插入的元素放到存放数据的e[N]数组中。现在是第idx个元素要进行操作。故,e[idx] = x;
2. 让这个插入的结点指向头结点指向的结点。形象来说,就是ne[N]这个数组中存放head存放的索引。ne[idx] = head;
3. 更新头指针中保存的信息,让头指针指向新插入的结点 head = idx;即通过头指针中保存的“地址”信息,可以找到相应的结点,获取其中的数据
4. 更新idx
void add_to_head(int x) { e[idx] = x; ne[idx] = head; head= idx++; }
将x插入到下标是k的结点后面
1. 将x的数据存入
2. 让新插入的节点指向下标是k的节点的后一个节点 ne[idx] = ne[k];
3. 让下标是k的节点指向新插入的节点
4. 更新idx
void add(in k ,int x) { e[idx] = x; ne[idx] = ne[k]; ne[k] = idx++; }
将下标是k的结点的后面结点删除
1. 和结构体链表的想法一样,让它指向它后一个结点的后一个结点
void remove(int k) { ne[k] = ne[ne[k]]; }