Week 9 咕咕东的目录管理器

题目描述

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

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

目录管理器可以理解为要维护一棵有根树结构,每个目录的儿子必须保持字典序。
在这里插入图片描述
现在咕咕东可以在命令行下执行以下表格中描述的命令:

命令类型实现说明
MKDIR s操作在当前目录下创建一个子目录 s,s 是一个字符串创建成功输出 “OK”;若当前目录下已有该子目录则输出 “ERR”
RM s操作在当前目录下删除子目录 s,s 是一个字符串删除成功输出 “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)的影响,撤销成功输出 “OK” 失败或者没有操作用于撤销则输出 “ERR”

样例

Input

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

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

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

Output

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

时空限制

Time limit 6000 ms
Memory limit 1048576 kB

样例输入

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

样例输出

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

思路

对于一条指令,采用结构体类型,其中包括指令类型、指令操作的文件名(如果有需要操作的文件),一个容器用来记录这条指令涉及的目录节点

对于目录中的每个节点,采用结构体记录节点的名字、孩子、父节点、子树大小以及对于该节点进行操作的各种函数

在具体实现每个指令时,需要有一个执行对象now,根据输入的指令和数据找到当前now的值

在实现每个函数时,需要设计返回值以确定该条指令是否成功执行,同时,对于UNDO函数的实现,需要对上一次操作进行撤销,所以需要将成功执行的指令存储起来,以备UNDO指令

对于实现TREE函数,需要进行前序遍历和后序遍历,为了防止超时,使用容器tenDescendants存储满足要求的节点,使用updated判断容器是否需要进行更新,如果没有更新,即可直接输出,如果更新了,那么对tenDescendants进行更新后,再输出,这种方法可以有效的防止多次TREE操作时需要进行多次遍历的情况

总结

在c++关闭同步时,cin和scanf不能同时使用😢wa了好几次都没发现错误

代码

#include <iostream>
#include <stdio.h> 
#include <algorithm>
#include <map>
#include <string>
#include <vector>

using namespace std;

char tmps[20];//声明一个辅助输入的字符串组 

struct Directory
{
	string name;//当前目录的名字
	map<string,Directory*> children;//用指针避免复制构造造成的浪费内存
	Directory* parent;//以备"CD..."要返回上级目录
	int subtreeSize;//以备"sz"要输出子树的大小
	vector<string>* tenDescendants;//保存当前节点的十个后代 
	bool updated;//记录当前节点的子孙有无变动,无变动则是十个代无需更新 
	Directory(string name,Directory* parent)
	{
		this->name=name;
		this->parent=parent;
		this->subtreeSize=1;
		this->tenDescendants=new vector<string>; 
	}
	
public:
	
	void maintain(int delta)
	{
		updated=true;
		subtreeSize+=delta;
		if(parent!=nullptr)
		{
			parent->maintain(delta);
		}
	}
	
	void tree()
	{
		if(subtreeSize==1) printf("EMPTY\n");
		else if(subtreeSize<=10)
		{
			if(this->updated)
			{
				tenDescendants->clear();
				treeAll(tenDescendants);
				this->updated=false;
			}
			
			for(int i=0;i<subtreeSize;i++)
			{
				printf("%s\n",tenDescendants->at(i).c_str());
			}
		}
		else
		{
			if(this->updated)
			{
				tenDescendants->clear();
				treeFirstSome(5,tenDescendants);
				treeLastSome(5,tenDescendants);
				this->updated=false;
			}
			
			for(int i=0;i<5;i++)
			{
				printf("%s\n",tenDescendants->at(i).c_str());
			}
			printf("...\n");
			for(int i=9;i>=5;i--)
			{
				printf("%s\n",tenDescendants->at(i).c_str());
			}
		}		
	}	
	
	Directory* getChild(string name)
	{
		auto it=children.find(name);
		if(it==children.end()) return nullptr;
		return it->second;
	}
	
	Directory* mkdir(string name)
	{
		if(children.find(name)!=children.end()) return nullptr;
		Directory* ch=new Directory(name,this);
		children[name]=ch;
		maintain(+1);
		return ch;
	}
	
