[ 数据结构 ] DS链表—学生宿舍管理

问题 J: DS链表—学生宿舍管理

时间限制: 1 Sec   内存限制: 128 MB
提交: 170   解决: 111
[ 提交][ 状态][ 讨论版]

题目描述

假设某校有20间宿舍,宿舍编号101,102,...,120。每间只住一名学生。初始部分宿舍已用。用两个链表(已用宿舍链表和可用宿舍链表)维护宿舍的管理,实现宿舍分配、宿舍交回。

约定已用宿舍链表按宿舍号升序链接。初始可用宿舍链表也按宿舍号升序链接。

宿舍分配从可用宿舍链表中摘取第一间宿舍分配给学生。学生交回的宿舍挂在可用宿舍链表最后。

备注:使用list容器或静态链表。不用考虑宿舍分配和交回不成功的情况。

输入

初始宿舍状态,第一行输入n,表示已用宿舍n间

后跟n行数据,每行格式为:宿舍号 学生姓名

操作次数m,后跟m行操作,操作格式如下:

assign 学生  //为学生分配宿舍,从可用宿舍链表头摘取一间宿舍,

                    //按宿舍号升序挂在已用宿舍链表中。

return  宿舍号   //学生退宿舍,删除已用宿舍链表中对应结点,

                         //挂在可用宿舍链表尾部。

display_free   //输出可用宿舍链表信息。

display_used   //输出已用宿舍链表信息。


输出

 display_free依次输出当前可用宿舍链表中的宿舍号,具体格式见样例。

 display_used依次输出当前已用宿舍链表中的学生和宿舍号,具体格式见样例。

样例输入

5
李明 10 3
张三 106
王五 107
钱伟 112
章立 118
8
assign 李四
assign 赵六
return 118
return 101
assign 马山
display_used
assign 林立
display_free

样例输出

赵六(102)-李明(103)-马山(104)-张三(106)-王五(107)-钱伟(112)
108-109-110-111-113-114-115-116-117-119-120-118-101

提示

/*
  看到这题第一反应:
  STL里有list的话,肯定直接用STL啊!自己写想必会麻烦多了!
  
  但是,用list的时候,又出了一些问题
  
----------------我本来的思路是这样子的:----------------
  写一个类 dorm 表示宿舍,有 string 类的元素姓名,和 int 类的元素,数字标号;并且给dorm类重载小于号等等..
  
  然后,再建2个list,存 dorm 类的元素,再按照题目要求写
  
  但是最后,这个思路被我废掉了,因为我遇到了各种各样的问题,比如说:
  1. 怎么让list对自定义类型排序
  这个其实我倒是查了不少资料,好像重载<即可,但是最后写出来,在DevC上,出了许多不知道怎么解决的问题
  
  2. 怎么找到给定标号的指定宿舍
  
  如果用 class dorm,并非不能处理,但是比较麻烦,不仅写得麻烦,比起我最终采用的方法,在时间效率上也糟糕许多
  
  还有许许多多的麻烦,不一一列举了,总之就是这个思路,我发现需要许多基本的知识,我都不懂,需要一一去查,所以...决定先放一放这个写自定义类型,并且用它来作为list的类型的方法
  
  嗯,先把别的题目都做完,还有机会再来看看这种方法,如果要实现,应该怎么实现
  
----------------我后来采取的思路:----------------
  后来的思路,就,写法上的简洁性和逻辑性上,就比我最初的思路好了不少(这个方法还是向同学请教的),所以说,有时方法很重要啊!~选错了方法,就是要查很多资料,最后发现这个方法没那么容易走通... T^T  
  
  这个方法就很巧妙了,我来总结一下为什么可以这么做:
  1. 对于空余的宿舍,我们只是需要知道它的标号即可,这个用 1个 list<int>来保存
  
  2.
  对于有人住的宿舍,我们要输出的信息比较多,而且含有中文,就势必需要用 char* 后者 string 类来完成,但是毕竟  C++ 的 string 类有很多方便操作字符串的函数,所以还是选 string 类
  
  但是这里有个小细节需要注意(一开始时,我就没有想明白这个问题,所以后来把这部分翻盘重写了一次):
  能不能在 assign 分配宿舍以后,直接将它转换为最终输出的那种格式呢?
  就是这种:
  姓名(宿舍号)这样?
  
  其实是不可以的!!!这个点有点隐蔽,我一开始为了方便输出,也想这么处理,但后来发现绝对不行!
  
  以为你输出时,已用宿舍是按照宿舍号排列,如果直接转为输出的格式,那么就变成了按名字排
  
  你说你去用 substr截取出名字?
  可你又知道名字一定是两位?虽然发出来的数据,名字都是2位的,但万一后台的名字,有些人名字是4位呢?
  
  你说你用 string类的 find_first_of来找到宿舍号的第一位?
  
  嗯,那如果宿舍号的范围改动一下,我只保证宿舍号是3位数,从100~999,而不是像这题,最高位一定是1,那用 find_first_of也没用啊!!!
  
  所以,最好的处理方式,就是将这3位放在最前面,在输出时,再用substr函数处理一下
  
----------------关于这题,更进一步的思考:----------------
  后来突然想到一个有意思的问题,如果这道题,我连宿舍号的位数相同都不保证了,比如说,从 1~1000,这样你用 substr,也不一定就是截取3位嘛...那此时该怎么办呢?
  
  我现在想到的就是,还是把宿舍号放前面,名字放后面,来一个循环:
*/
string s; //s = num + name; 
int pos;
for (pos = 0; pos <(int)s.size() && isdigit(s[pos]); pos++);
//这样最终得到的pos,就是名字的起始位置了,pos的前一个位置,就是宿舍号的终止位置了

