国家企业信用信息公示网查询系统网站编辑 seo
2026/1/24 10:13:06 网站建设 项目流程
国家企业信用信息公示网查询系统,网站编辑 seo,南宁希噢网站开发工作室,长沙专门做网站建设的公司《数据结构》课程设计报告 一、设计内容及其要求 资源管理器的模拟实现(A) 用树结构#xff0c;模拟实现资源管理器的功能#xff0c;包括#xff1a;文件夹的建立#xff1b;文件的增加#xff1b;文件的删除#xff1b;文件夹的删除。在此基础上增加了复制/移动/重命…《数据结构》课程设计报告一、设计内容及其要求资源管理器的模拟实现(A)用树结构模拟实现资源管理器的功能包括文件夹的建立文件的增加文件的删除文件夹的删除。在此基础上增加了复制/移动/重命名文件二、基本原理C/C 基本语法兄弟孩子法表示的多叉树的存储结构及其操作存储多叉树的链式栈的存储结构及其操作结构体指针的熟练使用文件读写操作双序确定一棵唯一二叉树Windows 命令行操作文件的命令三、具体设计方案设计说明、框图、流程图等设计说明:Ⅰ、需求分析用树结构设计一个资源管理器能够模拟资源管理器的基本功能如创建文件/文件夹删除文件/文件夹重命名文件/文件夹复制/移动文件查看文件/文件夹的路径等。输入的形式和输入值的范围程序的输入形式以字符串和整数为主字符串主要是输入文件夹/文件的名字而整数主要是定义文件的类型1 为文件夹类型2 为文件类型还有-1 是退出程序的命令。输出的形式输出的形式主要是字符串类型如执行完命令的提醒函数返回的文件路径函数输出的文件系统结构等都由字符串构成。程序所能达到的功能能够在程序内的文件树中模拟文件的操作过程结点的增加或删除代表文件的增加或删除在此基础上通过命令行将文件树的结构映射到系统盘中以实现在修改文件树的结点的同时会在操作系统中完成相应的操作实现真正能够管理部分系统文件的功能同时能够把程序的操作数据保存下来在程序下次启动时可以恢复上次操作完的状态以达到程序的循环重复使用。测试数据测试数据根据用户使用而定只要按照用户手册要求输入数据即可。Ⅱ、概要设计抽象数据类型typedef struct TreeNode { } TreeNode, *Tree; //定义存储文件系统的多叉树(兄弟孩子表示法) typedef struct Stack { } Stack, *LinkStack; //定义遍历多叉树需要用到的链式栈设计各程序模块及各模块之间的调用关系bool initStack(LinkStack S)//链栈的初始化 bool Push(LinkStack S, Tree T) //入栈 bool Pop(LinkStack S, Tree T) //出栈 bool getTop(LinkStack S, Tree T) //取栈顶元素 bool isStackEmpty(LinkStack S) //判断栈是否为空 void createFileSystem(Tree T) //建立文件系统创建文件树的根结点 void createNewTreeNode(Tree T, string name, int type, int level) //创建一个新结点用于初始化文件系统新建文件移动文件复制文件等操作。 bool initFilePath(Tree T) //初始化文件系统 创建文件树的必要结点 void saveFileSystem(Tree T) //保存文件系统数据到TXT文件中 void traverseFilePath(Tree T) //遍历文件系统并输出文件系统结构重载Tree findFileNode(Tree T, string filename) //在文件树上找到名为filename的文件夹用于查找、新建、删除、重命名、移动、复制文件等操作 Tree findFileNode(Tree T, string parentname, string filename) //在文件树上找到父母为parentname名为filename的文件用于查找、新建、删除、重命名、移动、复制文件等操作 Tree findFirstNextEmptyRoot(Tree T) //找到第一个nextSibling为空的根节点在插入创建新文件时要使用 bool checkSameName(Tree T, string filename, int type) //重名判别函数判定一个文件夹中是否已有同名文件在新建、移动、复制、重命名文件时要用到此函数重载string getFilePath(Tree T, string filename) //获取名为filename的文件夹在系统中的路径 string getFilePath(Tree T, string parentname,string filename) //获取父母为parentname名为filename的文件在系统中的路径 bool createNewFile(Tree T, string filename, string newfilename, int type) //创建一个新的文件/文件夹重载bool deleteFile(Tree T, string defilename) //删除名为defilename的文件夹 bool deleteFile(Tree T,string parentname, string defilename) //删除父母为parentname名为defilename的文件夹重载bool reNameFile(Tree T, string filename, string newfilename) //重命名名为filename的文件夹为newfilename bool reNameFile(Tree T, string parentname,string filename, string newfilename) //重命名父母为parentname名为filename的文件为newfilename bool lsFileChild(Tree T, string filename) //列出名为filename的文件夹下的所有文件 bool moveFile(Tree T, string mvparentname, string mvfilename, string tofilename) //移动父母为mvparentname名为mvparentname的文件到名为tofilename的文件夹中 bool copyFile(Tree T, string parentname, string cpfilename, string tofilename) //复制父母为parentname名为cpfilename的文件到名为tofilename的文件夹中 //从外存中读入文件系统树数据 void readFile() //利用读入的数据重建树 Tree readSystemFromTxt(MainData *preorder, MainData *midorder, int len) //将重建后的树的双亲和前驱还原 void connectPreParent(Tree T) void menu() //程序运行显示的菜单 void run(Tree T) //main函数的入口各模块之间的调用关系下页程序执行的流程图组员分工无。Ⅲ、详细设计抽象数据类型的具体实现typedef struct TreeNode { string fileName; //文件名 int fileType; //fileType为1代表文件夹 为0代表文件 根节点为文件夹类型 int nodeLevel; //存结点的层次注意并不是在树中的深度因为采用的是孩子兄弟表示法 存这个数主要是为了输出文件系统目录 struct TreeNode *pre; //前驱 struct TreeNode *parent; //父亲 struct TreeNode *firstChild; //第一个孩子 struct TreeNode *nextSibling; //下一个兄弟 } TreeNode, *Tree; typedef struct Stack { Tree data; struct Stack *next; } Stack, *LinkStack;主要操作的伪码算法bool createNewFile(Tree T, string filename, string newfilename, int type) // { TreeNode *p findFileNode(T, filename);//找到要新建的文件所在文件夹的指针 if(type 1 checkSameName(T, newfilename, type))//判别文件夹中是否有重名文件夹 { coutWarning:endl; cout文件系统中已存在名为 newfilename 的文件夹!endl; coutendl; return false; } else if(type 0 checkSameName(p, newfilename, type))//判别文件夹中是否有重名文件 { coutWarning:endl; cout文件夹中已存在名为 newfilename 的文件!endl; coutendl; return false; } if(p NULL) //指针等于空说明要新建的文件所在文件夹不存在 { cout文件夹不存在endl; return false; } else if(p-fileType 0) //结点的类型为文件文件下面不能再存储文件 { cout你不能在一个文件下创建文件请选择一个文件夹!endl; return false; } int level p-nodeLevel1; //新建分两种情况 if(p-firstChild NULL) //第一种情况文件夹是空的即文件夹的firstChild为空直接创建 { createNewTreeNode(p-firstChild, newfilename, type, level); //新建一个结点 //修改指针 p-firstChild-pre p; p-firstChild-parent p; } else //第二种情况文件夹不是空的要找到一个兄弟的下一个兄弟为空的结点然后创建 { TreeNode *q findFirstNextEmptyRoot(p); //找到第一个兄弟的下一个兄弟为空的结点 createNewTreeNode(q-nextSibling, newfilename, type, level);//新建一个结点 //修改指针 q-nextSibling-pre q; q-nextSibling-parent p; } string path getFilePath(T, filename,newfilename); //获得新建文件的路径 string cdcmd path.substr(8, 1):; //cdcmd为切换盘符的命令 system(cdcmd.c_str()); //在命令行中执行 if(type 1) //创建文件夹 { string cmd mkdir path.substr(8, path.length()-8); //mkdir为cmd中创建文件的命令 system(cmd.c_str()); 在命令行中执行 } else if(type 0) //创建文本文件 { string cmd type nulpath.substr(8, path.length()-8).txt; // type nul为cmd中创建文本文件的命令 system(cmd.c_str()); //在命令行中执行 } return true; //创建成功 返回true } bool deleteFile(Tree T, string defilename) //删除文件夹 { if(defilename D: || defilename E: || defilename F) //不允许删除D E: F:盘符 { cout禁止删除的文件夹!!endl; return false; } TreeNode *p findFileNode(T, defilename); //找到要删除的文件夹所在的结点 if(p NULL) //如果指针为空说明要删除的文件夹不存在 { cout要删除的文件不存在!endl; //删除文件夹时给予适当的提醒 string ensure; cout你选择删除的是一个文件夹你确定要这么做吗如果这么做的话该文件夹下的文件和文件夹将都被删除!endl; cout如果你依然要这么做请输入yes如果你要放弃操作请输入no:; cinensure; if(ensure no) return false; string path getFilePath(T, defilename); //拿到文件夹的路径 string cdcmd path.substr(8, 1):; //cd切换盘符 system(cdcmd.c_str()); //cmd中执行命令 LinkStack S; initStack(S); //初始化存储该文件夹的所有孩子的链式栈 Tree rootDel p; Tree tmp; if(p-firstChild ! NULL) //把该文件夹下所有结点压入栈 { Push(S, p-firstChild); p-firstChild; while(p-nextSibling ! NULL) { Push(S, p-nextSibling); p-nextSibling; } } while(!isStackEmpty(S)) //递归删除文件夹下的所有文件及文件夹 { Pop(S, tmp); if(tmp-fileType 1) deleteFile(T, tmp-fileName); else deleteFile(T, rootDel-fileName,tmp-fileName); } //最后执行删除该文件夹的操作 分两种情况 if(rootDel-pre-firstChild rootDel) //情况1 .删除文件夹结点的前驱是该文件夹结点的父母 { //修改相应指针并删除该结点 rootDel-pre-firstChild rootDel-nextSibling; if(rootDel-nextSibling ! NULL) rootDel-nextSibling-pre rootDel-pre; delete(rootDel); } else //情况2. 删除文件夹结点的前驱是该文件夹结点的兄弟 //修改相应指针并删除该结点 rootDel-pre-nextSibling rootDel-nextSibling; if(rootDel-nextSibling !NULL) rootDel-nextSibling-pre rootDel-pre; delete(rootDel); } string cmd rmdir /s path.substr(8, path.length()-8); //rmdir 为cmd中递归删除文件夹的命令 system(cmd.c_str()); //执行递归删除文件夹的命令 return true; //删除文件夹成功返回true } bool deleteFile(Tree T,string parentname, string defilename) //删除文件 { TreeNode *p findFileNode(T, parentname,defilename); //找到要删除的文件结点 if(p NULL) //若指针为空说明要删除的文件不存在 { cout要删除的文件不存在!endl; } string path getFilePath(T, parentname,defilename); //获取该文件的路径 string cdcmd path.substr(8, 1):; //切换盘符的命令 system(cdcmd.c_str()); //在cmd中执行切换盘符的命令 string cmd del path.substr(8, path.length()-8).txt; //del为cmd中删除文件的命令 system(cmd.c_str()); //在cmd中执行删除文件的命令 //在树中删除该文件结点 分两种情况 if(p-pre-firstChild p) //情况1. 删除文件夹结点的前驱是该文件夹结点的父母 { //修改相应指针并删除该结点 p-pre-firstChild p-nextSibling; if(p-nextSibling ! NULL) p-nextSibling-pre p-pre; delete(p); } else //情况2. 删除文件夹结点的前驱是该文件夹结点的兄弟 { //修改相应指针并删除该结点 p-pre-nextSibling p-nextSibling; if(p-nextSibling ! NULL) p-nextSibling-pre p-pre; delete(p); } return true; } //从外存中读入文件系统树数据 void readFile() { preorder new MainData[100]; midorder new MainData[100]; ifstream infile(fileone.txt); if(!infile) cerr文件打开失败; int k 0; while(!infile.eof()) { infilemidorder[k].filenamemidorder[k].fileTypemidorder[k].nodeLevel; k; } infile.close(); ifstream input(filetwo.txt); if(!input) cerr文件打开失败; int j 0; while(!input.eof()) { inputpreorder[j].filenamepreorder[j].fileTypepreorder[j].nodeLevel; j; } input.close(); LEN k-1; } //利用读入的数据重建树 Tree readSystemFromTxt(MainData *preorder, MainData *midorder, int len) { MainData rootKey preorder[0]; Tree root new TreeNode; root-fileName rootKey.filename; root-fileType rootKey.fileType; root-nodeLevel rootKey.nodeLevel; root-firstChild NULL; root-nextSibling NULL; root-parent NULL; root-pre NULL; if(len 1 preorder-filename midorder-filename) return root; MainData *rootMidOrder midorder; int leftLen 0; while(rootMidOrder-filename ! rootKey.filename rootMidOrder (midorderlen-1)) { rootMidOrder; leftLen; } //if(rootMidOrder-filename ! rootKey.filename ) return NULL; //error if(leftLen 0) { root-firstChild readSystemFromTxt(preorder1, midorder, leftLen); } if(len-leftLen-1 0) { root-nextSibling readSystemFromTxt(preorderleftLen1, rootMidOrder1, len-leftLen-1); } return root; } //将重建后的树的双亲和前驱还原 void connectPreParent(Tree T) { LinkStack S; initStack(S); TreeNode *par; TreeNode *now; TreeNode *prenow; TreeNode *p T; TreeNode *q new TreeNode; while(p || !isStackEmpty(S)) { if(p) { Push(S, p); par p; if(p-firstChild ! NULL) { p-firstChild-parent par; p-firstChild-pre p; now p-firstChild; while(now-nextSibling ! NULL) { prenow now; now now-nextSibling; now-parent par; now-pre prenow; } } p-firstChild; } else { Pop(S, q); q-nextSibling; } } } //以上只给了创建和删除以及缓存数据相关的代码其它的详见源码文件函数和过程的调用关系图Ⅳ、调试分析实现过程中遇到的问题及产生的思考如何存储文件系统易于操作 答多叉树与文件系统的结构是非常相似的但是一般的多叉树不易于存储和操作所以选择兄弟孩子树来存储多叉树。这样的话一个根节点就是一个文件夹而他的孩子以及他的孩子的兄弟就是它下面的文件结构清晰明了。怎么区分文件系统中的文件和文件夹 答很容易知道文件和文件夹在文件系统中的操作是截然不同的比如要创建一个文件这个文件只能放在一个文件夹下而不能放在一个文件下再比如要删除一个文件只需要找到它并删除就可以了但是要删除一个文件夹就要先把它目录下的所有文件及文件夹删除掉再删除这个文件夹很显然这是一个递归的过程。所以在定义文件树结点的时候引入了 type 这一变量当这个变量等于 1 时文件的类型为文件夹当这个变量等于 0 时文件的类型为文件这样对文件的类型加以区分以后再分别对文件和文件夹进行创建、删除等操作。怎么避免文件系统中的重名问题 答当你要在一个文件夹中创建文件时如果这个文件夹中已经有一个同名的文件就会造成查找文件时的文件不唯一的错误所以要保证每个文件夹中不能有重名文件。为此引入 checkSameName()函数在执行创建、移动、复制时要首先检查该文件夹目录下是否已存在重名文件。怎么去遍历整个文件系统并把文件系统的结构输出 答对兄弟孩子树采用先序非递归的方式去遍历即可这里不采用递归的方式的原因是如果单纯的输出每个结点的名称是体现不出文件系统的结构的因此我在程序中增加了控制文件系统层次的循环要在函数中插入这个循环最好是采用非递归的方式去遍历因为非递归方式的遍历比较好控制。还有就是这个循环要借助于文件结点的 nodeLevel 来实现nodeLevel 及此结点在文件系统结构中的层次比如第一级文件夹的层次为 1而它内部的文件和文件夹的层次为 2…以此类推。在创建新文件时要注意的问题 答首先如果要新建文件的文件夹存在的话第一步要执行判重操作也就是判断该文件夹下是否有重名函数如果没有则要考虑接下来的两种情况1.该文件夹目前是空的 2.该文件夹目前不是空的 如果是情况的话说明该文件的 firstchild 是空的插入到此位置即可如果是情况二则要先找到该文件结点的孩子的第一个兄弟为空的兄弟结点在此位置插入新的文件结点。在删除文件或文件夹时要注意的问题 答比较特殊的情况是删除文件夹的操作之前提到过删除文件夹要先删除该文件夹下的所有文件及文件夹然后再删除这个文件这是一个递归的过程。刚开始我犯了个错误就是直接删除了这个文件夹结点这样的后果就是这个文件夹结点的兄弟结点也被我删掉了这是肯定不行的因为我只想删除该文件夹结点的孩子和孩子的兄弟。于是我在函数中引入了一个栈来实现递归删除文件夹在删除文件夹时首先让它的孩子和孩子的兄弟入栈然后出栈递归删除它们最后删除根节点也就是要删除的该文件结点在删除根节点时还要注意分两种情况1.根节点的前驱是根节点的父亲 2.根节点的前驱是根节点的兄弟这里就又蹦出一个问题就是要保存结点的前驱因为在删除结点时要修改它的前驱结点而它的前驱结点可不一定是它的父母因此在文件树的定义中引入 pre 指针存储结点的前驱 根据这两种情况来修改指针在删除普通文件时同样要考虑这两种情况不过不用考虑递归删除的问题了。有一个问题就是如果我在系统中进行了一系列操作以后当我退出程序后程序中的文件树就没了这样下次再运行程序就又是一个新的文件系统这样的可用性是非常差的于是我就想能不能有一种办法将文件系统树的数据保存下来在下次运行程序时能够恢复上次运行的状态可不可行呢 答解决这个问题的关键就是兄弟孩子树的指针我如何保存呢想把指针存到 txt 文本文件里是不现实的所以只能通过复盘的方式将原来的兄弟孩子树重建。首先用到的第一个理论是根据二叉树的先序遍历和中序遍历可以确定唯一的一棵二叉树兄弟孩子树通过这个理论我就可以将原来兄弟孩子树的 firstChild 和 nextSibling 指针恢复了。还有一个问题没有解决那就是文件系统树中有前驱和双亲两个指针并且这两个指针是非常重要的如何将他们恢复到原来的状态呢既然我已经恢复了唯一确定的一棵二叉树兄弟孩子树那么他们的前驱和双亲也是确定的只要想出一种策略将他们恢复即可我的思路就是让每个根结点和它的 firstChild 以及 firstChild 的 nextSibling 们根据前驱和双亲的特点来非递归恢复。实现函数为 void connectPreParent(Tree T)。改进设想虽然兄弟孩子树表示的文件系统结构很清晰明了但是缺点也很明显由这种结构构成的文件系统的树太高了树太高会直接影响文件的查询速度进而影响各个操作的执行时间因此找一种更合适的树来存储文件系统会更好我想的是 B-树这种树也是多叉树和文件系统的结构很像而 B-树的阶数可以代表每个文件下最多存储的文件个数但是 B-树并不只是这么简单它还是一颗平衡树也就是说在新建、删除的过程中B-树的结构是不断调整的这就产生了一个问题在调整过程中文件的位置会改变因此不能用 B-树直接存储文件系统而是用 B-树建立文件索引然后去存储文件系统但是我现在的能力还有限不能把目前的系统迁移只是先实现了 B-树的各个操作代码附在附录中等我有能力实现了我会再完善这个系统。经验和体会在调试的过程中加固了对指针的操作的理解特别是对多个指针同时修改时的操作以前感觉操作两三个指针就要晕了但是对指针的操作深入理解之后我感觉指针的操作也没有想象中的那么复杂。做这个程序我最大的体会就是要有明确的目标和解决问题的方向比如要做一个特定功能的函数要先确定这个函数最后能够实现什么效果然后再去考虑这个函数的内部细节尽量考虑全面如果在调试过程中发现问题从纸上把过程画出来考虑是哪个环节出了问题然后去检查代码这样的方式是比较有效的。如果还是分析不出来可以用高级的 IDE 进行逐步调试跟着代码一步一步走总能找出问题的关键所在。四、设计小结本次课程设计选择了资源管理器这个题目感觉难度适中刚开始是先做出了一个纯模拟系统只能在命令行中看看文字不能完成实际的操作在老师指导后老师建议我能够实现真正操作系统中的文件我想了想感觉单纯的在命令行中显示操作确实过于枯燥了没有什么实际作用。于是我在原版代码的基础上实现了程序与 windows 文件系统的连接连接方式是我们常用的命令行。实现以后在程序中的操作会对应到实际的系统中去能够简单模拟资源管理器的功能如创建、删除、重命名、复制、移动等操作这样有些操作就不用到我的电脑里去操作了也不用到命令行中去操作了可以在这个程序中直接按照指令输入命令执行命令完成文件系统的操作同时能够查看程序中创建的文件系统的目录结构和信息有一定的可操作性。再后来我感觉这个系统的功能虽然比较完善了但是复用性太低了只能当个摆设于是我在最后实现了系统的数据保存以达到循环使用的目的。这也是我第一次写单个 C 程序超过了 1000 行代码其实在写的过程中并没有感觉到写完后发现居然有这么多了。在写的过程中碰到了很多困难每当通过自己的努力解决一个困难那种愉悦的心情是无法形容的。本次课程设计结束后我更深刻的理解了 C/C 的一些语法以及树和栈等数据结构并能够用一些数据结构去解决实际的问题从理论到实践大概就是这样一个过程。最后我认识到了数据结构这门课对于计算机专业学生的重要性它表面上看起来枯燥乏味但如果真的去用这些东西去解决一些困难的问题时会发现它就是你解决问题的利器。五、设计附录数据、图纸等Ⅰ、用户使用说明程序运行后界面如图所示你需要按照界面中显示的命令去输入请不要输入错误的指令那是无效的。比如你要创建一个新文件就输入 new 然后敲回车键 就会跳转到创建新文件的界面你需要根据界面上的提示来输入请严格按照界面中提示的规定输入尽管我在程序中加入了很多判断语句来阻止错误的输入但是我的考虑肯定是不周全的你要避免程序出现未知的崩溃一般情况下输入的字符串都是以空格隔开的当你输入完毕后敲回车键执行。Ⅱ、简单的测试使用演示下面演示创建一个新的文件夹和一个新的文件的操作首先运行源码出现用户使用说明中的界面输入 new 回车 进入新建文件界面在新建文件界面按照指令输入并执行这时打开我的电脑打开 E 盘会发现在 E 盘下新建了文件夹 TESTfile输入 r 返回然后再输入 new进入新建文件界面按照指令输入在刚才创建的文件夹 TESTfile 下创建一个新文件 t1输入完毕后回车执行此时在我的电脑中打开刚才创建的文件夹 TESTfile会发现里面有一个 t1.txt 文件接着又执行了在 TESTfile 文件夹中创建 t2.txt,t3.txt然后删除了刚才创建的 t1.txt 后的状态。输入任意字符返回后输入-1 正常退出程序以保证数据能够保存到外存中以供下次运行时读入。再次运行程序输入 check可以发现系统恢复了上次运行结束后的状态你可以接着上次继续进行你的操作。以上即为该程序的简单使用测试。继续使用的话只要严格按照程序给出的指令操作即可。Ⅲ、源程序资源管理器源代码在文件 SourceCode 中名为资源管理器 Source Manager-v1.0.cpp另外在 SourceCode 中还附上了 B-树的实现代码这是可能的一种改良该系统执行速度的方案。六、参考资料数据结构 C 语言版第二版--严蔚敏 李冬梅 吴伟民C 语言程序设计第二版C Primer Plus(第四版)Windows Command Prompt 命令用法♻️ 资源大小513KB➡️资源下载https://download.csdn.net/download/s1t16/87400399注更多内容可关注微信公众号【神仙别闹】如当前文章或代码侵犯了您的权益请私信作者删除

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询