WEEK9 周记 作业——模拟题_股股东的目录管理器

WEEK9 周记 作业——模拟题_股股东的目录管理器

一、题意

1.简述

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

2.输入格式

在这里插入图片描述

3.输出格式

在这里插入图片描述

4.时空限制

在这里插入图片描述

5.样例

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

二、算法

主要思路

按照题意将每一个功能都实现即可。
但是需要注意的是,有些地方是可以通过改进逻辑来降低时间复杂度的。
比如,对于RM操作,为了后面UNDO操作能够更好地执行,实际上我们在删除的时候只删除边即可,也就是只在其父节点的孩子map中将该节点删除即可,dir数组中则不必删除。
再比如tree操作的懒更新:记一下是不是最新了,当调用tree函数发现当前的就是最新的,就直接返回,复杂度为 O ( 1 ) O(1) O(1),如果不是最新的再去前序遍历再去更新。


有一个比较好的降低时间复杂度的点:
在TREE函数中,如果是孩子节点的数目大于10个,那么就需要输出前5个和后5个。此时本来打算统一用一个前序遍历函数将所有的都给遍历一遍。这样代码量少。
但是还有更省时间的方法。前五个用从头前序遍历,遍历到第五个就直接结束。后五个也前序遍历,但不从头开始,而是从最后一棵子树开始进行前序遍历。这种并没有打破前序遍历的顺序,而是将前序遍历的后面才进行的操作先进行。而如果最后一刻子树也有子树,则也是从最后一棵子树进行前序遍历。先完成自己所有子树的前序遍历的节点先记录下来。当记录了5个之后直接结束函数。当然,记录下来的是从最后一个数到倒数第5个数,所以输出的时候需要从从数组的后面往前输出。
这样的操作使得不需要对进行TREE操作的数的所有节点都遍历一遍,能够降低时间复杂度。


三、代码

#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<map>
#include<vector>
using namespace std;
const string order[7]= {"MKDIR","RM","CD","SZ","LS","TREE","UNDO"};
struct Directory{
	string name; //目录名 
	map<string,int> children; //孩子 
	int fa,sz; //父节点和当前子树的节点个数 
	vector<string> pre,bck; //存前序遍历的 
	bool tag; //是否被更新过 
	Directory(string name="root",int fa=-1):name(name),fa(fa){
		sz = 1;
		tag = 0;   //得是0 
	}
} dir[5010]; //0是根目录 
//删除某个目录的时候只需要删除边就行,
//不需要将这个目录对应的数组元素删除,不用这个数组元素就是了(以后再也找不到了) 
int idx; //目录数组的索引 

int now; //当前在哪一个目录 
vector<pair<string,int> > v; //<cmd,route>
void update(int cur,int num){
	while(cur!=-1){
		dir[cur].sz += num;
		dir[cur].tag = 0;
		cur = dir[cur].fa;	
	}	
}
void MKDIR(string& r){
	if(dir[now].children.count(r)==1){  //注意map的这个函数的作用!!见收藏的博客 
		cout<<"ERR"<<endl;
		return;
	}
	cout<<"OK"<<endl;
	dir[now].children.insert(make_pair(r,++idx)); 
	//注意map的这个函数的作用!!见收藏的博客
	update(now,1);
	 
	Directory d(r,now);
	dir[idx] = d;
	
	v.push_back(pair<string,int>("MKDIR",idx)); 
}
void RM(string& r){
	if(dir[now].children.count(r)==0){
		cout<<"ERR"<<endl;
		return;
	}
	cout<<"OK"<<endl;
	int pos = dir[now].children[r];
	dir[now].children.erase(r); //查一查map的删除
	update(now,(-1)*dir[pos].sz);
	
	v.push_back(pair<string,int>("RM",pos)); 
}

void CD(string& r){
	if(r==".."){ //进入上层目录 
		if(now==0){
			cout<<"ERR"<<endl;
			return;	
		}
		cout<<"OK"<<endl;
		v.push_back(pair<string,int>("CD",now));
		//不能放最前面,因为不会撤销不成功执行的操作
		//不能放在now修改之后 
		now = dir[now].fa;
		 
	}else{//进入某一个子目录 
		if(dir[now].children.count(r)==0){
			cout<<"ERR"<<endl;
			return;	
		}
		cout<<"OK"<<endl;
		v.push_back(pair<string,int>("CD",now)); 
		//不能放最前面,因为不会撤销不成功执行的操作 
		now = dir[now].children[r];
	}
	
}

void SZ(){ //输出当前目录的大小 
	cout<<dir[now].sz<<endl;
} 

