Week9 - 程序设计思维与实践 - 模拟文件目录管理系统

在这里插入图片描述

思路

课前试着做了做这道题,没做出来2333,先来总结一下课前没有想到的地方吧:

  • children 的存储方式:我一开始选用的是 vector ,插入时先二分查找位置然后执行插入,查找元素时二分查找,时间复杂度分别为 O ( n ) , O ( l o g n ) O(n),O(logn) O(n)O(logn),不是一个很好的选择
  • 前几个操作还比较好实现,但是对于 tree 操作的取最后 5 个元素,当时只是想到,把整棵树先序遍历一遍,边遍历边存入数组,然后输出最后 5 个元素,但是如果后续有新操作导致树形结构改变的话,那么这个数组还得再重新更新一遍,这样肯定行不通,然后就放弃了…听课23333

这节课收获蛮大的,完美地解决了我课前的疑惑,也在一定程度上拓宽了我的思路,非常感谢学长的耐心讲解!

  • map 存储 children结点,提高了插入和查找效率,插入降为 O ( l o g n ) O(logn) O(logn),查找降为 O ( 1 ) O(1) O(1)
  • 链式前向星式存储树形结构,结点存储在内存池,提高了运行效率,同时创建一个数组存储有效命令,便于处理 undo 操作
  • 将 Lazy-tag 应用在 tree 操作中,同时为每个结点存储其前向与后向结点,在第一次遍历之后,只有在当前结点又被更新过时,再重新遍历,否则直接输出结果,从而减少了重复遍历的操作。

代码实现

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

const string cmd_type[]={"MKDIR","RM","CD","SZ","LS","TREE","UNDO"}; 
const int maxn=100010;
int T,Q,n,tot,now;

struct Command{
	string name,arg;
	int type;	
	
	void init(string str){
		name=str;
		for(int i=0;i<7;i++){
			if(str==cmd_type[i]){
				type=i;
				if(i<3)
					cin>>arg;
				break;
			}
		}
	}
	
};

struct Directory{
	string name;
	int fa,sz;
	bool tag;
	map<string,int> mp;
	vector<string> pre,back;
	
	void init(string s,int p){
		name=s;
		fa=p;
		sz=1;
		tag=0;
		pre.clear();
		back.clear();
		mp.clear();
	} 
	
}node[maxn];

struct ValidCommand{
	string name;
	int u,v;
	ValidCommand(string nn,int uu,int vv):name(nn),u(uu),v(vv){}	
};

Command cmd; 
vector<ValidCommand> v;

void init(){
	tot=0;
	now=0;
	v.clear();
	node[0].init("root",-1);
}

void insert(string s,int p){
	node[++tot].init(s,p);
	node[p].mp[s]=tot;
}

void update(int id,int num){
	while(id!=-1){
		node[id].sz+=num;
		node[id].tag=0;
		id=node[id].fa;
	}
}

void mkdir(){
	map<string,int>::iterator it=node[now].mp.find(cmd.arg);
	if(it!=node[now].mp.end()){
		cout<<"ERR"<<endl;
	}
	else{
		cout<<"OK"<<endl;
		insert(cmd.arg,now);
		update(now,1);
		v.push_back(ValidCommand("MKDIR",now,tot));
	}
}

void rm(){
	map<string,int>::iterator it=node[now].mp.find(cmd.arg);
	if(it==node[now].mp.end()){
		cout<<"ERR"<<endl;
	}
	else{
		int u=it->second;
		node[now].mp.erase(it);
		update(now,-1*node[u].sz);
		v.push_back(ValidCommand("RM",now,u));
		cout<<"OK"<<endl;
	}	
}

void cd(){
	if(cmd.arg==".."){
		if(node[now].fa==-1){
			cout<<"ERR"<<endl;
			return;
		}
		else{		
			v.push_back(ValidCommand("CD",now,node[now].fa));
			now=node[now].fa;
			cout<<"OK"<<endl;
			return;
		}
	}
	else{
		map<string,int>::iterator it=node[now].mp.find(cmd.arg);
		if(it==node[now].mp.end()){
			cout<<"ERR"<<endl;
			return;
		}
		else{
			v.push_back(ValidCommand("CD",now,node[now].mp[cmd.arg]));
			now=node[now].mp[cmd.arg];
			cout<<"OK"<<endl;
		}			
	}
}

