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

题目描述:

咕咕东的雪梨电脑的操作系统在上个月受到宇宙射线的影响,时不时发生故障,他受不了了,想要写一个高效易用零bug的操作系统 —— 这工程量太大了,所以他定了一个小目标,从实现一个目录管理器开始。前些日子,东东的电脑终于因为过度收到宇宙射线的影响而宕机,无法写代码。他的好友TT正忙着在B站看猫片,另一位好友瑞神正忙着打守望先锋。现在只有你能帮助东东!

初始时,咕咕东的硬盘是空的,命令行的当前目录为根目录 root

目录管理器可以理解为要维护一棵有根树结构,每个目录的儿子必须保持字典序。

实现说明
MKDIR s在当前目录下创建一个子目录s,是一个字符串创建成功输出 "OK";若当前目录下已有该子目录则输出 "ERR"
RM s在当前目录下删除子目录 ss 是一个字符串删除成功输出 "OK";若当前目录下该子目录不存在则输出 "ERR"
CD s进入一个子目录 s,s 是一个字符串(执行后,当前目录可能会改变)进入成功输出 "OK";若当前目录下该子目录不存在则输出 "ERR"
特殊地,若 s 等于 ".." 则表示返回上级目录,同理,返回成功输出 “OK”,返回失败(当前目录已是根目录没有上级目录)则输出 “ERR”
SZ输出当前目录的大小也即输出 1+当前目录的子目录数
LS输出多行表示当前目录的 "直接子目录" 名若没有子目录,则输出 “EMPTY”;若子目录数属于 [1,10] 则全部输出;若子目录数大于 10,则输出前 5 个,再输出一行"…",输出后 5 个。
TREE输出多行表示以当前目录为根的子树的前序遍历结果若没有后代目录,则输出 “EMPTY”;若后代目录数+1(当前目录)属于 [1,10] 则全部输出;若后代目录数+1(当前目录)大于 10,则输出前 5 个,再输出一行 “…”,输出后 5 个。
UNDO撤销操作撤销最近一个 “成功执行” 的操作(即MKDIR或RM或CD)的影响,撤销成功输出 “YES” 失败或者没有操作用于撤销则输出 “ERR”

文末附英文题目

input:

输入文件包含多组测试数据,第一行输入一个整数表示测试数据的组数 T (T <= 20);

每组测试数据的第一行输入一个整数表示该组测试数据的命令总数 Q (Q <= 1e5);

每组测试数据的 2 ~ Q+1 行为具体的操作 (MKDIR、RM 操作总数不超过 5000);

output:

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

时空限制:

Time limit 6000 ms

Memory limit 1048576 kB

思路:

对于每条指令,设置一个结构体,来存储这条指令的各个信息:类型、操作的文件名s(若有)、以及一个容器用来记录这条操作涉及的目录节点。

对于每个节点,设置一个结构体,来存储这个节点的各个信息:当前节点的名字,父节点,子节点的map映射,以该节点为根的子树的大小。以及各种封装的函数。

对于每组数据,新建一个根节点now,然后根据输入的每条指令修改now节点的位置。

由于具有undo操作,需要记录每条成功执行的指令,开设容器cmdlist来存储执行成功的指令。因此在undo时,每次从容器尾部弹出一个命令,对该命令执行撤销操作。

