A - 咕咕东的目录管理器

题意

在这里插入图片描述

思路

1)自顶向下地设计整个程序框架,从程序的入口开始,先设计主函数,然后设计程序框架
程序入口

int main(){
	int T;cin>>T;
	while(T--)solve();
	return 0;
}
void solve(){
	int n;cin>>n;
	while(n--){
		cin>>temps;
		...
	}
}

一条命令不单纯是字符串,它可能设计undo,考虑封装成Command,以便服用和拓展

while(n--){
	scanf("%s",tmps);
	Command* cmd=new Command(tmmps);
}

2)思考封装
考虑“有什么”和“做什么”。
比如刚刚我们有一个命令字符串“tmps”,它即代表一条命令。
考虑到一条命令不单有命令形式,还有命令参数,比如“MKDIR s”,等
会我们肯定还要进行参数的分离,同类信息最好内聚,所以 —— 封装之!
封装Command

struct Command
{
	int type;//命令的类型
	string arg;//命令的 参数
	Command(string s) {//构造函数
		....
	}
};

将魔法值改成常量设计:

const string CMDNAMES[7] = { "MKDIR","RM","CD","SZ","LS","TREE","UNDO" };

构造函数:

Command(string s) {//构造函数


		for(int i=0;i<7;i++)
			if (CMDNAMES[i] == s) {
				type = i;
				//MKDIR、RM、CD的参数后续读入
				if (i < 3) scanf("%s", tmps), arg = tmps;
				return;
			}
	}


3)树形结构
维护一棵目录树是实现这道题的必然需求 —— 如何维护一棵树
题目要求一个目录能够根据子目录的名字取到它的子目录
所以要用 map<string,目录>,它可以根据 key 也就是 string 在内部进行排序。这样每次可以 log 级别复杂度取到子目录

struct Directory
{
	string name;//当前目录的名字
	map<string, Directory*>children;//用指针是避免复制构造造成的内存浪费
	Directory* parent;//以备CD.. 返回上级目录
	int subtreeSize;//以备sz要输出子树大小		
	Directory(string name, Directory* parent) {
		this->name = name;
		this->parent = parent;
		this->subtreeSize = 1;			
	}
};

4)解题框架
要开始写具体实现的时候,你发现,对于每条指令要有一个执行对象,那就是当前目录 “now
对于每个具体操作假设已经完成,实现solve胡基本框架:

void solve(){	
	int n; cin >> n;	
	Directory *now = new Directory("root", NULL);
	while (n--) {
		scanf("%s", tmps);		
		Command* cmd = new Command(tmps);		
		switch (cmd->type)
		{
			case 0:now->mkdir(cmd->arg) //MKDIR
			case 1:now->rm(cmd->arg)//RM
			case 2:now->cd(cmd->arg)//CD	
			case 3:now->sz();//SZ;
			case 4:now->ls();//LS;
			case 5:now->tree();//TREE		
			case 6://undo			
		}
	cout<<endl;//题目要求不同组数据直接要输出换行
}

5)实现细节:
对于结构体Dictionary:

struct Directory
{
	Directory* mkdir(string name);
	Directory* rm(string name);
	Directory* cd(string name);
	void sz();
	void ls();
	void tree();
}

同时你发现两个问题,这时发现两个问题。第一,要设计“返回值”告知某条命令的执行的结果成功/失败。 第二,“UNDO”没法封装在某一个 Directory 内部,它是隶属于当前测试数据环境的。所以,对于执行成功的命令,要保存起来,以备“UNDO。UNDO命令,它必须是 MKDIR、RM、CD 三种之一,而且需要已执行成功。因此,要保存每条指令执行的执行结果,保存到 struct Command{…}。

	Directory* tmpDir;//记录刚刚操作涉及的目录节点
