程序设计思维与实践 Week9 作业

题意:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
输入:

输入文件包含多组测试数据,第一行输入一个整数表示测试数据的组数 T (T <= 20);
每组测试数据的第一行输入一个整数表示该组测试数据的命令总数 Q (Q <= 1e5);
每组测试数据的 2 ~ Q+1 行为具体的操作 (MKDIR、RM 操作总数不超过 5000);
面对数据范围你要思考的是他们代表的 “命令” 执行的最大可接受复杂度,只有这样你才能知道你需要设计的是怎样复杂度的系统。

输出:

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

样例输入:

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

思路:

刚读这个题的时候,知道这是一个大模拟,大体上是先写出框架,再慢慢的填上每个小的操作,难一点的地方可能是小操作之间可能会产生影响。一开始刚前面几个小操作的时候,觉得应该多debug一下应该还是能写出来的。等题目看完的时候,看到那几个骚操作的时候,就就觉得这道题自己肯定是写不出来了,或者说对于我的能力来说,肯定是写不出来了。这道题更多的是一个做题经验吧,知道了自己有很多东西不会使用。
首先:
1、每个节点下可能会有多个子节点,在这里用的是map来实现的,在此之前我还没用过map,之前的时候对于不困难的题,一般是自己写几个对应的数组或者写一个结构体,来实现这个功能。一开始自己看的时候,在这里还是懵了一下,因为如果自己来实现的话,又会增加不少麻烦,还要实现对应的函数,代码量越大,bug肯定也是越多的。
2、然后是根据题意,自己会想到增加上父节点,子树节点数等。对于撤销操作,记录懒更新的vector和是否更新的updated大概也是不会想到的。
3、一个command结构体,将命令转为int型,分别对应相应的操作,使之在之后的操作更加简单,其中的,其中记录着命令,结构体中记录着当前操作的目录的指针,可以在撤销的时候直接去操作,这一个也不知道会不会这么做。并且在每次操作结束后,将上次的命令存到队列中去,可以找到撤销哪个操作,在刚看到这个题的时候,是没有想到用队列存上每一个操作的。
4、在删除的节点的时候,只是从map中删去名字,并没有释放节点,由于节点被记录在操作中,故在撤销的时候,可以直接向map中增加上这个节点,所以之后的所有节点都恢复了。(好像挺久没有怎么用过指针了,发现指针在有的时候还是有奇效。)
5、ls输出直接子目录,在这里用map<string, Directory*>的指针,来实现,分别输出所需要的子节点。
6、tree:由于使用了懒更新法,即首先判断是否有所变动,如果没有的话,则直接输出上次记录的。如果更新了,则判断输出,并重新记录。其中要判断,如果后代的目录数少于10,则直接记录输出,否则前序遍历记录前5个,后序遍历输出后5个,并记录,因此需要再写两个函数。
7、在撤销操作的时候,一直弹出队列,知道有能做的,或者队列为空。
8、总体框架很大,如果是自己写的话,肯定非常乱,(当然,自己目前肯定也写不出来),大致上跟着学长的敲的,敲完还有一堆bug。调完了卡住了,指针的vector没有初始化。修改了一下,样例跑出来了,但死活不过,改了很长时间,过了一个。又调了大半天,还是不过,拿着别人ac的代码,因为也都是跟着学长的框架走的,所以基本差不多,对着看哪儿有bug,改了好长时间。还是不过,后来跟着一行一行对着看,看了好几遍,还是没过,觉得没什么能改的了,后来又对着改,为了找出来错,把自己一下习惯写的东西,都改成一样的了,还是不过。然后又是一通乱改,也不知道怎么过了。后来好好的想了一下,可能是变量作用域或者是if和for的作用域的问题,在有些函数里面的变量名好像用到了类里面的变量,有的if和for没打括号,可能造成了问题(虽然这里也改几遍),以后要注意,还记得之前有次大的for用的i,后来中间好像用到了i,虽然用完作用域失效了,但还是产生了影响。
9、实验周临近,好几个大的代码作业,一个一个摧残着我,太难受了,每个都写老长时间。。。

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
#include <map>
#include <vector>
using namespace std;
char aa[30];

