咕咕东的目录管理器 || 复杂模拟题 Kattis - directorymanagement

本文详细介绍了一个高效目录管理器的设计与实现过程,包括如何处理MKDIR、RM等命令,以及如何实现复杂的UNDO功能。文章深入探讨了数据结构的选择和优化,如使用map和vector来维护目录树,并提供了完整的代码示例。

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

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

目录管理器可以理解为要维护一棵有根树结构,每个目录的儿子必须保持字典序。
在这里插入图片描述

在这里插入图片描述

输入

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

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

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

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

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

限制
Time limit 6000 ms

Memory limit 1048576 kB

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

解题思路
定义结构体command,Directory
考虑好undo这个操作
tree不能直接遍历,复杂度过高

代码实现

#include<string>
#include<cstring>
#include<map>
#include<iostream>
#include<vector>
using namespace std;

char tmps[30];

struct command;

struct Directory{
	string name;  //目录名字 
	map<string , Directory*> children; 
	Directory* parent; 
	int subtreeSize;    //sz输出子树大小 
	
	vector<string> tenDescendants;
	bool updated;
	
	Directory(string na,Directory* par){
		this->name = na;
		this->parent = par;
		this->subtreeSize = 1;
	}
public:
	bool addChild(Directory* ch)
	{
		if(children.find(ch->name) != children.end()) return 0;
		children[ch->name] = ch;
		maintain(+ch->subtreeSize);
		return 1;
	}
	
	Directory* getChild(string na) //获得儿子 
	{
		auto it = children.find(na);
		if(it == children.end()) return nullptr;
		return it->second;
	}
	
	Directory* mkdir(string na) //创建 
	{
		if(children.find(na) != children.end()) //如果已经存在 
		return nullptr;
		Directory* ch = new Directory(na,this);
		children[na] = ch;
		maintain(1);
		return ch;
	}
	
	Directory* rm(string na) //删除 
	{
		auto it = children.find(na);
		if(it == children.end())
		return nullptr;
		maintain(-1 * it->second->subtreeSize);
		children.erase(it);
		return it->second;
	}
	
	Directory* cd(string na)
	{
		if(".."==na)
		return this->parent;
		return getChild(na);
	}
	
	void maintain(int del)
	{  //向上维护子树大小 
		updated = 1;
		subtreeSize +=del;
		if(parent!=nullptr) parent->maintain(del);
	}
	
	void sz(){
		cout<<this->subtreeSize<<endl;
	}
	
	void ls(){
		int sz = children.size();
		if(sz == 0) cout<<"EMPTY"<<endl;
		else if(sz<=10) 
		{
		  auto it=children.begin();
		  while(it!=children.end()) 
 			{ 
 				cout<<it->first<<endl;
 				it++; 
 			} 
		}
		
		else {
			auto it = children.begin();
			for(int i=0;i<5;i++,it++)
			cout<<it->first<<endl;
			cout<<"...\n"<<endl;
			
			it = children.end();
			for(int i=0;i<5;i++) it--;
			for(int i=0;i<5;i++,it++)

	     	 cout<<it->first<<endl; 
		}
	}

	void tree()
	{
		if(subtreeSize==1) cout<<"EMPTY"<<endl;
		else if(subtreeSize<=10) {  //如果不超过10个
			if(this->updated)
			{   
			    tenDescendants.clear();
				treeAll(&tenDescendants);
				this->updated = 0;
			}

			for(int i=0;i<subtreeSize;i++)
			cout<<tenDescendants[i]<<endl;

		}
		else {   //如果超过10个
			if(this->updated){
				tenDescendants.clear();
				treeFirst(5,&tenDescendants);
				treeLast(5,&tenDescendants);
				this->updated = 0;
			}
		
			for(int i=0;i<5;i++)
			cout<<tenDescendants[i]<<endl;
			
			cout<<"..."<<endl;
			for(int i=9;i>=5;i--)
			cout<<tenDescendants[i]<<endl;
		}
	}
	
private:
		void treeAll(vector<string>* bar)
		{
			bar->push_back(name);
			auto it=children.begin();
			while(it!=children.end())
			{
				it->second->treeAll(bar);
				it++;
			}
		}
		void treeFirst(int num,vector<string>* v)
		{
			v->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->treeFirst(num,v);
					return ;
				}
				else {
					it->second->treeFirst(sts,v);
					num-=sts;
				}
				it++;
			}
		}
		void treeLast(int num,vector<string>* v)
		{
			
			int n=children.size();
			auto it = children.end();
			while(n--)
			{
				it--;
				int sts = it->second->subtreeSize;
				
				if(sts >= num)
				{
					it->second->treeLast(num,v);
					return ;
				}
				else
				{
					it->second->treeLast(sts,v);
					num-=sts;
				}
			}
				v->push_back(name);
		}
};


struct command{
	int type; //命令的类型
	string arg; //命令的参数
	Directory* tmpDir; //刚刚目录
	const string CMD_NAMES[7]={"MKDIR","RM","CD","SZ","LS","TREE","UNDO"};
	command(string s)
	{
		for(int i=0;i<7;i++) if(CMD_NAMES[i]==s){
			this->type = i;
			if(i<3) {
			cin>>tmps;
			arg = tmps;}
			return;
		} 
	} 
};



void slove()
{
	int n;cin>>n;
	Directory* now = new Directory("root",nullptr);
	vector<command*> cmdList;
	while(n--)
	{
		cin>>tmps;
	
		command* cmd = new command(tmps);
		switch(cmd->type){
			case 0: {
				cmd->tmpDir=now->mkdir(cmd->arg);
				if(cmd->tmpDir==nullptr) cout<<"ERR"<<endl;
				else{
				cout<<"OK"<<endl;
				cmdList.push_back(cmd);
			}
			break;
			}
			
			case 1:	{
			cmd->tmpDir=now->rm(cmd->arg);
			if(cmd->tmpDir==nullptr) cout<<"ERR"<<endl;
			else{
				cout<<"OK"<<endl;
				cmdList.push_back(cmd);
			}
			break;
			}
			
			case 2:	{
			Directory* ch = now->cd(cmd->arg);
			if(ch == nullptr) cout<<"ERR"<<endl;
			else{
				cout<<"OK"<<endl;
				cmd->tmpDir= 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=0;
				while(!success && !cmdList.empty())
				{
					cmd=cmdList.back();
					cmdList.pop_back();
					switch(cmd->type)
					{
						case 0:{
						Directory* a = now->rm(cmd->arg);
						if(a!=nullptr)
						success = 1;
						
						break;
						}
						case 1:{
						success = now->addChild(cmd->tmpDir);	break;
						}
						case 2:{
						now=cmd->tmpDir; success=1;	break;
						}
					}
				}
		
				if(success) cout<<"OK"<<endl;
				else cout<<"ERR"<<endl;
				}
		}
	}
}

int main()
{
	ios::sync_with_stdio(0);
	int T;
	cin>>T;
	while(T--) {slove(); cout<<endl; }
	return 0;
}

小结
题目很复杂,所以要先考虑全局,在一步步来实现。
不能直接一上来就一个一个的实现功能,因为如果不先考虑undo,那么后面改起来就很难。
tree 要注意复杂度 ,直接遍历会超时

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值