链表的使用
(本文仅为笔者学习笔记,如有错误之处恳请各位读者指正)
简译:
你有一个破损的键盘。键盘上的所有键都可以正常工作,但有时Home键或者End键会自动按下。你并不知道键盘存在这一问题,而是专心地打稿子,甚至连显示器都没打开。当你打开显示器之后,展现在你面前的是一段悲剧的文本。你的任务是在打开显示器之前计算出这段悲剧文本。
输入包含多组数据。每组数据占一行,包含不超过100000个字母、下划线、字符"["或"]"。其中字符"["表示Home键,"]"表示End键。输入结束标志为文件结束符(EOF)。输入文件不超过5MB。对于每组数据,输出一行,即屏幕上的悲剧文本。
分析:
设输入的字符串是s[1~n],则可以用s[next[i]]表示在显示器中紧接着字符s[i]的下一个字符。将整个字符串看作一个链表,next[i]可以看作字符i的next指针。
(以下程序中只是在数组上模拟链表操作,并非真正意义上的链表)
#include<cstdio>
#include<cstring>
const int maxn = 100000+5;
int last; // last:链表尾指针
int cur; // 指向当前字符的前一个字符
int next[maxn]; // 记录链表中各个节点的后继节点(s数组中的下标)
char s[maxn]; // 文本数组
int main(){
while(scanf("%s", s+1) == 1){ // 有文本输入
int n = strlen(s+1); // s+1:输入保存在s[1],s[2]...中
last = cur = 0; // 初始化链表的尾指针和cur指针(均指向头部虚拟节点)
next[0] = 0;
for(int i=1; i<=n; i++){ // i:当前节点
char ch = s[i]; // 一次读取输入文本中的每个字符
if(ch == '[') // 碰到home键
cur = 0; // cur回到头节点继续写
else if(ch == ']') // 碰到end键
cur = last; // cur回到尾部节点继续写
else{
// 第一层循环: next[i=1]=next[cur=0]=0; next[cur=0]=1;
// 第二层循环: next[i=2]=next[cur=1]=0; next[cur=1]=2;
// next[当前字符节点]=next[cur上一个字符节点]=0; next[cur上一个字符节点]=当前字符节点
next[i] = next[cur]; // 将当前节字符点的next指针暂时指向头结点
next[cur] = i; // 将上一个字符节点的next指针指向当前字符节点
if(cur == last) // 更新尾指针
last = i;
cur = i; // cur指向当前字符,进入下一层循环后i+1,cur又指向了"前一个字符"
}
}
for(int i=next[0]; i!=0; i=next[i]){ // 按照next记录的后继节点在s数组中的下标依次输出文本中的字符
printf("%c",s[i]);
}
printf("\n");
}
return 0;
}
题目连接:Broken Keyboard(a.k.a. Beiju Text) - UVa 11988