/*
  我觉得这题特别巧妙的地方,也就是对串的处理了
  
  另外...
  
----------------列举一下这题可能用到的相关函数----------------
string::size() //注意返回值为 size_t,严格说来,用前需要强制转换为int,有时不转也不会错,但是最好还是转
string::substr() //截取字串
stringstream::.str()函数 //将stringstream类转化为string类
to_string() //[ http://www.cplusplus.com/reference/string/to_string/ ]
list::remove() //删除list中的指定元素
list::erase() //删除迭代器内的元素值
list::sort() //排序



----------------查阅资料后,觉得应该注意的细节----------------
1. 来自  c++ 字符串流 sstream(常用于格式转换) [ http://blog.csdn.net/xiaogugood/article/details/21447431 ]

在多次转换中重复使用同一个stringstream(而不是每次都创建一个新的对象)对象最大的好处在于效率。stringstream对象的构造和析构函数通常是非常耗费CPU时间的。

//这个在 ACM 里就有体验过了,string 和 stringstream 真的是很慢的,虽然说 STL 好像都或多或少有性能瓶颈

2. stream 的清空,并不是用 clear(),上篇文章说是用clear(),但我亲自测验过了,用clear()没用,而是应该用
ss.str("");
详见:[ http://blog.csdn.net/chenlei0630/article/details/39643887 ]

摘录:
clear() 方法只是重置了stringstream的状态标志,并没有清空数据。如果需要清空数据,可以用s1.str(“”)来实现这个目的。
谨记!不然很容易使你的程序出现错误,并且吃掉你的内存!
*/
//用sstream
#include <iostream>
#include <list>
#include <string>
#include <sstream>
#define rep(i, n) for ( int i = 0; i < (n); i++ )
using namespace std;
int n; // num of dorms
int t; // num of commans 