void LS(){ //输出当前目录的直接目录名 
	int num = dir[now].children.size();
	if(num==0){
		cout<<"EMPTY"<<endl;
	}else if(num>=1&&num<=10){
		for(auto i=dir[now].children.begin();i!=dir[now].children.end();i++)
			cout<<i->first<<endl;
	}else{
		auto it = dir[now].children.begin(); 
		for(int i=0;i<5;i++){//前五个 
			cout<<it->first<<endl;
			it++;
		}
		cout<<"..."<<endl;
		it = dir[now].children.end();
		for(int i=0;i<5;i++) it--;
		for(int i=0;i<5;i++){//后五个 
			cout<<it->first<<endl;
			it++;	
		}
			
	}
}
void getAll(int cur){
	dir[now].pre.push_back(dir[cur].name);
	auto it=dir[cur].children.begin();
	for(;it!=dir[cur].children.end();it++){
		getAll(it->second);
	}
}

void getPreVector(int cur,int& preIndex){
	if(preIndex<5){
		dir[now].pre.push_back(dir[cur].name);
		preIndex++;	
	}
	else return; 
	auto it=dir[cur].children.begin();
	for(;it!=dir[cur].children.end();it++){
		getPreVector(it->second,preIndex);
		if(preIndex>=5) return;  //能降低时间复杂度 
	}
}

void getBckVector(int cur,int& bckIndex){  //这个函数很巧妙,能够降低时间复杂度 
	auto it=dir[cur].children.end();
	while(it!=dir[cur].children.begin()){//判断前一个当前it是不是begin 
		it--; 
		getBckVector(it->second,bckIndex);
		if(bckIndex>=5) return;  //能降低时间复杂度
	} 
	if(bckIndex<5){
		dir[now].bck.push_back(dir[cur].name);
		bckIndex++;
	}
	else return;
}

//void preOrder(int cur,int preIndex,int bckIndex){
//	if(preIndex<5){
//		dir[now].pre.push_back(dir[cur].name);
//		preIndex++;	
//	}
//	auto it=dir[cur].children.begin();
//	for(;it!=dir[cur].children.end();it++){
//		preOrder(it->second);
//	}
//	if(bckIndex<5){
//		dir[now].bck.push_back(dir[cur].name);
//		bckIndex++;
//	}
//}
void pushdown(){  //只针对当前now所在的节点 
	dir[now].pre.clear();
	dir[now].bck.clear(); //每次更新都得清空,很重要 
	int sz = dir[now].sz;
	if(sz>1&&sz<=10){
		getAll(now);
	}else{
		int preIndex=0;
		int bckIndex=0;
		getPreVector(now,preIndex);
		getBckVector(now,bckIndex);
	}
	dir[now].tag = 1;   ///别忘了! 
}
void TREE(){
	int sz = dir[now].sz;
	if(dir[now].tag==0){
		pushdown();
	}
	if(sz==1){
		cout<<"EMPTY"<<endl;
		return;
	}
	if(sz>1&&sz<=10){	
		for(int i=0;i<sz;i++)
			cout<<dir[now].pre[i]<<endl; //查查这里的[] 
	}else{
		for(int i=0;i<5;i++)
			cout<<dir[now].pre[i]<<endl; //查查这里的[] 
		cout<<"..."<<endl;
		for(int i=4;i>=0;i--)
			cout<<dir[now].bck[i]<<endl; //查查这里的[] 
	}
}

void UNDO(){
	if(v.size()==0){
		cout<<"ERR"<<endl;
		return;
	}
	else{
		cout<<"OK"<<endl;
		pair<string,int> pp = v[v.size()-1]; //注意这种写法 
		v.pop_back();
		if(pp.first=="MKDIR"){
			dir[now].children.erase(dir[pp.second].name);
			update(now,-1);
		}else if(pp.first=="RM"){
			dir[now].children[dir[pp.second].name] = pp.second;
			update(now,dir[pp.second].sz);
		}else{
			now = pp.second;
		}
	} 
} 
int getType(string s,string& r){  //这里的输入判断还是比较巧妙的 
	for(int i=0;i<7;i++){
		if(s==order[i]){
			if(i<3) cin>>r;
			return i;
		}
	}
}
int main(){
	int t;
	ios::sync_with_stdio(false);
	cin>>t;
	for(int tt=0;tt<t;tt++){
		if(tt!=0) cout<<endl;
		idx = 0;
		now = 0;
		v.clear();
		dir[now].bck.clear();
		dir[now].pre.clear();
		dir[now].children.clear();
		dir[now].tag = 0;
		dir[now].sz = 1;
		int q;
		cin>>q;
		while(q--){
			string cmd,r;
			cin>>cmd;
			int type = getType(cmd,r);
			switch(type){
				case 0:
					MKDIR(r);
					break;
				case 1:
					RM(r);
					break;
				case 2:
					CD(r);
					break;
				case 3:
					SZ();
					break;
				case 4:
					LS();
					break;
				case 5:
					TREE();
					break;
				case 6:
					UNDO();
					break;
			}
		}
		
	}
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值