week9-A(咕咕东的目录管理器)

题意

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

样例输入
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
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

思路

  • 首先我们应该去思考我们需要进行怎样的操作,这些操作之间有无关联,可不可以进行封装,使用面向对象进行解决这个问题,题目中明显的看出这是一个树的结构,操作对应着树的动态创建和删除等操作;
  • 我们发现几乎全部的操作都是单独的对树进行操作,我们就可以创建一个树的类,然后将操作封装,其次就是应该定义树的结点结构,以及我们发现undo操作等,需要对上一个命令进行恢复操作,那么我们还需要保存命令,那么,命令依旧不能是一个单独的变量,我们同样将命令进行封装为一个结构体。
  • 对于MKDIR操作,创建子目录,本质上就是创建子节点,我们对于每一个结点与其子节点使用map数组进行一个映射,方便直接通过迭代器进行查询,以及删除;所以对于创建结点就只是map[name]=child,然后要进行其父节点子树规模的更新。
  • 对于RM操作,就是通过迭代器进行一个结点的删除 ,mp.erase(it);
  • 对于CD操作,首先要进行判断是不是返回当前目录,是的话,返回其FA结点,如果不是,返回其child结点;
  • 对于SZ操作,就是输入其子树的规模;
  • 对于LS操作,需要进行分层操作,根据子目录的多少,如果是0,那么就是“EMPTY",如果小于10 ,则直接通过迭代器进行mp的输出,如果大于10,那么就先使用迭代器输出前五个,然后将迭代器直接以到末位,然后末尾向前先偏移5个,然后向后输入后五个;
  • 对于tree操作,还是进行分层操作,对于子目录小于十个的,直接一个一个输出即可,对于大于10个,我们需要考虑进行前五个的操作和后五个目录的操作,分别使用两个递归函数进行解决即可,此题由于数据范围比较大,那我们如果对于tree操作每次进行便利的话,肯定会超时,那么此时我们记录目录即可,如果没有更新直接读取即可,此处的记忆性体现在RM操作中的记录。
  • 对于UNDO操作,我们之前就在命令结构体中,记录了当前操作结点,其次我们需要一个vector数组记录每一个命令,以明确命令的先后关系。还有一点就是UNDO操作只是会针对MKDIR\RM\CD操作,那么我们就需要记住MIKDIR创建的结点,RM删除的结点,然后进行相应的处理即可。

总结

此题对于我来说,就是一个复杂问题的对象化,充分使用面向对象进行解决问题,将方法全部进行封装,有利于维护,具有整体性;
然后就是解决此题的一个层次化问题,要考虑全面,到底这个结构能不能进行使用,使用了对于后面的操作有没有不便利之处,要进行全局考虑。

代码

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<map>
using namespace std;
struct Directory
{

	string name;            //当前目录名称
	map<string, Directory*> mp;    //所有后代建立名称的映射
	Directory* fa;    //父目录
	int subtreesize;   //子树规模
	bool updated;
	vector<string> tenChild;    //保存节点的十个后代
	Directory(string name, Directory* fa)
	{
		this->name = name;
		this->fa = fa;
		this->subtreesize = 1;
	}
public:
	Directory* getChild(string name);//获得字目录
	Directory* mkdir(string name);  //创建新目录
	Directory* rm(string name);
	Directory* cd(string name);
	bool addChild(Directory* ch);
	void maintain(int x);//更新之前的子树大小
	void sz();
	void ls();
	void tree();
private:
	void treeAll(vector<string>* bar);//后代加入桶
	void treefirst(int num, vector<string>* bar);//前序
	void treelast(int num, vector<string>* bar);//后序
};
struct Command {
	const string CMDNAMES[7] = { "MKDIR","RM","CD","SZ","LS","TREE","UNDO" };
	int type;      //命令类型
	string arg;  //命令参数
	Command(string s)
	{
		for (int i = 0; i < 7; i++)
			if (CMDNAMES[i] == s)
			{
				type = i;
				string temps;
				if (i < 3) {
					cin >> temps;
					arg = temps;
				}
				return;
			}
	}
	Directory* temp;//记录刚刚操作的目录,以防UNDO
};
Directory* Directory::getChild(string name)
{
	map<string, Directory*>::iterator it = mp.find(name);
	if(it==mp.end())
	    return nullptr;
	return it->second;
}
Directory* Directory::mkdir(string name)
{
	if(mp.find(name)!=mp.end())//若当前目录下已有该目录
		return nullptr;
	Directory* child = new Directory(name, this);
	mp[name] = child;
	maintain(1);//更新之前的子树
	return child;
}

Directory* Directory::rm(string name)
{
	map<string, Directory*>::iterator it = mp.find(name);
	if(it==mp.end())//如果不存在该目录
		return nullptr;
	maintain(-1 * it->second->subtreesize);//删除子目录以及其子树
	mp.erase(it);//删除子目录

	return it->second;//返回子目录的下一个兄弟目录
}

Directory* Directory::cd(string name)
{
	if ( name=="..")//返回上级目录
		return this->fa;
	return  getChild(name);
}