void solve(){	
	int n; cin >> n;	
	Directory *now = new Directory("root", NULL);
	vector<Command*>cmdList;//新增加的数组存成功执行的命令以备undo
	while (n--) {
		scanf("%s", tmps);		
		Command* cmd = new Command(tmps);
		Directory * ch;
		switch (cmd->type)
		{
		case 0:case 1://MKDIR、RM
			cmd->tmpDir = cmd->type == 0 ? now->mkdir(cmd->arg) : now->rm(cmd->arg);
			if (cmd->tmpDir == nullptr) printf("ERR\n");
			else {
				printf("OK\n");
				cmdList.push_back(cmd);
			}
			break;
		case 2://CD
			ch = now->cd(cmd->arg);
			if (ch == nullptr)printf("ERR\n");
			else {
				printf("OK\n");
				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;
		//15、解决undo
		case 6://undo			
		}
	}
	cout<<endl;
}

UNDO操作的实现:

case 6://undo
			bool success = false;//undo执行成功与否
			while (!success && !cmdList.empty()) {
				cmd = cmdList.back(); cmdList.pop_back();
				switch (cmd->type)
				{
				//UNDO MKDIR  
				case 0:success = now->rm(cmd->arg) != nullptr; break;
				//UNDO RM
				case 1:success = now->addChild(cmd->tmpDir); break;
				//UNDO CD
				case 2:now = cmd->tmpDir; success = true; break;
				}
			}
			printf(success ? "OK\n" : "ERR\n");
		}

6)目录管理实现细节:

struct Dictionary//目录 
{
    string name;
    map<string,Dictionary*> children;//孩子按照字典序 
    Dictionary* parent;
    int subtreeSize;
    vector<string> tenDescendants[100];
    bool updated;
    Dictionary(string n,Dictionary* p)
    {
        name = n;
        parent = p;
        subtreeSize = 1;
    }
    Dictionary* getChild(string name)
    {
        map<string,Dictionary*>::iterator it = children.find(name);
        if(it == children.end())
            return NULL;
        return it->second;
    }
    Dictionary* mkdir(string name)
    {
        if(children.find(name)!=children.end())
            return NULL; 
        Dictionary* ch = new Dictionary(name,this);
        children[name] = ch;//创建 
        maintain(+1);
        return ch;
    }
    Dictionary* rm(string name)
    {
        map<string,Dictionary*>::iterator it = children.find(name);
        if(it == children.end())
            return NULL;
        maintain(-1*it->second->subtreeSize);
        children.erase(it);
        return it->second;
    }
    Dictionary* cd(string name)
    {
        if(".." ==name)
            return this->parent;
        return getChild(name);
    }
    bool addChild(Dictionary* ch)
    {
        if(children.find(ch->name)!=children.end())
            return false;
        children[ch->name] = ch;
        maintain(+ch->subtreeSize);
        return true;
    }
    void maintain(int delta)
    {
        updated = true;
        subtreeSize+=delta;
        if(parent!=NULL)
            parent->maintain(delta);//递归向上更新 
    }
    void sz()
    {
        printf("%d\n",this->subtreeSize);
    }
    void ls()
    {
        int sz = children.size();
        if(sz==0) printf("EMPTY\n");
        else if(sz<=10) 
		{
         for(map<string,Dictionary*>::iterator it = children.begin();it!=children.end();it++)
         printf("%s\n",it->first.c_str());
		}
        else
        {
            map<string,Dictionary*>::iterator it = children.begin();
            for(int i = 0;i<5;i++,it++) printf("%s\n",it->first.c_str());
            printf("...\n");
            it = children.end();
            for(int i = 0;i<5;i++) it--;
            for(int i=0;i<5;i++,it++) printf("%s\n",it->first.c_str());
        }
    }
   
};

7)实现TREE命令
利用缓存(懒更新),节点数远少于 TREE 操作数,指不定还有重复询问,对于目录相同期间问过的相同问题,理应只有一次是计算过程

