Week9 作业 A - 咕咕东的目录管理器

题面
咕咕东的雪梨电脑的操作系统在上个月受到宇宙射线的影响,时不时发生故障,他受不了了,想要写一个高效易用零bug的操作系统 —— 这工程量太大了,所以他定了一个小目标,从实现一个目录管理器开始。前些日子,东东的电脑终于因为过度收到宇宙射线的影响而宕机,无法写代码。他的好友TT正忙着在B站看猫片,另一位好友瑞神正忙着打守望先锋。现在只有你能帮助东东!
初始时,咕咕东的硬盘是空的,命令行的当前目录为根目录 root。
目录管理器可以理解为要维护一棵有根树结构,每个目录的儿子必须保持字典序。

现在咕咕东可以在命令行下执行以下表格中描述的命令:
命令
类型
实现
说明
MKDIR s
操作
在当前目录下创建一个子目录 s,s 是一个字符串
创建成功输出 “OK”;若当前目录下已有该子目录则输出 “ERR”
RM s
操作
在当前目录下删除子目录 s,s 是一个字符串
删除成功输出 “OK”;若当前目录下该子目录不存在则输出 “ERR”
CD s
操作
进入一个子目录 s,s 是一个字符串(执行后,当前目录可能会改变)
进入成功输出 “OK”;若当前目录下该子目录不存在则输出 “ERR”
特殊地,若 s 等于 “…” 则表示返回上级目录,同理,返回成功输出 “OK”,返回失败(当前目录已是根目录没有上级目录)则输出 “ERR”
SZ
询问
输出当前目录的大小
也即输出 1+当前目录的子目录数
LS
询问
输出多行表示当前目录的 “直接子目录” 名
若没有子目录,则输出 “EMPTY”;若子目录数属于 [1,10] 则全部输出;若子目录数大于 10,则输出前 5 个,再输出一行 “…”,输出后 5 个。
TREE
询问
输出多行表示以当前目录为根的子树的前序遍历结果
若没有后代目录,则输出 “EMPTY”;若后代目录数+1(当前目录)属于 [1,10] 则全部输出;若后代目录数+1(当前目录)大于 10,则输出前 5 个,再输出一行 “…”,输出后 5 个。若目录结构如上图,当前目录为 “root” 执行结果如下,
UNDO
特殊
撤销操作
撤销最近一个 “成功执行” 的操作(即MKDIR或RM或CD)的影响,撤销成功输出 “OK” 失败或者没有操作用于撤销则输出 “ERR”
输入
输入文件包含多组测试数据,第一行输入一个整数表示测试数据的组数 T (T <= 20);
每组测试数据的第一行输入一个整数表示该组测试数据的命令总数 Q (Q <= 1e5);
每组测试数据的 2 ~ Q+1 行为具体的操作 (MKDIR、RM 操作总数不超过 5000);
面对数据范围你要思考的是他们代表的 “命令” 执行的最大可接受复杂度,只有这样你才能知道你需要设计的是怎样复杂度的系统。
输出
每组测试数据的输出结果间需要输出一行空行。注意大小写敏感。
时空限制
Time limit 6000 ms
Memory limit 1048576 kB
样例输入
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
解题思路:
首先对每条指令,每个指令有指令的类型以及MKDIR,RM,CD三个指令还有参数,所以用Command结构体进行封装。又因为目录管理器是一棵目录树的数据结构,所以需要维护该树,又因为要求字典序,所以要用map<string,目录>,它可以根据key也就是string 在内部进行排序,用类Directory表示。
具体指令:
MKDIR 查找目标目录,存在则输出 “ERR”,创建目录,往map里插入,成功输出 “OK”;往前调用函数更改 snum值
RM 查找目标目录,不存在则输出 “ERR”,删除成功输出 “OK”;记录命令
CD 查找目标目录,不存在则输出 “ERR”,否则更改workdir 记录命令
SZ 直接返回 workdir->snum
LS 若没有子目录,则输出 “EMPTY”;若子目录数属于 [1,10] 则全部输出;若子目录数大于 10,则前序输出前 5 个,再输出一行 “…”,后序输出后 5 个。
TREE 若没有后代目录,则输出 “EMPTY” ,若后代目录数+1(当前目录)属于 [1,10] 则全部前序输出,若后代目录数+1(当前目录)大于 10,则前序输出前 5 个,后序遍历后5个 加上缓存
UNDO 取出满足条件的最后一条命令,还原。mk->rm rm->mk,注意的是取出原先删除的结点 cd->直接还原工作目录

