程序设计思维与实践 Week9 作业 A-咕咕东的目录管理器

题目链接:A-咕咕东的目录管理器

题目描述:
咕咕东的雪梨电脑的操作系统在上个月受到宇宙射线的影响,时不时发生故障,他受不了了,想要写一个高效易用零bug的操作系统 —— 这工程量太大了,所以他定了一个小目标,从实现一个目录管理器开始。前些日子,东东的电脑终于因为过度收到宇宙射线的影响而宕机,无法写代码。他的好友TT正忙着在B站看猫片,另一位好友瑞神正忙着打守望先锋。现在只有你能帮助东东!
初始时,咕咕东的硬盘是空的,命令行的当前目录为根目录 root。
目录管理器可以理解为要维护一棵有根树结构,每个目录的儿子必须保持字典序。
现在咕咕东可以在命令行下执行以下表格中描述的命令:
在这里插入图片描述
Input:
输入文件包含多组测试数据,第一行输入一个整数表示测试数据的组数 T (T <= 20);
每组测试数据的第一行输入一个整数表示该组测试数据的命令总数 Q (Q <= 1e5);
每组测试数据的 2 ~ Q+1 行为具体的操作 (MKDIR、RM 操作总数不超过 5000);

Output:
每组测试数据的输出结果间需要输出一行空行。注意大小写敏感。

Sample Input:
1
22
MKDIR dira
CD dirb
CD dira
MKDIR a
MKDIR b
MKDIR c
CD …
MKDIR dirb
CD dirb
MKDIR x
CD …
MKDIR dirc
CD dirc
MKDIR y
CD …
SZ
LS
TREE
RM dira
TREE
UNDO
TREE

Sample Output:
OK
ERR
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
9
dira
dirb
dirc
root
dira
a
b
c
dirb
x
dirc
y
OK
root
dirb
x
dirc
y
OK
root
dira
a
b
c
dirb
x
dirc
y

Hint:
面对数据范围你要思考的是他们代表的 “命令” 执行的最大可接受复杂度,只有这样你才能知道你需要设计的是怎样复杂度的系统。

思路:
构造两个结构体,一个储存目录信息,另一个储存命令信息,同时用一个字符串数组存放使用的命令名,使用map存储边,undo前一个命令是cd,直接用命令存储的数组得到答案;如果是rm,就恢复map;mkdir就去掉map;对于tree,可以采用记录更新的方法,如果一个结构体内被标记为没有更新,就要对其进行更新;如果标记为更新,就可以直接拿来用,把要求的信息放进一个数组中,直接输出。

总结:
复杂的模拟题,做起来的感觉有点像数据结构课设了,通过课上的讲解和学长的解法代码总算弄出来了,但是如果直接看到这个题,整个人就交代了。

代码:

#include <iostream>
#include <cstring>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn=1e5+10;
string s;
int T,Q,op,cnt,current;
vector<pair<string,pair<int,int>>> v;	
const string cmdname[]={"MKDIR","RM","CD","SZ","LS","TREE","UNDO" };
struct command{
	string name,arg;
	int type;
	void initialize(string str){
		name=str;
		for(int i=0;i<7;i++)
			if(str==cmdname[i]){
				type=i;
				if(i<3)
					cin>>arg;
				break;
			}
	}
}cmd;
struct directory{
	string name;
	map<string,int> mp;
	int fa,sz;
	vector<string> pre,bck;
	bool tag;
	void initialize(string s, int p){
		tag=0,fa=p,sz=1,name=s;
		pre.clear(),bck.clear(),mp.clear();
	}
}node[maxn];
void update(int x,int num){
	while(x!=-1){
		node[x].tag=0;
		node[x].sz+=num;
		x=node[x].fa;
	}
}
void makenode(string s,int p) {
	node[++cnt].initialize(s,p);
	node[p].mp[s]=cnt;
}
void mkdir(){
	if(node[current].mp.count(cmd.arg)){
		cout<<"ERR"<<endl;
		return;
	}
	makenode(cmd.arg,current);
	v.push_back(make_pair("MKDIR",make_pair(current,cnt)));
	update(current,1);
	cout<<"OK"<<endl;
}
void rm() {
	if(!node[current].mp.count(cmd.arg)){
		cout<<"ERR"<<endl;
		return;
	}
	int u=node[current].mp[cmd.arg];
	update(current,-node[u].sz);
	v.push_back(make_pair("RM", make_pair(current,u)));
	node[current].mp.erase(node[u].name);
	cout<<"OK"<<endl;
}
void cd(){
	if(cmd.arg==".."){
		if(node[current].fa==-1){
			cout<<"ERR"<<endl;
			return;
		}
		v.push_back(make_pair("CD",make_pair(current,node[current].fa)));
		current=node[current].fa;
		cout<<"OK"<<endl;
		return;
	}
	if(!node[current].mp.count(cmd.arg)){
		cout<<"ERR"<<endl;
		return;
	}
	int u = node[current].mp[cmd.arg];
	v.push_back(make_pair("CD",make_pair(current,u)));
	current = u;
	cout<<"OK"<<endl;
}
void sz(){
	cout<<node[current].sz<<endl;
}
void undo(){
	if(v.size()==0){
		cout<<"ERR"<<endl;
		return;
	}
	auto t=v[v.size()-1];
	v.pop_back();
	cout<<"OK"<<endl;
	int temp=current;
	if(t.first=="MKDIR"){
		cmd.name="RM";
		current=t.second.first;
		cmd.arg=node[t.second.second].name;
		int u=node[current].mp[cmd.arg];
		update(current,-node[u].sz);
		node[current].mp.erase(node[u].name);
		current=temp;
	}
	else if(t.first=="RM"){
		current=t.second.first;
		int u=t.second.second;
		update(current,node[u].sz);
		node[current].mp[node[u].name]=u;
		current=temp;
	}
	else current=t.second.first;
}
void ls(){
	int m=node[current].mp.size();
	if(m==0){
		cout<<"EMPTY"<<endl;
		return;
	}
	else if(m>=1&&m<=10){
		auto u=node[current].mp.begin();
		while(u!=node[current].mp.end()){
			cout<<u->first<<endl;
			u++;
		}
		return;
	}
	else if(m>10){
		auto u=node[current].mp.begin();
		for(int i=1;i<=5;i++){
			cout<<u->first<<endl;
			u++;
		}
		cout<< "..."<<endl;
		u=node[current].mp.end();
		for(int i=1;i<=5;i++)
			u--;
		for(int i=1;i<=5;i++){
			cout<<u->first<<endl;
			u++;
		}
	}
}
void pushdown(int x);
void pretrack(int x){
	node[x].pre.push_back(node[x].name);
	if(node[x].sz==1)
		return;
	if(node[x].sz<=10){
		for(auto i:node[x].mp){
			if(!node[i.second].tag)
				pushdown(i.second);
			node[x].pre.insert(node[x].pre.end(),node[i.second].pre.begin(),node[i.second].pre.end());
		}
		return;
	}
	int pos=1;
	for(auto i:node[x].mp){
		if(!node[i.second].tag)
			pushdown(i.second);
		for(auto j:node[i.second].pre){
			node[x].pre.push_back(j);
			pos++;
			if(pos>=5)
				break;
		}
		if(pos>=5)
			break;
	}
}
void bcktrack(int x) {
	auto it=node[x].mp.end();
	it--;
	int pos=0;
	for(;;it--){
		int u=it->second;
		if(!node[u].tag)
			pushdown(u);
		for(int i=node[u].bck.size()-1;i>=0;i--){
			node[x].bck.push_back(node[u].bck[i]);
			pos++;
			if(pos>=5){
				reverse(node[x].bck.begin(),node[x].bck.end());
				break;
			}
		}
		if(pos>=5)
			break;
		if (it==node[x].mp.begin())
			break;
	}
}
void pushdown(int id){
	node[id].pre.clear();
	node[id].bck.clear();
	pretrack(id);
	if(node[id].sz>10)
		bcktrack(id);
	else 
		node[id].bck=node[id].pre;
	node[id].tag=1;
}
void tree(){
	if(!node[current].tag)
	    pushdown(current);
	int m=node[current].sz;
	if(m==1)
		cout<<"EMPTY"<<endl;
	else if(m>1&&m<=10){
		for(int i=0;i<node[current].pre.size();i++)
			cout<<node[current].pre[i]<<endl;
	}
	else{
		for(int i=0;i<5;i++)
			cout<<node[current].pre[i]<<endl;
		cout<<"..."<<endl;
		for(int i=5;i>=1;i--)
			cout<<node[current].bck[node[current].bck.size()-i]<<endl;
	}
}
int main(){
	cin>>T;
	while(T--){
		cin>>Q;
		cnt=0,current=0;
	    v.clear();
	    node[0].initialize("root", -1);
		while(Q--){
		cin>>s;
		cmd.initialize(s);
		op=cmd.type;
		switch(op){
				case 0:{
					mkdir();
					break;
				}
				case 1:{
					rm();
					break;
				}
				case 2:{
					cd();
					break;
				}
				case 3:{
					sz();
					break;
				}
				case 4:{
					ls();
					break;
				}
				case 5:{
					tree();
					break;
				}
				case 6:{
					undo();
					break;
				}
			}
	    }
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值