【算法竞赛入门经典】6.2链表 例题6-4 UVa11988
链表是啥玩意
链表可以看作是vector功能的一个扩展,在实现不定长数组的基础上,不仅仅能在末尾添加/删除元素,可以在数组中插入元素。
链表实现方式
链式
顾名思义,链式存储结构是最常用的链表实现方法。
typedef struct List
{
int data;
struct List *next;
};
这个非常常见,到是都是关于它的介绍,我就不写了。
数组模拟
这个有一些优雅,也告诉了我们链表并不一定要用指针。
看一个例题UVa11988
You’re typing a long text with a broken keyboard. Well it’s not so badly broken. The only problem
with the keyboard is that sometimes the “home” key or the “end” key gets automatically pressed
(internally).
You’re not aware of this issue, since you’re focusing on the text and did not even turn on the
monitor! After you finished typing, you can see a text on the screen (if you turn on the monitor).
In Chinese, we can call it Beiju. Your task is to find the Beiju text.
Input
There are several test cases. Each test case is a single line containing at least one and at most 100,000
letters, underscores and two special characters ‘[’ and ‘]’. ‘[’ means the “Home” key is pressed
internally, and ‘]’ means the “End” key is pressed internally. The input is terminated by end-of-file
(EOF).
Output
For each case, print the Beiju text on the screen.
Sample Input
This_is_a_[Beiju]_text
[[]][][]Happy_Birthday_to_Tsinghua_University
Sample Output
BeijuThis_is_a__text
Happy_Birthday_to_Tsinghua_University
下面开始贴本题的题解代码部分来解释。
const int maxn = 100000 + 5;
int last, cur, next[maxn]; // 光标位于cur号字符之后面
char s[maxn];
可以理解为固定了链表的大小为maxn,空间已经分配好,即使没有被使用/没有串进表中,空间也已经在那里了。
last指向表尾元素,cur指向当前元素。
next数组可以理解为链式结构汇总结构体内的指针,指向当前数据的下一个数据的序号。
这样,创建数据的时候就可以理解了
while(scanf("%s", s+1) == 1) {
int n = strlen(s+1); // 输入保存在s[1], s[2]...中
last = cur = 0;
next[0] = 0;
此段代码将字符串的所有数据全部放到了s数组当中,即已经分配好的空间里面。但是,节点并没有指定连接顺序,即不能确定链式结构中指针的指向。此处为初始化但不代表没有值,只不过认为是没有的。
此时,尾指针指向0,当前元素指针也指向0,而0中没有值,即可以认为是NULL。第一个元素的指针也指向NULL;
接下来开始将他们串起来
for(int i = 1; i <= n; i++) {
char ch = s[i];
if(ch == '[') cur = 0;
else if(ch == ']') cur = last;
else {
next[i] = next[cur];
next[cur] = i;
if(cur == last) last = i; // 更新“最后一个字符”编号
cur = i; // 移动光标
}
}
此处根据’[‘和’]’来修改当前元素位置来控制下一个插入的地方。即可以理解为链式结构中的当前指针。
每一个s[i]节点都已经是创建好了的,接下来只需要插入即可。
next[i] = next[cur];
类比链式结构中,即可以理解为,将插入节点的指针域指向原来当前节点所指向的那个节点。
next[cur] = i;
类比链式结构中,当前节点指针域指向新插入的s[i]节点
if(cur == last) last = i; // 更新“最后一个字符”编号
这一句字面意思没什么好讲的。
cur = i; // 移动光标
类比链式结构中,当前节点的指针改为指向新插入的s[i]节点。
这样理解来看就可链式结构是一个意思了。区别仅仅在于所有节点已经创建好了只是没有串连且指针域是用已经提前创建好的数组下标来表示的。
完整题目代码【原书上的】
// UVa11988 Broken Keyboard
// Rujia Liu
#include<cstdio>
#include<cstring>
const int maxn = 100000 + 5;
int last, cur, next[maxn]; // 光标位于cur号字符之后面
char s[maxn];
int main() {
while(scanf("%s", s+1) == 1) {
int n = strlen(s+1); // 输入保存在s[1], s[2]...中
last = cur = 0;
next[0] = 0;
for(int i = 1; i <= n; i++) {
char ch = s[i];
if(ch == '[') cur = 0;
else if(ch == ']') cur = last;
else {
next[i] = next[cur];
next[cur] = i;
if(cur == last) last = i; // 更新“最后一个字符”编号
cur = i; // 移动光标
}
}
for(int i = next[0]; i != 0; i = next[i])
printf("%c", s[i]);
printf("\n");
}
return 0;
}