#include<iostream>
#include<vector>
#include<cstring>
#include<map>
using namespace std;

struct ptrcmp {
    bool operator()(const char* s1, const char* s2) const {
        return strcmp(s1, s2) < 0;
    }
};

struct dirnode {
    char * name;
    dirnode* up;
    map<char *, dirnode*,ptrcmp> sub;
    int snum;
    vector<char*> qianxu;
    vector<char*> houxu;
    int updated;
    dirnode(dirnode* up, char * name) :up(up), name(name) {
        snum = 1;
        updated = 1;
    }
};

struct opcode {
    char * name;
    int optype;
    dirnode* olddir;
    opcode(char * name, int optype) :name(name), optype(optype) {
        olddir = NULL;
    }
    opcode(char * name, int optype, dirnode* olddir) :name(name), optype(optype), olddir(olddir) {}
};

class dir {
public:
    dir() {
        char* root = new char[10];
        strcpy(root, "root");
        workdir = new dirnode(NULL, root);
        rmdir = NULL;
    }
    void touched(int num) {
        dirnode* thisnode = workdir;
        while (thisnode != NULL) {
            thisnode->snum += num;
            thisnode->updated = 1;
            thisnode = thisnode->up;
        }
    }
    void mkdir(char * s) {
        map<char *, dirnode*,ptrcmp>::iterator it = workdir->sub.find(s);
        if (it != workdir->sub.end()) {
            printf("ERR\n");
            return;
        }
        dirnode* newnode = new dirnode(workdir, s);
        workdir->sub.insert(make_pair(s, newnode));
        history.push_back(opcode(s, 1));
        touched(1);
        printf("OK\n");
        return;
    }
    void rm(char * s) {
        map<char *, dirnode*,ptrcmp>::iterator it = workdir->sub.find(s);
        if (it == workdir->sub.end()) {
            printf("ERR\n");
            return;
        }
        rmdir = it->second;
        workdir->sub.erase(it);
        history.push_back(opcode(s, 2, rmdir));
        touched(0-rmdir->snum);
        printf("OK\n");
        return;
    }
    void cd(char * s) {
        if (s[0] == '.' && s[1] == '.' && s[2] == '\0') {
            if (workdir->up == NULL) {
                printf("ERR\n");
                return;
            }
            history.push_back(opcode(s, 3, workdir));
            workdir = workdir->up;
            printf("OK\n");
            return;
        }
        map<char *, dirnode*,ptrcmp>::iterator it = workdir->sub.find(s);
        if (it == workdir->sub.end()) {
            printf("ERR\n");
            return;
        }
        history.push_back(opcode(s, 3, workdir));
        workdir = it->second;
        printf("OK\n");
        return;
    }
    int sz() {
        return workdir->snum;
    }
    void ls() {
        if (workdir->sub.empty()) {
            printf("EMPTY\n");
            return;
        }
        if (workdir->sub.size() <= 10) {
            for (auto it = workdir->sub.begin(); it != workdir->sub.end(); it++) {
                printf("%s\n", it->first);
            }
            return;
        }
        int count = 1;
        for (auto it = workdir->sub.begin(); it != workdir->sub.end(); it++) {
            printf("%s\n", it->first);
            if (count == 5) {
                printf("...\n");
                break;
            }
            count++;
        }
        count = 1;
        vector<char*> toput;
        for (auto it = workdir->sub.rbegin(); it != workdir->sub.rend(); it++) {
            toput.push_back(it->first);
            if (count == 5) {
                break;
            }
            count++;
        }
        for (int i = 4; i >= 0; i--) {
            printf("%s\n", toput[i]);
        }
        toput.clear();
        return;
    }
    void undo() {
        if (history.empty()) {
            printf("ERR\n");
            return;
        }
        opcode* ccode = &history.back();
        if (ccode->optype == 1) { //mk->rm
            map<char *, dirnode*,ptrcmp>::iterator it = workdir->sub.find(ccode->name);
            workdir->sub.erase(it);
            history.pop_back();
            touched(-1);
            printf("OK\n");
            return;
        }
        else if (ccode->optype == 2) { //rm->mk
            map<char *, dirnode*,ptrcmp>::iterator it = workdir->sub.find(ccode->name);
            workdir->sub.insert(make_pair(ccode->name, ccode->olddir));
            history.pop_back();
            touched(ccode->olddir->snum);
            printf("OK\n");
            return;
        }
        else if (ccode->optype == 3) { //cd
            workdir = ccode->olddir;
            history.pop_back();
            printf("OK\n");
            return;
        }
        history.pop_back();
        printf("ERR\n");
    }
    void tree() {
        if (workdir->sub.empty()) {
            printf("EMPTY\n");
            return;
        }
        if (sz() <= 10) {
            if (workdir->updated) {
                workdir->qianxu.clear();
                preorderall(workdir,&workdir->qianxu);
                workdir->updated = 0;
            }
            for (int i = 0; i < workdir->qianxu.size(); i++) {
                printf("%s\n", workdir->qianxu[i]);
            }
            return;
        }
        if (workdir->updated) {
            workdir->qianxu.clear();
            workdir->houxu.clear();
            int count = 5;
            preorder(workdir, count, &workdir->qianxu);
            count = 5;
            postorder(workdir, count,&workdir->houxu);
            workdir->updated = 0;
        }
        for (int i = 0; i < 5; i++) {
            printf("%s\n", workdir->qianxu[i]);
        }
        printf("...\n");
        for (int i = 4; i >= 0; i--) {
            printf("%s\n", workdir->houxu[i]);
        }
    }