void tree()
    { 
        if(subtreeSize==1) printf("EMPTY\n");
        else if(subtreeSize<=10)
        {
            if(this->updated)
            {
                tenDescendants->clear();
                treeAll(tenDescendants);
                this->updated = false;
            }
            for(int i = 0;i<subtreeSize;i++) printf("%s\n",tenDescendants->at(i).c_str());
        }
        else
        {
            if(this->updated)
            {
                tenDescendants->clear();
                treeFirstSome(5,tenDescendants);
                treeLastSome(5,tenDescendants);
                this->updated = false;
            }
            for(int i=0;i<5;i++) printf("%s\n",tenDescendants->at(i).c_str());
            printf("...\n");
            for(int i=9;i>=5;i--) printf("%s\n",tenDescendants->at(i).c_str());
        }
    }
    //更新全桶
    void treeAll(vector<string>* bar)//前序遍历 
    {
        bar->push_back(name);
        for(map<string,Dictionary*>::iterator it = children.begin();it!=children.end();it++)
        it->second->treeAll(bar);
    }//更新先根序列的5个
    void treeFirstSome(int num,vector<string>* bar)
    {
        bar->push_back(name);num--;
        if(num==0 ) return;
        int n = children.size();
        map<string,Dictionary*>::iterator  it = children.begin();
        while(n--)
        {
            int snum= it->second->subtreeSize;
            if(snum>=num)
            {
                it->second->treeFirstSome(num,bar);
                return;
            }
            else
            {
                it->second->treeFirstSome(snum,bar);
                num -= snum;
            }
            it++;
        }
    }
    //更新后根序列的5个
    void treeLastSome(int num,vector<string>* bar)
    {
        int n = children.size();
        map<string,Dictionary*>::iterator it = children.end();
        while(n--)
        {
            it--;
            int snum = it->second->subtreeSize;
            if(snum>=num)
            {
                it->second->treeLastSome(num,bar);
                return;
            }
            else
            {
                it->second->treeLastSome(snum,bar);
                num-= snum;
            }
        }
        bar->push_back(name);
    }

完整代码