struct Directory{
	string name;    //当前目录得名字
	map<string, Directory*> children;  //子目录 
	Directory* parent;
	int childsize;      //输出子树的大小 
	vector<string> huancun;   //缓存十个后代 
	bool updated;              //如果缓存没有更新,则直接输出 
	 
	Directory(string Name, Directory* Parent){
		this->name=Name;
		this->parent=Parent;
		this->childsize=1; 
	} 
public:
	bool addChild(Directory* ch)
	{
		if (children.find(ch->name) != children.end()) return 0;
		children[ch->name] = ch;
		maintain(+ch->childsize);
		return true;
	}
	
	//向上修改孩子节点数 
	void maintain(int num){ 
		updated = true;
		childsize += num;
		if (parent != nullptr) parent->maintain(num);
	}
	
	//获得儿子 
	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->childsize);
		children.erase(it);
		return it->second;
	}
	
	Directory* cd(string Name){
		if (".."==Name)
			return this->parent;
		return getChild(Name);
	}
	void sz(){    //当前目录大小
		cout<<this->childsize<<endl;	
	}
	void ls(){  //输出多行表示直接子目录
		int num = children.size();
		if (num == 0) cout << "EMPTY" << endl;
		else if (num <= 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 << "..." << 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 (childsize == 1) cout << "EMPTY" << endl;
		else if (childsize <= 10) {
			if (this->updated) //更新后,需要清空,重新遍历得到 
			{
				huancun.clear();
				treeAll(&huancun);//重新遍历
				this->updated = false;
			}

			for (int i = 0; i < childsize; i++)
				cout << huancun[i] << endl;

		}
		else { //个数大于十,输出前五个,后五个,需要谦虚遍历和后序遍历 
			if (this->updated) {  //更新过 
				huancun.clear();
				treeFirst(5, &huancun); //记录前面五个
				treeLast(5, &huancun);  //记录后面五个
				this->updated = false;
			}

			for (int i = 0; i < 5; i++) //输出前五个 
				cout << huancun[i] << endl;

			cout << "..." << endl;
			for (int i = 9; i >= 5; i--)    //放的时候是倒着放的,所以输出的时候倒着输出 
				cout << huancun[i] << endl;
		}
	}
	
private:
	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 n1 = it->second->childsize; //该儿子包含的数量
			if (n1 >= num)
			{
				it->second->treeFirst(num, v);
				return;
			}
			else {
				it->second->treeFirst(n1, v);
				num -= n1; //在这颗子树上取了n1个
			}
			it++;   //在下一棵子树上取 
		}
	}
	void treeLast(int num, vector<string>* v){
		int n = children.size();
		auto it = children.end();
		while (n--){
			it--;
			int n1 = it->second->childsize;

			if (n1 >= num)
			{
				it->second->treeLast(num, v);
				return;
			}
			else
			{
				it->second->treeLast(n1, v);
				num -= n1;
			}
		}
		v->push_back(name);
	}
	void treeAll(vector<string>* v){
		v->push_back(name);
		auto it = children.begin();
		while (it != children.end())
		{
			it->second->treeAll(v);
			it++;
		}
	}
	
};


struct Command {
	const string cname[7] = { "MKDIR","RM","CD","SZ","LS","TREE","UNDO" };
	int type; //将命令转为整数型
	string arg; //命令
	Directory* tmpDir; //刚刚目录
	Command(string s){
		for (int i = 0; i < 7; i++) if (cname[i] == s) {
			this->type = i;
			if (i < 3) {
				cin >> aa;
				arg = aa;
			}
			return;
		}
	}
};


int main(){
	ios::sync_with_stdio(0);
	int T;
	cin>>T;
	while(T--){
		int Q; cin >> Q;
		vector<Command*> cmdList;
		Directory* now = new Directory("root", nullptr);
		while (Q--){
			cin >> aa;
			Command* cmd = new Command(aa);
			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 = false;
					while (!success && !cmdList.empty()){
						cmd = cmdList.back();
						cmdList.pop_back();
						switch (cmd->type){
							case 0: {
								Directory* xy = now->rm(cmd->arg);
								if (xy != 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;
				}
			}
		}
	cout<<endl;
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值