	Directory* rm(string name)
	{
		auto it=children.find(name);
		if(it==children.end()) return nullptr;
		maintain(-1 * it->second->subtreeSize);
		children.erase(it);
		return it->second;
	}
	
	Directory* cd(string name)
	{
		if(".."==name)
		{
			return this->parent;
		} 
		return getChild(name);
	}
	
	bool addChild(Directory* ch)
	{
		if(children.find(ch->name)!=children.end())
			return false;
		children[ch->name]=ch;
		maintain(+ch->subtreeSize);
		return true;
	}
	
	void sz()
	{
		printf("%d\n",this->subtreeSize);
	}
	
	void ls()
	{
		int sz=children.size();
		if(sz==0) printf("EMPTY\n");
		else if(sz<=10)
			for(auto& entry:children)
				printf("%s\n",entry.first.c_str());
		else
		{
			auto it=children.begin();
			for(int i=0;i<5;i++,it++)
			{
				printf("%s\n",it->first.c_str());
			}
			printf("...\n");
			it=children.end();
			for(int i=0;i<5;i++) it--;
			for(int i=0;i<5;i++,it++)
				printf("%s\n",it->first.c_str());
		}
	}
	
private:
	void treeAll(vector<string>* bar)
	{
		bar->push_back(name);
		for(auto &entry:children)
			entry.second->treeAll(bar);
	}
	
	void treeFirstSome(int num,vector<string>* bar)
	{
		bar->push_back(name);
		if(--num==0) return;
		int n=children.size();
		auto it=children.begin();
		while(n--)
		{
			int sts=it->second->subtreeSize;
			if(sts>=num)
			{
				it->second->treeFirstSome(num,bar);
				return;
			}
			else
			{
				it->second->treeFirstSome(sts,bar);
				num-=sts;
			}
			it++;
		}
	}
	
	void treeLastSome(int num,vector<string>* bar)
	{
		int n=children.size();
		auto it=children.end();
		while(n--)
		{
			it--;
			int sts=it->second->subtreeSize;
			if(sts>=num)
			{
				it->second->treeLastSome(num,bar);
				return;
			}
			else
			{
				it->second->treeLastSome(sts,bar);
				num-=sts;
			}
		}
		bar->push_back(name);
	} 	
};

struct Command
{
	int type;
	string arg;
	const string CMDNAMES[7]={"MKDIR","RM","CD","SZ","LS","TREE","UNDO"};
	Command(string s)
	{
		for(int i=0;i<7;i++)
		{
			if(CMDNAMES[i]==s)
			{
				type=i;
				if(i<3) 
				{
					scanf("%s",tmps),arg=tmps;
				}
				return;
			}
		}
	}
	Directory* tempDir;
};

void solve()
{
	int n;
	cin>>n;
	Directory *now=new Directory("root",nullptr);
	vector<Command*>cmdList;
	while(n--)
	{
		scanf("%s",tmps);
		Command* cmd=new Command(tmps);
		switch(cmd->type)
		{
			case 0:
			{
				cmd->tempDir=now->mkdir(cmd->arg);
				if(cmd->tempDir==nullptr) printf("ERR\n");
				else
				{
					printf("OK\n");
					cmdList.push_back(cmd);
				}
				break;
			}
			case 1:
			{
				cmd->tempDir=now->rm(cmd->arg);
				if(cmd->tempDir==nullptr) printf("ERR\n");
				else
				{
					printf("OK\n");
					cmdList.push_back(cmd);
				}
				break;
			}
			case 2:
			{
				Directory * ch=now->cd(cmd->arg);
				if(ch==nullptr) printf("ERR\n");
				else
				{
					printf("OK\n");
					cmd->tempDir=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->addChild(cmd->tempDir); 
							break;
						case 2:
							now=cmd->tempDir; 
							success=true; 
							break;
					}
				}
				printf(success ? "OK\n":"ERR\n");
			}
		}
	}
	printf("\n");
}

int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		solve();
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yySakura

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值