#include <bits/stdc++.h>
using namespace std;
char tmps[20];
struct Dictionary//目录 
{
    string name;
    map<string,Dictionary*> children;//孩子按照字典序 
    Dictionary* parent;
    int subtreeSize;
    vector<string> tenDescendants[100];
    bool updated;
    Dictionary(string n,Dictionary* p)
    {
        name = n;
        parent = p;
        subtreeSize = 1;
    }
    Dictionary* getChild(string name)
    {
        map<string,Dictionary*>::iterator it = children.find(name);
        if(it == children.end())
            return NULL;
        return it->second;
    }
    Dictionary* mkdir(string name)
    {
        if(children.find(name)!=children.end())
            return NULL; 
        Dictionary* ch = new Dictionary(name,this);
        children[name] = ch;//创建 
        maintain(+1);
        return ch;
    }
    Dictionary* rm(string name)
    {
        map<string,Dictionary*>::iterator it = children.find(name);
        if(it == children.end())
            return NULL;
        maintain(-1*it->second->subtreeSize);
        children.erase(it);
        return it->second;
    }
    Dictionary* cd(string name)
    {
        if(".." ==name)
            return this->parent;
        return getChild(name);
    }
    bool addChild(Dictionary* ch)
    {
        if(children.find(ch->name)!=children.end())
            return false;
        children[ch->name] = ch;
        maintain(+ch->subtreeSize);
        return true;
    }
    void maintain(int delta)
    {
        updated = true;
        subtreeSize+=delta;
        if(parent!=NULL)
            parent->maintain(delta);//递归向上更新 
    }
    void sz()
    {
        printf("%d\n",this->subtreeSize);
    }
    void ls()
    {
        int sz = children.size();
        if(sz==0) printf("EMPTY\n");
        else if(sz<=10) 
		{
         for(map<string,Dictionary*>::iterator it = children.begin();it!=children.end();it++)
         printf("%s\n",it->first.c_str());
		}
        else
        {
            map<string,Dictionary*>::iterator it = children.begin();
            for(int i = 0;i<5;i++,it++) printf("%s\n",it->first.c_str());
            printf("...\n");
            it = children.end();
            for(int i = 0;i<5;i++) it--;
            for(int i=0;i<5;i++,it++) printf("%s\n",it->first.c_str());
        }
    }
    void tree()
    { 
        if(subtreeSize==1) printf("EMPTY\n");
        else if(subtreeSize<=10)
        {
            if(this->updated)
            {
                tenDescendants->clear();
                treeAll(tenDescendants);
                this->updated = false;
            }
            for(int i = 0;i<subtreeSize;i++) printf("%s\n",tenDescendants->at(i).c_str());
        }
        else
        {
            if(this->updated)
            {
                tenDescendants->clear();
                treeFirstSome(5,tenDescendants);
                treeLastSome(5,tenDescendants);
                this->updated = false;
            }
            for(int i=0;i<5;i++) printf("%s\n",tenDescendants->at(i).c_str());
            printf("...\n");
            for(int i=9;i>=5;i--) printf("%s\n",tenDescendants->at(i).c_str());
        }
    }
    void treeAll(vector<string>* bar)//前序遍历 
    {
        bar->push_back(name);
        for(map<string,Dictionary*>::iterator it = children.begin();it!=children.end();it++)
        it->second->treeAll(bar);
    }
    void treeFirstSome(int num,vector<string>* bar)
    {
        bar->push_back(name);num--;
        if(num==0 ) return;
        int n = children.size();
        map<string,Dictionary*>::iterator  it = children.begin();
        while(n--)
        {
            int snum= it->second->subtreeSize;
            if(snum>=num)
            {
                it->second->treeFirstSome(num,bar);
                return;
            }
            else
            {
                it->second->treeFirstSome(snum,bar);
                num -= snum;
            }
            it++;
        }
    }
    void treeLastSome(int num,vector<string>* bar)
    {
        int n = children.size();
        map<string,Dictionary*>::iterator it = children.end();
        while(n--)
        {
            it--;
            int snum = it->second->subtreeSize;
            if(snum>=num)
            {
                it->second->treeLastSome(num,bar);
                return;
            }
            else
            {
                it->second->treeLastSome(snum,bar);
                num-= snum;
            }
        }
        bar->push_back(name);
    }
};
struct Command
{
    string com[7] = {"MKDIR","RM","CD","SZ","LS","TREE","UNDO"};
    int type;   //命令类型
    string arg; //命令参数
    Command(string s)
    {
        for(int i = 0;i<7;i++)
        {
         if(com[i]==s)
         {
            type = i;
            if(i<3) scanf("%s",tmps),arg = tmps;
         }
		}
       
    }
    Dictionary* tmpDir;

};
void solve()
{   int n;scanf("%d",&n);
    Dictionary* now = new Dictionary("root",NULL);//当前目录 
    vector<Command*> cmdList;
    while(n--)
    {
        scanf("%s",tmps);
        Command* cmd = new Command(tmps);
        if(cmd->type==0||cmd->type==1)
        {
            cmd->tmpDir = cmd->type==0?now->mkdir(cmd->arg):now->rm(cmd->arg);
            if(cmd->tmpDir == NULL) printf("ERR\n");
            else
            {
                printf("OK\n");
                cmdList.push_back(cmd);
            }
        }
        if(cmd->type==2)
        {
            Dictionary* ch = now->cd(cmd->arg);
            if(ch==NULL) printf("ERR\n");
            else
            {
                printf("OK\n");
                cmd->tmpDir = now;/ 
                now = ch;
                cmdList.push_back(cmd);
            }
        }
        if(cmd->type==3) now->sz();
        if(cmd->type==4) now->ls();
        if(cmd->type==5) now->tree();
        if(cmd->type==6)//undo 
            {
                bool success = false;
                while(!success&&!cmdList.empty())
                {
                    cmd = cmdList.back();cmdList.pop_back();
                    switch(cmd->type)
                    {
                        case 0: success = now->rm(cmd->arg)!=NULL;break;
                        case 1: success = now->addChild(cmd->tmpDir);break;
                        case 2: now = cmd->tmpDir; success = true; break;
                    }
                }
                printf(success?"OK\n":"ERR\n");
            }
        }

}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)  solve();
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值