对于TREE指令,要进行前序和后序遍历,但是在未修改的情况下如果多次出现TREE操作,输出的内容是一样的,但却进行了多次的遍历,会导致超时,因此用容器ten来记录符合要求的节点,如果没有修改,则直接输出。如果修改了,则更新ten后再输出。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
char com[20],sec[20];
struct documents
{
	bool flag;
	string name;
	int child_size;
	documents* parent;
	vector<string> *ten;
	map<string,documents*>child;
	documents(string name,documents* parent)
	{
		this->name=name;
		this->parent=parent;
		this->child_size=1;
		this->ten=new vector<string>;
	}
public:
	documents* get_child(string name)
	{
		auto tmp=child.find(name);
		if(tmp==child.end())
			return nullptr;
		return tmp->second;
	}
	documents* mkdir(string name)
	{
		if(child.find(name)!=child.end())
			return nullptr;
		documents* ch=new documents(name,this);
		child[name]=ch;
		change(+1);
		return ch;
	}
	documents* rm(string name)
	{
		auto tmp=child.find(name);
		if(tmp==child.end())
			return nullptr;
		change(-1*tmp->second->child_size);
		child.erase(tmp);
		return tmp->second;
	}
	documents* cd(string name)
	{
		if(".."==name)
			return this->parent;
		return get_child(name);
	}
	bool add_child(documents* ch)
	{
		if(child.find(ch->name)!=child.end())
			return false;
		child[ch->name]=ch;
		change(+ch->child_size);
		return true;
	}
	void change(int delta)
	{
		flag=true;
		child_size+=delta;
		if(parent!=nullptr)
		parent->change(delta);
	}
	void sz()
	{
		printf("%d\n",this->child_size);
	}
	void ls()
	{
		int sz=child.size();
		if(sz==0) printf("EMPTY\n");
		else if(sz<=10) for(auto &entry:child) printf("%s\n",entry.first.c_str());
		else
		{
			auto tmp=child.begin();
			for(int i=0;i<5;i++,tmp++)
				printf("%s\n",tmp->first.c_str());
			printf("...\n");
			tmp=child.end();
			for(int i=0;i<5;i++) tmp--;
			for(int i=0;i<5;i++,tmp++)
			printf("%s\n",tmp->first.c_str());
		}
	}
	void tree()
	{
		if(child_size==1) printf("EMPTY\n");
		else if(child_size<=10)
		{
			if(this->flag)
			{
				ten->clear();
				ergodic(ten);
				this->flag=false;
			}
			for(int i=0;i<child_size;i++)
			printf("%s\n",ten->at(i).c_str());
		}
		else
		{
			if(this->flag)
			{
				ten->clear();
				tree_pre(5,ten);
				tree_last(5,ten);
				this->flag=false;
			}
			for(int i=0;i<5;i++)
			printf("%s\n",ten->at(i).c_str());
			printf("...\n");
			for(int i=9;i>=5;i--)
			printf("%s\n",ten->at(i).c_str());
		}
	}
private:
	void ergodic(vector<string> *bar)
	{
		bar->push_back(name);
		for(auto &entry:child)
		entry.second->ergodic(bar);
	}
	void tree_pre(int sum,vector<string> *bar)
	{
		bar->push_back(name);
		if(--sum==0) return;
		int n=child.size();
		auto tmp=child.begin();
		while(n--)
		{
			int st=tmp->second->child_size;
			if(st>=sum)
			{
				tmp->second->tree_pre(sum,bar);
				return;
			}
			else
			{
				tmp->second->tree_pre(st,bar);
				sum-=st;
			}
			tmp++;
		}
	}
	void tree_last(int sum,vector<string> *bar)
	{
		int n=child.size();
		auto tmp=child.end();
		while(n--)
		{
			tmp--;
			int st=tmp->second->child_size;
			if(st>=sum)
			{
				tmp->second->tree_last(sum,bar);
				return;
			}
			else
			{
				tmp->second->tree_last(st,bar);
				sum-=st;
			}
		}
		bar->push_back(name);
	}
};
struct command
{
	const string cmd_names[7]={"MKDIR","RM","CD","SZ","LS","TREE","UNDO"};
	int type;
	string arg;
	documents* tmp_dir;
	command(string s)
	{
		for(int i=0;i<7;i++)
		if(cmd_names[i]==s)
		{
			type=i;
			if(i<3)
			{
				scanf("%s",sec);
				arg=sec;
				return;
			}
		}
	}
};
int main()
{
	int T,n;
	cin>>T;
	while(T--)
	{
		documents *now=new documents("root",nullptr);
		vector<command*>cmdlist;
		cin>>n;
		for(int i=1;i<=n;i++)
		{
			scanf("%s",com);
			command* cmd=new command(com);
			documents* ch;
			switch(cmd->type)
			{
				case 0:
						cmd->tmp_dir=now->mkdir(cmd->arg);
						if(cmd->tmp_dir==nullptr) printf("ERR\n");
						else
						{
							printf("OK\n");
							cmdlist.push_back(cmd);
						}
						break;
				case 1:
						cmd->tmp_dir=now->rm(cmd->arg);
						if(cmd->tmp_dir==nullptr) printf("ERR\n");
						else
						{
							printf("OK\n");
							cmdlist.push_back(cmd);
						}
						break;
				case 2:
					{
						ch=now->cd(cmd->arg);
						if(ch==nullptr) printf("ERR\n");
						else
						{
							printf("OK\n");
							cmd->tmp_dir=now;
							now=ch;
							cmdlist.push_back(cmd);
						}
						break;
					}
				case 3:
						now->sz();break;
				case 4:
						now->ls();break;
				case 5:
						now->tree();break;
				case 6:
					{
						bool success=false;
						while(!success&&!cmdlist.empty())
						{
							cmd=cmdlist.back();
							cmdlist.pop_back();
							switch(cmd->type)
							{
								case 0:
									success=now->rm(cmd->arg)!=nullptr;break;
								case 1:
									success=now->add_child(cmd->tmp_dir);break;
								case 2:
									now=cmd->tmp_dir;success=true;break;
							}
						}
						if(success) printf("OK\n");
						else printf("ERR\n");
					}
			}
		}
		printf("\n");
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值