Ps.很好的一道对链表的练习题,第一次练习使用链表,也是发现了自己对链表实现很多不清晰的理解(一片WA声) b( ̄▽ ̄)d
题目:UVA-11988
题目描述:每个样例是一行无空格的字符串,模拟在电脑上打字,’[’ 代表光标移至开头,之后的字符串整体打印在开头,‘]’ 代表光标移至末尾,之后的字符正常在末尾打印。要求输出打印出来的字符
样例输入:This_is_a_[Beiju]_text
[[]][][]Happy_Birthday_to_Tsinghua_University
样例输出:BeijuThis_is_a__text
Happy_Birthday_to_Tsinghua_University
分析:
首先这题用单纯数组存储来实现是肯定不行的,数组的插入需要把后面所有元素后移一位,会TLE,而链表就可以很灵活地插入了。
一开始理解错了题意,用了双向的链表,左右两边延伸,导致样例输入的“This_is_a_[Beiju]_text"的输出变成了“ujieBThis_is_a__text”。这里 ‘[’ 的意思应该是将从 ‘[’ 之后到下一个 ‘[ ’ 或 ‘]’ 之前的所有字符原顺序打印在开头,所有应该是单向链表的插入操作,把 '[’ 之后的字符挨个插入到head节点后面。
首先是用指针实现链表(一堆注释,给自己理解):
#include<iostream>
#include<string>
#include<cstdio>
#include<sstream>
using namespace std;
struct node
{
char ch;node *next;
};
int main()
{
node *head, *tail, *p; //head 头节点,tail指向尾部(用于返回末尾)string str; //指针p代表光标位置,每下一个字符都放在p节点(光标)之后 while (cin >> str) //读取一行{
p = tail = head = new(node); //统一初始化,头节点并不用于存放元素p->next = NULL;stringstream ss(str); //将str放入名为ss的流中 (需要头文件sstream)char c;while (ss>>c) //从ss中依次读取字符{
if (c == '[') //若为‘[’ 光标p移至开头p = head;else if (c == ']') //若为‘]’ 光标p移至末尾p = tail;else{
node *x = new (node); //创建新节点xx->ch = c;x->next = NULL;if (p->next == NULL) //当光标p后没有字符{
p->next = x; p = tail = x; //末尾更新为x,光标p后移一位(等于x)}else //当光标p后面有字符{
x->next = p->next; //进行链表插入操作(插入到光标p之后)p->next = x;p = x; //光标p后移一位(等于x)}}}node *prei=head;for (node *i = head->next; i != NULL; i = i->next){
//输出,同时释放内存(delete)putchar(i->ch);delete(prei);prei = i;}delete(prei);putchar('\n');}return 0;
}
单向链表用数组来实现会方便很多,但是我一开始看用数组实现的链表一脸懵逼,写一下我自己对其的理解吧。
数组实现的链表 类比于 结构体指针的链表
数组实现中用node[maxn]来存储节点数据,在这里,node的下标实际上相当于一个地址,每个节点都有各自的下标(理解为地址),node[maxn]中只需要依次存储就行。
数组实现中用next[maxn]来充当指针,每个next中存储着链表中该节点下一位的下标(理解为地址),那么i=next[i]就相当于p=p->next,以此类推。
举个栗子:
在位于链表末尾的节点a(下标为a)后面插入一个下标为b的节点,那么操作就是
//数组实现
next[b]=next[a]; //next[b]是b的下一位,next[a]是a的下一位
next[a]=b;//链表实现
b->next=a->next;
a->next=b;
这样类比一下,数组实现链表就很好理解了( ?? ω ?? )y
以下数组实现链表的解题代码
#include<iostream>
#include<string>
#include<cstdio>
#include<sstream>
using namespace std;
int main()
{
char node[100001];char c;string str;while (cin >> str) {
int head = 0, tail=0, p=0, count=0; //count用于在node中依次存储int next[100001] = {
0 }; //next全初始化为0,类比于空指针stringstream ss(str); //p依旧代表光标while (ss>>c){
if (c == '[')p = head;else if (c == ']')p = tail;else{
count++;node[count] = c; //现在count就相当于现在这个节点的地址了if (next[p] == 0) //当p为末尾,新节点接到后面然后更新为末尾{
next[p] = count;p=tail= count;}else //当p不为末尾,则插入{
next[count] = next[p];next[p] = count;p = count;}}}for (int i = next[head]; i != 0; i = next[i]) putchar(node[i]); //一样的遍历方式,head只做头节点,不存数据putchar('\n');}return 0;
}