    void preorderall(dirnode* cnode, vector<char*>* qianxu) {
        qianxu->push_back(cnode->name);
        for (auto it = cnode->sub.begin(); it != cnode->sub.end(); it++) {
            preorderall(it->second,qianxu);
        }
    }
    void preorder(dirnode* cnode, int& remain,vector<char*>* qianxu) {
        if (remain < 1) return;
        qianxu->push_back(cnode->name);
        remain--;
        for (auto it = cnode->sub.begin(); it != cnode->sub.end() && remain > 0; it++) {
            preorder(it->second, remain,qianxu);
        }
    }
    void postorder(dirnode* cnode, int& remain, vector<char*>* houxu) {
        for (auto it = cnode->sub.rbegin(); it != cnode->sub.rend() && remain > 0; it++) {
            postorder(it->second, remain,houxu);
        }
        if (remain < 1) return;
        houxu->push_back(cnode->name);
        remain--;
    }

private:
    dirnode* workdir;
    dirnode* rmdir;
    vector<opcode> history;
};

void mainloop() {
    int q;
    scanf("%d", &q);
    dir d;
    char op[8];
    char * s;
    for (int qi = 0; qi < q; qi++) {
        scanf("%s", op);
        if (op[0] == 'M') {
            s = new char[24];
            scanf("%s", s);
            d.mkdir(s);
        }
        else if (op[0] == 'R') {
            s = new char[24];
            scanf("%s", s);
            d.rm(s);
        }
        else if (op[0] == 'C') {
            s = new char[24];
            scanf("%s", s);
            d.cd(s);
        }
        else if (op[0] == 'S') {
            printf("%d\n", d.sz());
        }
        else if (op[0] == 'L') {
            d.ls();
        }
        else if (op[0] == 'T') {
            d.tree();
        }
        else if (op[0] == 'U') {
            d.undo();
        }
    }

}
int main()
{
    int t;
    scanf("%d", &t);
    for (int ti = 0; ti < t; ti++) {
        mainloop();
        if (ti != t - 1) {
            printf("\n");
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值