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

这篇博客介绍了一个基于Map的数据结构实现的目录管理系统,用于处理命令输入并支持撤销操作。在处理大量的TREE操作时,通过懒更新策略避免超时,确保在时间限制内完成任务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

样例输入

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

思路

咋一看这题有点懵,用什么数据结构存储?树?

因为在每个子目录下,使用字典序排序,因此可以使用map记录子目录。map的first存子目录的名字,second存目录类型的指针。

目录类型主要包括姓名、父亲目录的指针和目录的map。为方便操作还有treeSize,flag等元素。

同时,声明数据类型Command,对输入的指令进行操作(包括分析指令,存储参数等)。

目录中还包含了几乎涵盖题目要求的所有操作。其中,前三个操作并不是直接输出,而转移到了处理函数solve()中解决。因为这三个操作可能需要UNDO,因此不仅需要输出,还要返回UNDO必要的参数。

因为UNDO操作的需求,在删除子目录时只是将子目录从当前目录的map中摘除,而不将子目录中的内容清空。

另外,UNDO操作因为需要指令的信息,所以无法在Directory中声明操作,而直接在solve()中处理。

本题,最最关键的问题是时间限制和数据范围。命令总数1e5,也就是说TREE操作的数目极限情况下差不多要到1e5次,多组数据最多20组,显然如果每一次TREE操作都进行遍历的话会超时。

因此,采用懒更新的方法,在每次进行插入或删除操作时标记更新,然后在进行TREE操作时将答案存储。如果下次进行TREE操作没有更新,无需重新遍历,直接输出即可。

 

代码

#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
#include<map>
#include<vector>
#include<stack>
using namespace std;
string order;//辅助输入的字符串数组,指令名称

struct Directory//字典
{
	string name;//当前目录的名字
	map<string, Directory*> children;//子目录
	Directory* parent; //方便返回上一层目录
	int treeSize;//子树大小
	bool flag;//标记是否被更新过
	vector<string>* tenChild;
	Directory(string name, Directory* parent)
	{
		this->name = name;
		this->parent = parent;
		this->treeSize = 1;
		tenChild = new vector<string>;
		flag = true;
	}


public:
	Directory* mkdir(string name);
	Directory* rm(string name);
	Directory* cd(string name);
	void update(int num);
	bool addChild(Directory *child);
	void sz();
	void ls();
	void tree();

protected:
	void all(vector<string>* bar);
	void pre(int &num, vector<string>* bar);
	void post(int &num, vector<string>* bar);

};


struct Command
{
	const string cmdName[7]{ "MKDIR","RM","CD","SZ","LS","TREE","UNDO" };
	int type;//命令的类型
	string arg;//命令的参数
	Directory* last;
	Command(string s)
	{
		for (int i = 0; i < 7; i++)
		{
			if (cmdName[i] == s)
			{
				type = i;
				if (i < 3)
				{
					cin >> order;
					arg = order;
				}
			}
		}
	}
};



void Directory::update(int num)
{//更新每个字典的信息
	flag = true;
	treeSize += num;
	if (parent != nullptr)
		parent->update(num);
}


Directory* Directory::mkdir(string name)
{//创建子目录成功,返回子目录指针
	if (children.find(name) != children.end())//已经存在
		return nullptr;
	Directory *child = new Directory(name, this);
	children[name] = child;
	update(1);
	return child;
}

Directory* Directory::rm(string name)
{//删除成功,返回子目录指针
	map<string, Directory*>::iterator it = children.find(name);
	if (it == children.end())
		return nullptr;
	Directory* com = it->second;
	update(-1 * it->second->treeSize);
	children.erase(it);
	return com;
}

bool Directory::addChild(Directory* child)//增加子目录
{
	if (children.find(child->name) != children.end())//已经存在
		return false;
	children[child->name] = child;
	update(child->treeSize);
	return true;
}

void Directory::sz()
{
	cout << this->treeSize << endl;
}

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

Directory* Directory::cd(string name)
{
	if (name == "..")
		return parent;
	map<string, Directory*>::iterator it = children.find(name);
	if (it == children.end())
		return nullptr;
	else return it->second;
}

void Directory::tree()
{
	int size = this->treeSize;
	if (size == 1) cout << "EMPTY" << endl;
	else if (size <= 10)
	{
		if (flag)
		{
			tenChild->clear();
			all(tenChild);
			flag = false;
		}
		for (int i = 0; i < size; i++) cout << tenChild->at(i) << endl;
	}
	else
	{
		if (flag)
		{
			tenChild->clear();
			int num = 5;
			pre(num, tenChild);
			num = 5;
			post(num, tenChild);
			flag = 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::all(vector<string>* bar)
{
	bar->push_back(this->name);
	for (map<string, Directory*>::iterator it = children.begin();
		it != children.end(); it++)

		it->second->all(bar);

}

void Directory::pre(int &num, vector<string>* bar)
{
	if (num <= 0) return;
	bar->push_back(this->name);
	int size = this->treeSize;
	map<string, Directory*>::iterator it = children.begin();
	int sz = children.size();
	for (int i = 0; i < sz; i++, it++)
		it->second->pre(--num, bar);

}

void Directory::post(int &num, vector<string>* bar)
{
	int size = this->treeSize;
	map<string, Directory*>::iterator it = children.end();
	if (children.size() != 0)
	{
		it--;
		int sz = children.size();
		for (int i = 0; i < sz; i++, it--)
			it->second->post(num, bar);
	}
	if (num <= 0) return;
	bar->push_back(this->name);
	num--;
}


void solve()
{
	int Q;
	cin >> Q;
	Directory *now = new Directory("root", nullptr);
	stack<Command*> done; //存储成功执行的命令
	while (Q--)
	{
		cin >> order;
		Command *cmd = new Command(order);
		switch (cmd->type)
		{
		case 0://mkdir创建子目录
		{
			cmd->last = now->mkdir(cmd->arg);
			if (cmd->last == nullptr) cout << "ERR" << endl;
			else
			{
				cout << "OK" << endl;
				done.push(cmd);

			}
			break;
		}
		case 1://rm 删除子目录
		{
			//cout << "in" << endl;
			cmd->last = now->rm(cmd->arg);
			if (cmd->last == nullptr) cout << "ERR" << endl;
			else
			{
				cout << "OK" << endl;
				done.push(cmd);
			}
			break;
		}
		case 2://cd 进入目录
		{
			Directory* re = now->cd(cmd->arg);
			if (re == nullptr) cout << "ERR" << endl;
			else
			{
				cout << "OK" << endl;
				cmd->last = now;
				now = re;
				done.push(cmd);
			}
			break;
		}
		case 3:
		{
			now->sz();
			break;
		}
		case 4:
		{
			now->ls();
			break;
		}
		case 5:
		{
			now->tree();
			break;
		}
		case 6:
		{
			bool is = false;
			while (!is && !done.empty())
			{
				cmd = done.top();
				done.pop();
				if (cmd->type == 0)
				{
					if (now->rm(cmd->arg) != nullptr)
						is = true;
					break;
				}
				if (cmd->type == 1)
				{
					is = now->addChild(cmd->last);
					break;
				}
				else
				{
					now = cmd->last;
					is = true;
					break;
				}
			}
			if (!is) cout << "ERR" << endl;
			else cout << "OK" << endl;
			break;
		}
		}
	}
}


int main()
{
	int T;
	cin >> T;
	while (T--) solve();
	system("Pause");
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值