UVA-11988 Broken Keyboard (模拟,字符串,单向链表(指针实现、数组实现))

版权声明:个人学习笔记记录 https://blog.csdn.net/Ratina/article/details/83719197

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);  //创建新节点x
				x->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;
}

猜你喜欢

转载自blog.csdn.net/Ratina/article/details/83719197