├── part1 ├── t1 │ ├── skipList │ │ ├── skiplist.cpp │ │ ├── main.cpp │ │ └── skiplist.h │ ├── rand │ │ └── main.cpp │ ├── expeSl │ │ ├── main.cpp │ │ └── skiplist.h │ ├── README.md │ └── t1.md ├── t4 │ ├── REAEMD.md │ ├── solution1.cpp │ ├── solution2.cpp │ └── t4.md ├── t3 │ ├── README.md │ ├── console.h │ ├── main.cpp │ ├── t3.md │ └── catalogTree.h └── t2 │ ├── LoserTree.h │ ├── externalSorter.cpp │ ├── README.md │ ├── t2.md │ └── main.cpp ├── part2 ├── main.cpp ├── README.md └── busLine.md └── README.md /part1/t1/skipList/skiplist.cpp: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /part1/t4/REAEMD.md: -------------------------------------------------------------------------------- 1 | * 两种方法分别为分支定界和回溯 -------------------------------------------------------------------------------- /part1/t3/README.md: -------------------------------------------------------------------------------- 1 | * catalogTree.h 结构ADT+功能 2 | * console.h 终端 3 | * main.cpp 主程序 -------------------------------------------------------------------------------- /part2/main.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/json13245/DS-courseDesign/HEAD/part2/main.cpp -------------------------------------------------------------------------------- /part1/t3/console.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/json13245/DS-courseDesign/HEAD/part1/t3/console.h -------------------------------------------------------------------------------- /part1/t3/main.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/json13245/DS-courseDesign/HEAD/part1/t3/main.cpp -------------------------------------------------------------------------------- /part1/t2/LoserTree.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/json13245/DS-courseDesign/HEAD/part1/t2/LoserTree.h -------------------------------------------------------------------------------- /part1/t1/rand/main.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/json13245/DS-courseDesign/HEAD/part1/t1/rand/main.cpp -------------------------------------------------------------------------------- /part1/t4/solution1.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/json13245/DS-courseDesign/HEAD/part1/t4/solution1.cpp -------------------------------------------------------------------------------- /part1/t4/solution2.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/json13245/DS-courseDesign/HEAD/part1/t4/solution2.cpp -------------------------------------------------------------------------------- /part1/t1/expeSl/main.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/json13245/DS-courseDesign/HEAD/part1/t1/expeSl/main.cpp -------------------------------------------------------------------------------- /part1/t1/expeSl/skiplist.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/json13245/DS-courseDesign/HEAD/part1/t1/expeSl/skiplist.h -------------------------------------------------------------------------------- /part1/t1/skipList/main.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/json13245/DS-courseDesign/HEAD/part1/t1/skipList/main.cpp -------------------------------------------------------------------------------- /part1/t1/skipList/skiplist.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/json13245/DS-courseDesign/HEAD/part1/t1/skipList/skiplist.h -------------------------------------------------------------------------------- /part1/t2/externalSorter.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/json13245/DS-courseDesign/HEAD/part1/t2/externalSorter.cpp -------------------------------------------------------------------------------- /part1/t2/README.md: -------------------------------------------------------------------------------- 1 | * 各文件功能说明: 2 | * main.cpp:生成用于排序的随机数据 3 | * LoserTree.h:存储最小输者树类的声明及一些相关结构体 4 | * externalSorter.cpp:最小输者树的实现和外排序的实现 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 山东大学数据结构课程设计 2 | 3 | * 课程设计分为part1&part2两部分: 4 | 5 | * part1包含四个题,每个人都是一样的 6 | * [t1](./part1/t1/t1.md) 7 | * [t2](./part1/t2/t2.md) 8 | * [t3](./part1/t3/t3.md) 9 | * [t4](./part1/t4/t4.md) 10 | * part2是综合题,每个人的题是从题库中随机分配的,舍友有的是栈实现符号匹配,有的是后缀树组,这里给出我的题。 11 | * [part2](./part2/README.md) 12 | -------------------------------------------------------------------------------- /part1/t2/t2.md: -------------------------------------------------------------------------------- 1 | # **外排序** 2 | 3 | ### **问题描述** 4 | 5 | 应用竞赛树结构模拟实现外排序。 6 | 7 | 8 | 9 | ### **基本要求** 10 | 11 | * 设计并实现最小输者树结构 ADT,ADT 中应包括初始化、返回赢者,重构等基本操作。 12 | * 应用**最小输者树**设计实现外排序,外部排序中的生成最初归并串以及 K 路归并都应用**最小输者树**结构实现; 13 | 14 | * 随机创建一个较长的文件作为外排序的初始数据;设置归并路数以及缓冲区的大小;获得外排序的访问磁盘的次数并进行分析。可采用小文件来模拟磁盘块 15 | 16 | -------------------------------------------------------------------------------- /part1/t1/README.md: -------------------------------------------------------------------------------- 1 | * 源码分为三个项目(模块),分别是: 2 | * skipList:跳表 ADT 实现及正确性验证模块 3 | * rand:随机数及随机操作生成模块 4 | * expeSl:跳表维护动态数据效率实验模块 5 | * 三个项目所含文件及功能: 6 | * skipList: 7 | * skiplist.h:跳表ADT的声明与实现(由于类模板的限制,跳表ADT的声明与实现无法分别分管在skiplist.h与skiplist.cpp文件中,故声明与实现均写在skiplist.h文件中) 8 | * main.cpp:用于验证跳表结构的正确性,导入示例数据集和自己生成的数据,将结果输出到文本文件中 9 | * rand: 10 | * main.cpp:生成随机数用于初始化跳表,生成随机操作用于对跳表进行大量操作,方便实验测时 11 | * expeSl: 12 | * skiplist.h:与skiplist项目中对应内容一致 13 | * main.cpp:根据rand项目生成的随机数初始化跳表,测定初态各种操作用时,再将rand项目生成的随机操作用于跳表,最后测定末态各种操作用时 -------------------------------------------------------------------------------- /part1/t4/t4.md: -------------------------------------------------------------------------------- 1 | # 石油放大器设置问题 2 | 3 | ## 问题描述 4 | 5 | 对于一个石油传送网络可由一个加权有向无环图 G 表示。该图中有一个称为源点的顶点 S ( 保证 S 的入度为 0 ) , 从 S 出发 , 石油流向图中的其他顶点 . G 中每条边上的权重为它所连接的两点间的距离。 6 | 7 | 在输送石油的过程中 , 需要有一定的压力才能使石油从一个点到达另一个点,但压力会随着路程的增加而降低 ( 即压力的损失量是路程的函数 ) . 8 | 9 | 因此为了保证石油在网络的正常运输,在网络传输中必须保证在任何位置的压力都要不小于最小压力 Pmin。为了维持这个最小压力,可在 G 中的一些或全部顶点放置压力放大器 , 压力放大器可以将压力恢复至该网络允许的最大压力Pmax。 10 | 11 | 可以设 d 为石油从压力 Pmax 降为压力 Pmin 所走的距离 , 在无压力放大器的情况下石油可运输的距离不超过 d . 12 | 13 | 在设置信号放大器问题中,需要在 G 中放置最少数量的放大器,使得该传输网络从 S 出发,能够将汽油输送到图中的**所有**其他顶点。 14 | 15 | ## 基本要求 16 | 17 | * 给出两种方法以解决上述问题,验证两种方法的正确性. 18 | 19 | * 比较两种方法的时间和空间性能,用图表显示比较结果。 -------------------------------------------------------------------------------- /part1/t3/t3.md: -------------------------------------------------------------------------------- 1 | # 模拟文件目录系统 2 | 3 | ## 问题描述 4 | 5 | * 使用树结构实现一个简单文件目录系统的模拟程序。 6 | 7 | ## 基本要求 8 | 9 | * 设计并实现目录树 CatalogTree 的 ADT。 10 | 11 | * 应用以上 CatalogTree 结构设计并实现一文件目录系统的模拟程序。 12 | 13 | * 文件目录系统程序是一个不断等待用户输入命令的解释程序,根据用户输入的命令完成相关操作,直到退出(quit)。目录系统应支持如下基本操作: 14 | * dir ——列出**当前目录下的**所有子目录与文件项。 15 | * cd ——列出当前目录的绝对路经 。 16 | * cd ..——当前目录变为当前目录的父目录 。 17 | * cd str——当前目录变为 str 所表示路径的目录。 18 | * mkdir str ——在(当前目录下)创建一个子目录(名为 str),若存在则不进行任何操作。 19 | * mkfile str ——在(当前目录下)创建一个文件(名为 str) ,若存在则不进行任何操作。 20 | * delete str ——删除(当前目录下)名为 str 的目录或文件,若不存在则不进行任何操作。 21 | * save str—— 将从根节点开始的目录树结构保存到文件(名为 str)中。 22 | * load str —— 从文件 str 中读取之前保存的目录树结构,并根据其重新建立当前目录树 23 | * quit —— 退出程序 24 | 25 | ## 选做功能 26 | 27 | 你可以自行充实目录树支持的指令,添加一些参数支持,这将有助于你对目录系统 28 | 29 | 的理解。提倡实现其他指令或带参数的现有指令。 30 | 31 | tips: 32 | 33 | 你应区分出 str 代表的是绝对路径还是相对路径; -------------------------------------------------------------------------------- /part1/t1/t1.md: -------------------------------------------------------------------------------- 1 | # 跳表实现与分析 2 | 3 | 4 | 5 | ### **问题描述** 6 | 7 | 实现并分析跳表结构。 8 | 9 | ### **基本要求** 10 | 11 | * 构造并实现跳表 ADT,跳表 ADT 中应包括初始化、查找、插入、删除指定关键字的元素、删除关键字最小的元素、删除关键字最大的元素等基本操作。生成测试数据并验证你所实现的跳表结构的正确性。 12 | 13 | 14 | 15 | * 分析各基本操作的时间复杂性。 16 | 17 | 18 | 19 | * 对跳表维护动态数据集合的效率进行实验验证。给定随机产生的 N 个数据并将其初始化为严格跳表,在此基础上进行一系列插入、删除、查找操作(操作序列可以随机生成),观察在操作序列执行后,跳表结构的改变对跳表各操作的执行时间的影响。 20 | 21 | * 可以设计如下实验: 22 | * 随机产生的 N 个数据并将其初始化为严格跳表;设定每个操作序列中包含插入、删除(包括删除指定关键字的元素、删除关键字最小的元素、删除关键字最大的元素)、查找操作的次数都是 K 次(操作数据随机生成),在初始跳表的基础上,依次执行M 个操作序列,统计每个操作序列中各个操作执行所需的平均时间(以元素的比较次数衡量),获得随着 M 的增加而导致的操作时间的变化情况。分析产生这样变化的原因。当操作时间大到一定程度后应进行跳表的整理操作,设计相应的整理算法,并从数量上确定何时较为合适。观察在添加整理操作后执行时间的变化情况。 23 | 24 | ### **程序正确性的验证** 25 | 26 | * 你需要设计程序验证你所实现的跳表的正确性,本次实验我们提供了示例数据集供你验证程序的正确性,数据集可以在此处下载。除了我们所提供的数据集,你也需要在自己生成的数据上验证程序的正确性。你可以通过如下工具比较输出文件是否一致: 27 | 28 | * Web Tools: https://text-compare.com/• 29 | 30 | * Windows: 在命令行中使用 FC 命令,FC file1 file2 31 | 32 | * OSX and Linux: 在终端中使用 diff 命令,diff file1 file2 33 | 34 | -------------------------------------------------------------------------------- /part2/README.md: -------------------------------------------------------------------------------- 1 | # 公交线路上的优化路径查询 2 | 3 | ## 问题描述 4 | 5 | 最短路径问题是图论中的一个经典问题,其中的Dijkstra算法一直被认为是图论中的好算法,但有的时候需要适当的调整Dijkstra算法才能完成多种不同的优化路径的查询。 6 | 7 | 对于某城市的公交线路,乘坐公交的顾客希望在这样的线路上实现各种优化路径的查询。设该城市的公交线路的输入格式为: 8 | 9 | 线路编号:起始站名(该站坐标);经过的站点1名(该站坐标);经过的站点2名(该站坐标);……;经过的站点n名(该站坐标);终点站名(该站坐标)。该线路的乘坐价钱。该线路平均经过多少时间来一辆。车速。 10 | 11 | 例如:63:A(32,45);B(76,45);C(76,90);……;N(100,100)。1元。5分钟。1/每分钟。 假定线路的乘坐价钱与乘坐站数无关,假定不考虑公交线路在路上的交通堵塞。对这样的公交线路,需要在其上进行的优化路径查询包括:任何两个站点之间最便宜的路径;任何两个站点之间最省时间的路径等等。 12 | 13 | ## 基本要求 14 | 15 | ① 根据上述公交线路的输入格式,定义并建立合适的图模型。 16 | 17 | ② 针对上述公交线路,能查询获得任何两个站点之间最便宜的路径,即输入站名S,T后,可以输出从S到T的最便宜的路径,输出格式为:线路x:站名S,…,站名M1;换乘线路x:站名M1,…,站名M2;…;换乘线路x:站名MK,…,站名T。共花费x元。 18 | 19 | ③ 针对上述公交线路,能查询获得任何两个站点之间最省时间的路径(不考虑在中间站等下一辆线路的等待时间),即输入站名S,T后,可以输出从S到T的考虑在中间站等下一辆线路的等待时间的最省时间的路径,输出格式为:线路x:站名S,…,站名M1;换乘线路x:站名M1,…,站名M2;…;换乘线路x:站名MK,…,站名T。共花费x时间。 20 | 21 | ④ 针对上述公交线路,能查询获得任何两个站点之间最省时间的路径(要考虑在中间站等下一辆线路的等待时间),即输入站名S,T后,可以输出从S到T的考虑在中间站等下一辆线路的等待时间的最省时间的路径,输出格式为:线路x:站名S,…,站名M1;换乘线路x:站名M1,…,站名M2;…;换乘线路x:站名MK,…,站名T。共花费x时间。 22 | 23 | 实现提示 :需深入考虑,应根据不同的应用目标,即不同的优化查询来建立合适的图模型。 24 | -------------------------------------------------------------------------------- /part2/busLine.md: -------------------------------------------------------------------------------- 1 | # **公交线路上的优化路径查询** 2 | 3 | ### **问题描述** 4 | 5 | * 最短路径问题是图论中的一个经典问题,其中的Dijkstra算法一直被认为是图论中的好算法,但有的时候需要适当的调整Dijkstra算法才能完成多种不同的优化路径的查询。 6 | 7 | * 对于某城市的公交线路,乘坐公交的顾客希望在这样的线路上实现各种优化路径的查询。设该城市的公交线路的输入格式为: 8 | 9 | 线路编号:起始站名(该站坐标);经过的站点1名(该站坐标);经过的站点2名(该站坐标);……;经过的站点n名(该站坐标);终点站名(该站坐标)。该线路的乘坐价钱。该线路平均经过多少时间来一辆。车速。 10 | 11 | * 例如:63:A(32,45);B(76,45);C(76,90);……;N(100,100)。1元。5分钟。1/每分钟。 假定线路的乘坐价钱与乘坐站数无关,假定不考虑公交线路在路上的交通堵塞。对这样的公交线路,需要在其上进行的优化路径查询包括:任何两个站点之间最便宜的路径;任何两个站点之间最省时间的路径等等。 12 | 13 | ### **基本要求:** 14 | 15 | * ① 根据上述公交线路的输入格式,定义并建立合适的图模型。 16 | * ② 针对上述公交线路,能查询获得任何两个站点之间最便宜的路径,即输入站名S,T后,可以输出从S到T的最便宜的路径,输出格式为:线路x:站名S,…,站名M1;换乘线路x:站名M1,…,站名M2;…;换乘线路x:站名MK,…,站名T。共花费x元。 17 | * ③ 针对上述公交线路,能查询获得任何两个站点之间最省时间的路径(不考虑在中间站等下一辆线路的等待时间),即输入站名S,T后,可以输出从S到T的考虑在中间站等下一辆线路的等待时间的最省时间的路径,输出格式为:线路x:站名S,…,站名M1;换乘线路x:站名M1,…,站名M2;…;换乘线路x:站名MK,…,站名T。共花费x时间。 18 | * ④ 针对上述公交线路,能查询获得任何两个站点之间最省时间的路径(要考虑在中间站等下一辆线路的等待时间),即输入站名S,T后,可以输出从S到T的考虑在中间站等下一辆线路的等待时间的最省时间的路径,输出格式为:线路x:站名S,…,站名M1;换乘线路x:站名M1,…,站名M2;…;换乘线路x:站名MK,…,站名T。共花费x时间。 19 | * 实现提示 :需深入考虑,应根据不同的应用目标,即不同的优化查询来建立合适的图模型。 -------------------------------------------------------------------------------- /part1/t2/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Lei 3 | * @Date: 2021-03-18 19:23:50 4 | * @LastEditors: Lei 5 | * @LastEditTime: 2021-03-18 20:05:59 6 | */ 7 | #include 8 | #include 9 | using namespace std; 10 | vector V; 11 | void make_dir(string folderPath) { 12 | // string folderPath = "input"; 13 | 14 | if (0 != access(folderPath.c_str(), 0)) { 15 | mkdir(folderPath.c_str()); 16 | } 17 | return; 18 | } 19 | void generate_data(string filename, int k = 0) { 20 | V.clear(); 21 | // string s = "input/data.txt"; 22 | ofstream outfile(filename); 23 | ostringstream outstring; 24 | srand(time(0) + k); 25 | int n = rand() % 23333 + k; 26 | // cout << n << '\n'; 27 | outstring << n << "\n"; 28 | for (int i = 0; i < n; i++) { 29 | V.push_back((rand() * rand() % 5000000)); 30 | outstring << V[i] << " "; 31 | } 32 | // string str = outstring.str(); 33 | outfile << outstring.str(); 34 | return; 35 | } 36 | void calculation_result(string filename) { 37 | // string s = "output/ans.txt"; 38 | sort(V.begin(), V.end()); 39 | ofstream outfile(filename); 40 | ostringstream outstring; 41 | for (auto &i : V) { 42 | outstring << i << " "; 43 | } 44 | outfile << outstring.str(); 45 | return; 46 | } 47 | int main() { 48 | make_dir("input"); 49 | make_dir("output"); 50 | int k = 1; 51 | cout << "Start generating data:\n"; 52 | for (int i = 1; i < 9; i++) { 53 | cout << "Generate " << to_string(i) << " set of data:\n"; 54 | string input = "input/data" + to_string(i) + ".in"; 55 | string output = "output/ans" + to_string(i) + ".out"; 56 | generate_data(input, k); 57 | calculation_result(output); 58 | k *= 10; 59 | } 60 | cout << "Generated\nGood luck!"; 61 | 62 | return 0; 63 | } -------------------------------------------------------------------------------- /part1/t3/catalogTree.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | struct TreeNode {//树节点 5 | TreeNode *parent;//父指针 6 | TreeNode *FirstChild;//第一个儿子指针 7 | TreeNode *brother;//兄弟指针 8 | bool isFile;//true表示文件,false表示目录 9 | char fileName[100];//用字符串存储树节点对应的文件或目录的名字 10 | int depth;//当前节点的深度 11 | int size;//当前节点的子文件数目 12 | }; 13 | typedef TreeNode *nowPosition;//当前位置 14 | typedef TreeNode *Tree;//树节点数组表示整个树 15 | typedef TreeNode *ptr;//指向树节点的指针 16 | 17 | class catalogTree; 18 | void findPath(catalogTree *a, nowPosition x);//根据位置寻找路径 19 | void deletePtr(catalogTree *a, ptr t);//根据位置删除 20 | 21 | class catalogTree {//目录树 22 | 23 | public: 24 | TreeNode *root;//根节点 25 | ptr nowPtr;//树节点指针,指向树中我们当前访问位置的树节点 26 | 27 | catalogTree();//构造函数 28 | ~catalogTree() {//析构函数 29 | deletePtr(this, root);//删除树的根节点及其n辈孩子节点 30 | }; 31 | void mkdir(char *name, nowPosition t);//在对应nowPosition创建对应名字的目录 32 | void mkfile(char *name, nowPosition t);//在对应nowPosition创建对应名字的文件 33 | void ListDir();//列出当前目录下的文件 34 | void Delete(char *str);//删除某文件或目录(通过给出相对路径/绝对路径) 35 | void cd();//打印当前目录的绝对路径 36 | void cdPath(char *str);//跳转到指定路径 37 | void cdFather();//跳转到父路径 38 | void saveCatalog(char *filename);//将目录结构保存至文件 39 | void loadCatalog(char *filename);//将目录结构从文件载入 40 | void print(nowPosition D, int Depth, FILE *file);//向文件打印出目录结构 41 | }; 42 | 43 | 44 | 45 | catalogTree::catalogTree() 46 | { //构造函数 47 | ptr tRoot = (TreeNode*)malloc(sizeof(TreeNode));//申请根节点空间 48 | tRoot->FirstChild = NULL; 49 | memset(tRoot->fileName, 0, sizeof(tRoot->fileName)); 50 | tRoot->fileName[0] = '/'; 51 | tRoot->isFile = false; 52 | tRoot->parent = NULL; 53 | tRoot->brother = NULL; 54 | tRoot->size = 0; 55 | root = tRoot; 56 | nowPtr = root;//当前路径为根目录(当前指针指向根节点) 57 | }; 58 | 59 | void catalogTree::print(nowPosition D, int Depth, FILE *file)//向文件打印出目录结构(save) 60 | { 61 | ptr tmp; 62 | if (D != NULL) { 63 | for (int i = 0; i < Depth; i++) { 64 | fprintf(file, "\t");//通过制表符演示目录结构 65 | } 66 | if (D->isFile == true) {//是文件 67 | fprintf(file, "%s .f\n", D->fileName); 68 | } 69 | else {//是目录 70 | fprintf(file, "%s .d\n", D->fileName); 71 | for (tmp = D->FirstChild; tmp != NULL; tmp = tmp->brother) 72 | { 73 | print(tmp, Depth + 1, file);//递归打印 74 | } 75 | } 76 | } 77 | } 78 | 79 | 80 | void catalogTree::saveCatalog(char *filename) {//将目录结构保存至文件 81 | FILE* file = fopen(filename, "w");//向文件中写入,即保存至文件 82 | if (file == NULL) { 83 | printf(" 文件打开失败\n"); 84 | return; 85 | } 86 | print(this->root, 0, file);//将目录结构存入文件 87 | fclose(file); 88 | } 89 | 90 | 91 | 92 | void inputCata(catalogTree *T, nowPosition D, char *preDir, int preDepth, FILE *file)//将文件中内容载入(load) 93 | { 94 | char buf[120]; 95 | char type[3]; 96 | char subBuf[100]; 97 | memset(buf, 0, sizeof(buf)); 98 | memset(type, 0, sizeof(type)); 99 | memset(subBuf, 0, sizeof(subBuf)); 100 | int i; 101 | int tmpNum = 0; 102 | fgets(buf, sizeof(buf), file);//一行一行载入数据 103 | if (strlen(buf) == 0) return;//如果读到文件末尾,结束 104 | strncpy(type, buf + strlen(buf) - 3, 2);//获取该行数据是文件还是目录 105 | for (i = 0; buf[i] == '\t'; i++) {//计算改行中有多少缩进,可以判断出哪一级的文件 106 | tmpNum++; 107 | } 108 | char * c = new char; 109 | if (i == 0) inputCata(T, D, c, 0, file);//如果没有缩进,则证明是第一行根路径 110 | 111 | else//不是根路径 112 | { 113 | strncpy(subBuf, buf + tmpNum, strlen(buf) - 4 - tmpNum);//获取该行中文件或目录的文件 114 | if (tmpNum > preDepth) {//如果该行中制表符缩进比上一行多,证明改行文件/目录为上一行目录的子文件 115 | T->cdPath(preDir);//改变当前指标为上一行目录 116 | } 117 | else if (tmpNum < preDepth) {//如果缩进小于上一行,每小一行,则当前指针做一次“回到上一路径”操作 118 | for (int j = tmpNum; j < preDepth; j++) { 119 | T->cdFather(); 120 | } 121 | } 122 | //默认深度与上一行文件/目录属于同一深度 123 | 124 | if (strcmp(type, ".d") == 0) {//如果是目录 125 | T->mkdir(subBuf, T->nowPtr); 126 | } 127 | else {//如果是文件 128 | T->mkfile(subBuf, T->nowPtr); 129 | } 130 | inputCata(T, T->nowPtr, subBuf, tmpNum, file);//进入下一行,递归输入 131 | 132 | } 133 | } 134 | 135 | 136 | void catalogTree::loadCatalog(char *filename) {//递归搜索当前位置的路径 137 | FILE *file = fopen(filename, "r"); 138 | if (file == NULL) { 139 | printf(" 文件打开失败,请检查文件名是否正确\n"); 140 | return; 141 | } 142 | inputCata(this, nowPtr, "/", 0, file);//调用input方法进行载入 143 | fclose(file); 144 | cdPath("/"); 145 | } 146 | 147 | //递归搜索当前位置的路径 148 | void findPath(catalogTree *a, nowPosition x) { 149 | if (x == a->root) { 150 | printf("/"); 151 | return; 152 | } 153 | else 154 | { 155 | findPath(a, x->parent); 156 | printf("%s/\n", x->fileName); 157 | } 158 | } 159 | 160 | void catalogTree::cd()//输出当前项的绝对路径 161 | { 162 | ptr x = nowPtr; 163 | findPath(this, x); 164 | } 165 | 166 | //根据给出的路径改变nowPtr,跳转到指定路径 167 | void catalogTree::cdPath(char *str) 168 | { 169 | ptr tmp; 170 | if (str[0] == '/') {//如果第一个字符为'/',证明是绝对路径 171 | ptr t = root; 172 | const char *d = "/"; 173 | char *p; 174 | p = strtok(str, d);//分隔字符串 175 | bool flag;//判断用户输入的路径或命令是否有错 176 | while (p) 177 | { 178 | flag = false; 179 | for (tmp = t->FirstChild; tmp != NULL; tmp = tmp->brother) { 180 | if (strcmp(tmp->fileName, p) == 0 && tmp->isFile == false) { 181 | t = tmp;//不断修改t的值,t不断趋近我们要cd的目录项 182 | flag = true; 183 | break; 184 | } 185 | } 186 | if (flag == false) {//如果为false,则用户输入的路径应该有错 187 | printf(" 没有该命令\n"); 188 | return; 189 | } 190 | p = strtok(NULL, d); 191 | } 192 | this->nowPtr = t;// 193 | } 194 | else {//相对路径 195 | 196 | const char *d = "/"; 197 | char *p; 198 | ptr t = nowPtr; 199 | p = strtok(str, d); 200 | bool flag;//判断用户输入的路径或命令是否有错 201 | while (p) 202 | { 203 | flag = false; 204 | for (tmp = t->FirstChild; tmp != NULL; tmp = tmp->brother) { 205 | if (strcmp(tmp->fileName, p) == 0 && tmp->isFile == false) { 206 | t = tmp;//不断更新当前路径,从当前目录项向下,到达目的项 207 | flag = true; 208 | break; 209 | } 210 | } 211 | if (flag == false) { 212 | printf(" 没有该命令\n"); 213 | return; 214 | } 215 | p = strtok(NULL, d); 216 | } 217 | nowPtr = t; 218 | } 219 | 220 | } 221 | 222 | void catalogTree::cdFather() {//cd.. 当前目录变为当前目录的父目录 223 | if (nowPtr == root) { 224 | printf("已到根路径!\n"); 225 | return; 226 | } 227 | nowPtr = nowPtr->parent; 228 | } 229 | 230 | void catalogTree::ListDir()//列出当前目录下所有文件,即当前目录项中所有文件或目录 231 | { 232 | nowPosition t = nowPtr; 233 | ptr tmp; 234 | for (tmp = t->FirstChild; tmp != NULL; tmp = tmp->brother) { 235 | if (tmp->isFile) { 236 | printf(" %s.f\n", tmp->fileName); 237 | } 238 | else { 239 | printf(" %s.d\n", tmp->fileName); 240 | } 241 | } 242 | } 243 | 244 | 245 | void deletePtr(catalogTree *a, ptr t) {//删除某个文件或目录,删除指针t对应的节点及其所有孩子 246 | ptr tmp; 247 | if (t->isFile) {//如果要删除的是文件 248 | tmp = t->parent->FirstChild; 249 | if (tmp == t) {//如果删除的文件是父亲的第一个儿子,将父亲的儿子指针指向该文件的兄弟,然后释放 250 | t->parent->FirstChild = tmp->brother; 251 | free(t); 252 | return; 253 | } 254 | 255 | //否则,删除的文件不是父亲的第一个儿子,执行链表的一般删除操作,找到该节点的位置,让该节点的前驱的兄弟指针指向删除结点的下一个兄弟,然后释放 256 | for (tmp = t->parent->FirstChild; tmp != NULL; tmp = tmp->brother) { 257 | if (t == tmp->brother) { 258 | tmp->brother = t->brother; 259 | free(t); 260 | return; 261 | } 262 | } 263 | } 264 | else {//如果要删除的是目录 265 | if (t->FirstChild == NULL) {//如果该目录下没有孩子(文件或目录),则直接删除 266 | if (t == a->root) return;//若要删除的是根节点,不执行删除,直接返回 267 | 268 | if (t->parent->FirstChild == t) {//如果该目录位于父亲节点的第一个儿子,则将父亲的儿子指针置为空,然后释放 269 | t->parent->FirstChild = t->brother; 270 | } 271 | else 272 | { 273 | for (tmp = t->parent->FirstChild; tmp != NULL; tmp = tmp->brother) {//如果不是第一个儿子,则找到该节点的前驱,将前驱的兄弟指针指向该节点的兄弟,然后释放该节点 274 | if (tmp->brother == t) { 275 | tmp->brother = t->brother; 276 | break; 277 | } 278 | } 279 | } 280 | free(t); 281 | } 282 | else {//如果该目录下有孩子(文件或目录),则访问下一层,再判断其孩子如何删除(并进行删除),如此,进行递归删除 283 | while (t->FirstChild != NULL) {//还没递归到目录树的最底层 284 | for (tmp = t->FirstChild; tmp != NULL; tmp = tmp->brother) {//访问下层链表, 285 | if (tmp->brother == NULL) { 286 | deletePtr(a, tmp);//递归删除,删除tmp节点及其n辈孩子节点 287 | break; 288 | } 289 | 290 | } 291 | } 292 | deletePtr(a, t);//最后删除它自己(在将其孩子孙子都删除后) 293 | } 294 | } 295 | } 296 | 297 | void catalogTree::Delete(char *str) {//删除 298 | 299 | //删除操作 300 | nowPosition t; 301 | bool flag = false; 302 | for (t = nowPtr->FirstChild; t != NULL; t = t->brother) { 303 | if (strcmp(t->fileName, str) == 0) { 304 | flag = true; 305 | break; 306 | } 307 | } 308 | if (flag == false) { 309 | printf(" 没有该目录或文件\n"); 310 | return; 311 | } 312 | deletePtr(this, t); 313 | 314 | } 315 | 316 | void catalogTree::mkdir(char *name, nowPosition t) {//创建文件夹 317 | 318 | ptr tmp; 319 | for (tmp = t->FirstChild; tmp != NULL; tmp = tmp->brother) { 320 | if (strcmp(tmp->fileName, name) == 0) {//&&tmp->isFile == false 321 | cout << " 不能产生相同名字的目录或文件,创建失败" << '\n'; 322 | return; 323 | } 324 | } 325 | 326 | tmp = (ptr)malloc(sizeof(struct TreeNode));//创建树节点 327 | tmp->parent = t; 328 | tmp->FirstChild = NULL; 329 | tmp->isFile = false;//false表示该节点为目录 330 | tmp->size = 0; 331 | strcpy(tmp->fileName, name); 332 | tmp->brother = t->FirstChild; 333 | t->FirstChild = tmp; 334 | 335 | } 336 | 337 | void catalogTree::mkfile(char *name, nowPosition t) {//创建文件 338 | ptr tmp; 339 | 340 | for (tmp = t->FirstChild; tmp != NULL; tmp = tmp->brother) { 341 | if (strcmp(tmp->fileName, name) == 0) {//&& tmp->isFile == true 342 | cout << " 不能产生相同名字的文件,创建失败" << '\n'; 343 | return; 344 | } 345 | } 346 | 347 | tmp = (ptr)malloc(sizeof(struct TreeNode));//创建树结点 348 | tmp->parent = t; 349 | tmp->FirstChild = NULL; 350 | tmp->isFile = true; 351 | tmp->size = 1; 352 | strcpy(tmp->fileName, name); 353 | tmp->brother = t->FirstChild; 354 | t->FirstChild = tmp; 355 | for (tmp = t; t != NULL; t = t->parent) { 356 | t->size++; 357 | } 358 | } --------------------------------------------------------------------------------