void sz(){
	cout<<node[now].sz<<endl;
}

void ls(){
	int Size=node[now].mp.size();
	if(Size==0){
		cout<<"EMPTY"<<endl;
		return;
	}
	else if(Size<=10){	
		for(map<string,int>::iterator it=node[now].mp.begin();
				it!=node[now].mp.end();it++){
			cout<<it->first<<endl;			
		}
	}
	else{
		map<string,int>::iterator it=node[now].mp.begin();
		for(int i=0;i<5;i++){
			cout<<it->first<<endl;
			it++;
		}
		cout<<"..."<<endl;
		it=node[now].mp.end();
		for(int i=0;i<5;i++)
			it--;
		for(int i=0;i<5;i++){
			cout<<it->first<<endl;
			it++;
		}					
	}
}

void undo(){
	if(v.size()==0){
		cout<<"ERR"<<endl;
		return;
	}
	ValidCommand enable=v[v.size()-1];
	v.pop_back();
	cout<<"OK"<<endl;
	if(enable.name=="MKDIR"){		
		int u=enable.v;
		update(now,(-1)*node[u].sz);
		node[now].mp.erase(node[u].name);
	} 
	else if(enable.name=="RM"){
		node[now].mp[node[enable.v].name]=enable.v;
		update(now,node[enable.v].sz);
	}
	else{
		now=enable.u;
	}
}

void pushdown(int id);

void pretrack(int id){
	node[id].pre.push_back(node[id].name);
	if(node[id].sz==1)
		return;
	if(node[id].sz<=10){
		for(map<string,int>::iterator it=node[id].mp.begin();
				it!=node[id].mp.end();it++){
			if(!node[it->second].tag)
				pushdown(it->second);
			node[id].pre.insert(node[id].pre.end(),node[it->second].pre.begin(),
								node[it->second].pre.end());			
		}
		return;		
	}
	int cnt=1;
	for(map<string,int>::iterator it=node[id].mp.begin();
			it!=node[id].mp.end();it++){
		if(!node[it->second].tag)
			pushdown(it->second);
		for(int j=0;j<node[it->second].pre.size();j++){
			node[id].pre.push_back(node[it->second].pre[j]);
			if(++cnt>=5)
				break;
		}
		if(cnt>=5)
			break;		
	}	
}

void backtrack(int id){
	int cnt=0;
	map<string,int>::iterator it=node[id].mp.end();
	--it;
	while(1){
		if(!node[it->second].tag)
			pushdown(it->second);
		for(int i=node[it->second].back.size()-1;i>=0;i--){
			node[id].back.push_back(node[it->second].back[i]);
			if(++cnt>=5){
				reverse(node[id].back.begin(),node[id].back.end());
				break;
			}
		}
		if(cnt>=5||it==node[id].mp.begin())
			break;
		it--;
	}
}

void pushdown(int id){
	node[id].pre.clear();
	node[id].back.clear();
	pretrack(id);
	if(node[id].sz>10)
		backtrack(id);
	else
		node[id].back=node[id].pre;
	node[id].tag=1;
}

void tree(){
	if(!node[now].tag)
		pushdown(now);
	if(node[now].sz==1)
		cout<<"EMPTY"<<endl;
	else if(node[now].sz>1&&node[now].sz<=10){
		for(int i=0;i<node[now].pre.size();i++)
			cout<<node[now].pre[i]<<endl;
	}
	else{
		for(int i=0;i<5;i++)
			cout<<node[now].pre[i]<<endl;
		cout<<"..."<<endl;
		for(int i=5;i>=1;i--)
			cout<<node[now].back[node[now].back.size()-i]<<endl;
	}
}

int main()
{
//	freopen("test.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>T;
	while(T--){
		cin>>Q;
		init();
		for(int i=1;i<=Q;i++){
			string s;
			cin>>s;
			cmd.init(s);
			switch(cmd.type){
				case 0:{
					mkdir();
					break;
				}
				case 1:{
					rm();
					break;
				}
				case 2:{
					cd();
					break;
				}
				case 3:{
					sz();
					break;
				}
				case 4:{
					ls();
					break;
				}
				case 5:{
					tree();
					break;
				}
				case 6:{
					undo();
					break;
				}
			}
		}
		cout<<endl;
	}	
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值