void solve ()
{
	list<int> free;
	list<string> used;
	list<int>::iterator it1;
	list<string>::iterator it2;
	string s;
	stringstream ss;
	int num;
	int first; // if it is the first element to be output
	cin >> n;
	
	for (int i = 101; i <= 120; i++) free.push_back(i);
	
	rep(i, n)
	{
		cin >> s >> num;
		free.remove(num);
	//	ss.clear();
		ss.str("");
		ss << num;
		string tp = ss.str() + s;
	//	cout << tp << endl;
		used.push_back( tp );
	}
	
	cin >> t;
	rep(i, t)
	{
		cin >> s;
		if ( s[0] == 'a' )
		{
			cin >> s;
		//	cout << "why WA?" << s << endl;
			num = free.front();
			free.pop_front();
			
			ss.str("");
		//	ss.clear(); //不知道为什么,明明用了 clear() 以后,下一行仍然有输出 
		//	cout << "wrong there? " << ss.str() << endl;
			ss << num;
			string tp = ss.str() + s;
		//	cout << tp << endl;
			used.push_back( tp );
		}
		else if ( s[0] == 'r' )
		{
			cin >> num;
		//	ss.clear();
			ss.str("");
			ss << num;
			
		//	cout << "wrong there? " << ss.str() << endl;
			string tp = ss.str();
			for ( it2 =  used.begin(); it2 != used.end(); it2++ )
			{
				if ( (*it2).substr(0, 3) == tp )
				{
					used.erase(it2);
					break;
				}
			}
			free.push_back(num);
		}
		else if ( s == "display_free" )
		{
			first = 1;
			for ( it1 = free.begin(); it1 != free.end(); it1++ )
			{
				if ( first ) first = 0;
				else cout << "-";
				cout << (*it1);
			}
			cout << endl;
		}
		else
		{
			used.sort();
			first = 1;
			for ( it2 = used.begin(); it2 != used.end(); it2++ )
			{
				if ( first ) first = 0;
				else cout << "-";
				cout << (*it2).substr(3) << "(" << (*it2).substr(0, 3) << ")";
			}
			cout << endl;
		}
	}
	
}

int main ()
{
	solve();
	return 0;
}

//不用 stream,用 to_string 函数:
/*
  说明:
  学校的oj用不了 C++11的语法特性,所以这个写法,只是理论可行,没真正在oj上判过
  
  查阅过的相关资料:
  http://bbs.csdn.net/topics/392033713
  https://stackoverflow.com/questions/15569179/to-string-not-declared-in-scope
  http://blog.csdn.net/qiqi123i/article/details/53150837
  http://blog.csdn.net/qiqi123i/article/details/61912466
*/
#include <iostream>
#include <list>
#include <string>
#define rep(i, n) for ( int i = 0; i < (n); i++ )
using namespace std;
int n; // num of dorms
int t; // num of commans 

void solve ()
{
	list<int> free;
	list<string> used;
	list<int>::iterator it1;
	list<string>::iterator it2;
	string s;
	int num;
	int first; // if it is the first element to be output
	cin >> n;
	
	for (int i = 101; i <= 120; i++) free.push_back(i);
	
	rep(i, n)
	{
		cin >> s >> num;
		free.remove(num);
		string tp = to_string(num) + s;
		used.push_back( tp );
	}
	
	cin >> t;
	rep(i, t)
	{
		cin >> s;
		if ( s[0] == 'a' )
		{
			cin >> s;
			num = free.front();
			free.pop_front();
			
			string tp = to_string(num) + s;
			used.push_back( tp );
		}
		else if ( s[0] == 'r' )
		{
			cin >> num;

			string tp = to_string(num);
			for ( it2 =  used.begin(); it2 != used.end(); it2++ )
			{
				if ( (*it2).substr(0, 3) == tp )
				{
					used.erase(it2);
					break;
				}
			}
			free.push_back(num);
		}
		else if ( s == "display_free" )
		{
			first = 1;
			for ( it1 = free.begin(); it1 != free.end(); it1++ )
			{
				if ( first ) first = 0;
				else cout << "-";
				cout << (*it1);
			}
			cout << endl;
		}
		else
		{
			used.sort();
			first = 1;
			for ( it2 = used.begin(); it2 != used.end(); it2++ )
			{
				if ( first ) first = 0;
				else cout << "-";
				cout << (*it2).substr(3) << "(" << (*it2).substr(0, 3) << ")";
			}
			cout << endl;
		}
	}
}

int main ()
{
	solve();
	return 0;
}





  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值