bool Directory::addChild(Directory* ch)
{
	if(mp.find(ch->name)!=mp.end())//如果存在该字目录
		return false;
	mp[ch->name] = ch;
	maintain(+ch->subtreesize);
	return true;
}

void Directory::maintain(int x)//维护向上的sz
{
	updated = true;
	subtreesize = subtreesize + x;
	if (fa != nullptr)
		fa->maintain(x);
}

void Directory::sz()//返沪子目录的规模
{
	cout<<subtreesize<<endl;
}

void Directory::ls()
{
	int s = mp.size();
	if (s == 0)
		cout<<"EMPTY"<<endl;
	else if (s <= 10)
	{
		map<string, Directory*>::iterator it = mp.begin();
		for (; it != mp.end(); it++)
			cout<<it->first<<endl;
	}
	else
	{
		map<string, Directory*>::iterator it = mp.begin();
		for (int i = 0; i < 5; i++, it++)
			cout<<it->first<<endl;
		cout<<"..."<<endl;
		it = mp.end();
		for (int i = 0; i < 5; i++) it--;
		for(int i=0;i<5;i++,it++) 
			cout<<it->first<<endl;
	}
}

void Directory::tree()
{
	if (subtreesize == 1)
		cout<<"EMPTY"<<endl;
	else if (subtreesize <= 10)
	{
		if (this->updated)
		{
			
			tenChild.clear();
			treeAll(&tenChild);
			this->updated = false;
		}
		for (int i = 0; i < subtreesize; i++)
			cout<<tenChild.at(i)<<endl;

	}
	else
	{
		if (this->updated)
		{
			tenChild.clear();
			treefirst(5, &tenChild);
			treelast(5, &tenChild);
			this->updated = false;
		}
		for (int i = 0; i < 5; i++)
			cout<<tenChild.at(i)<<endl;
		cout<<"..."<<endl;
		for(int i=9;i>=5;i--)
			cout<<tenChild.at(i)<<endl;
	}
}

void Directory::treeAll(vector<string>* bar)
{//更新全桶
	bar->push_back(name);
	map<string, Directory*>::iterator it = mp.begin();
	for (; it != mp.end(); it++)
		it->second->treeAll(bar);
}

void Directory::treefirst(int num, vector<string>*bar)
{
	bar->push_back(name);
	if (--num == 0) return;
	int n = mp.size();
	map<string, Directory*>::iterator it = mp.begin();
	while (n--)
	{
		int sz1 = it->second->subtreesize;
		if (sz1 >= num)
		{
			it->second->treefirst(num, bar);
			return;
		}
		else
		{
			it->second->treefirst(sz1, bar);
			num = num - sz1;
		}
		it++;
	}
}

void Directory::treelast(int num, vector<string>* bar)
{
	int n = mp.size();
	map<string, Directory*>::iterator it = mp.end();
	while (n--)
	{
		it--;
		int sz1 = it->second->subtreesize;
		if (sz1 >= num)
		{
			it->second->treelast(num, bar);
			return;
		}
		else	
		{
			it->second->treelast(sz1, bar);
			num = num - sz1;
		}
		
	}
	bar->push_back(name);
}

void solve()
{
	int n;
	cin>>n;//操作命令条数
	Directory* now = new Directory("root", NULL);//当前目录
	vector<Command*> cmdList;//为UNDO做准备
	for(int i=0;i<n;i++)
	{
		string temps;//命令
		cin >> temps;
		Command* cmd = new Command(temps);
		switch (cmd->type)
		{
		case 0: 
			    cmd->temp= now->mkdir(cmd->arg);
				if (cmd->temp == NULL)
					cout<<"ERR"<<endl;
				else
				{
					cout<<"OK"<<endl;
					cmdList.push_back(cmd);
				}
			    break;//MKDIR
		case 1: 
				cmd->temp = now->rm(cmd->arg);
				if (cmd->temp == NULL)
					cout<<"ERR"<<endl;
				else
				{
					cout<<"OK"<<endl;
					cmdList.push_back(cmd);
				}
				break;//RM
		case 2: {
			Directory* ch = now->cd(cmd->arg);
			if (ch == NULL)
				cout<<"ERR"<<endl;
			else
			{
				cout<<"OK"<<endl;
				cmd->temp = now;
				now = ch;
				cmdList.push_back(cmd);
			}
			break;  //CD
		}
		case 3: now->sz(); break;        //SZ
		case 4: now->ls(); break;        //LS
		case 5: now->tree(); break;      //TREE
		case 6: {
			bool success = false;
			while (!success && !cmdList.empty())
			{
				cmd = cmdList.back();
				cmdList.pop_back();
				switch (cmd->type)
				{
				case 0: {Directory *tempp= now->rm(cmd->arg); if(tempp!=NULL) success=true;break; }//UNDO MAKDIR
				case 1: success = now->addChild(cmd->temp); break;//UNDO rm;
				case 2: now = cmd->temp; success = true; break; //UNDO CD
				}
			}
			if (success)
				cout<<"OK"<<endl;
			else
				cout<<"ERR"<<endl;
			break;
		}
		}
	}
}
int main()
{ 
	int T;
	cin >> T;
	for (int i = 0; i < T; i++)
	{
		solve();
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值