当前位置: 首页 > news >正文

1.7.课设实验-数据结构-二叉树-文件夹创建系统

一.题目:

利用二叉树简单理解文件夹创建的过程。

二.代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>//二叉树结构体 
typedef struct BiTNode
{//1.结点即文件夹名称char nameFileNode[50];//2.左、右孩子指针即子目录 struct BiTNode *lchild;struct BiTNode *rchild;//3.父指针即父级目录 struct BiTNode *parent; 
}BiTNode,*BiTree;//单个文件夹在顺序表中的数据 
typedef struct
{//1.文件夹名称char nameFile[50];//2.文件夹的父级路径的索引int parentIndex; 
}FileData; //存储二叉树即文件夹的顺序表->长度采用动态变化 
typedef struct 
{//1.指向动态数组的指针->表示连续存储的空间 FileData *data;//2.顺序表中当前文件夹个数    int numFile; //3.动态数组当前数组最大容量        int capacity;      
}FileList;/*---------------------------------------赵旭文---------------------------------------*/
//求文件夹二叉树的树高的函数
int treeDepth(BiTree T)
{if(T==NULL){return 0;}else{int l = treeDepth(T->lchild);int r = treeDepth(T->rchild);return l > r ? l+1 : r+1;}
} //查找父级目录在文件夹顺序表中的位置的函数
/*形参需要文件夹顺序表、父指针指向的文件夹*/ 
/*返回父级目录在文件夹顺序表中的索引*/ 
int findParent(FileList list,BiTNode *parent)
{//特殊情况即根结点->只有根结点的父指针为NULL if(parent == NULL) {return -1;  // 根节点的父节点索引为-1 }//1.遍历文件夹顺序表查找是否有与父指针指向的文件夹同名的文件夹for( int i=0 ; i<list.capacity ; i++ ){//2.判断当前索引上的文件夹与父指针指向的文件夹是否同名int result = strcmp( list.data[i].nameFile , parent->nameFileNode );//3.结果if(result==0){//4.查找成功,返回索引return i; } } //5.查找失败,返回-1return -1; 
}
/*---------------------------------------赵旭文---------------------------------------*//*---------------------------------------黄黄---------------------------------------*/
//添加文件夹到文件夹顺序表的函数
/*形参包括文件夹顺序表、插入的文件夹名称(插入到顺序表)、文件夹二叉树(用来求扩容常量)、插入的文件夹(找父级路径)*/
void InsertFileData(FileList &list,char name[50],BiTree T,BiTNode file)
{//1.把文件夹放入文件夹顺序表的最后一位(刚好就是list.numFile,比如0个文件夹时新添加一个就在0索引)strcpy( list.data[ list.numFile ].nameFile , name );  //2.补全刚放入的文件夹的父级目录的索引/*2.1.调用函数findParent查找父级目录在文件夹顺序表中的索引*/int index= findParent( list , file.parent );/*2.2.赋值*/list.data[ list.numFile ].parentIndex = index;//3.文件夹顺序表的文件夹数量加1 list.numFile++;//4.文件夹顺序表扩容/*4.1.求文件夹二叉树的高度*/int height=treeDepth(T);/*4.2.得出扩容结果*///list.capacity = list.capacity + pow(2,height);这里只改变了capacity,但没有重新分配内存(会出现主函数崩溃),正确如下://得出新的扩容结果并记录int newCapacity = list.capacity + pow(2, height); /*调用realloc函数,第一个参数就是先前获得的内存块,第二个参数就是新扩容的内存块,如果需要还会复制旧内存块的内容*/   FileData *newData = (FileData*)realloc( list.data, sizeof(FileData) * newCapacity );//判断 if(newData!=NULL) {//此时成功分配 list.data = newData; //记录新的扩容结果 list.capacity = newCapacity; //记录扩容后的长度 } 
} 	 // 创建文件夹(结点)即插入结点到二叉树的函数
/*形参需要文件夹二叉树、新插入的文件夹名称、文件夹顺序表*/
void creatFile(BiTree &T, char inputFile[50],FileList &list)
{//1.判空 if(T == NULL) return;//2.在文件夹二叉树中找到要插入的位置,判断是否创建在当前文件夹的子目录下printf("当前文件夹:%s \n", T->nameFileNode);printf("请选择创建位置(1.左子目录 2.右子目录 3.取消创建):");int result;scanf("%d", &result);  //3.判断 if(result == 1) {//4.创建在左目录下if(T->lchild == NULL) //左子目录为空,可直接创建 {//4.1.先给T的左孩子分配内存空间T->lchild = (BiTree)malloc(sizeof(BiTNode));//4.2.判断 if( T->lchild == NULL) /*内存分配失败*/{printf("内存分配失败!\n");return;}else /*内存分配成功*/{strcpy(T->lchild->nameFileNode, inputFile); //初始化新节点T->lchild->lchild = NULL; //设置左指针 T->lchild->rchild = NULL; //设置右指针 T->lchild->parent = T;  //设置父指针printf("文件夹 '%s' 创建成功!\n", inputFile);InsertFileData(list, inputFile, T , *(T->lchild)); //添加到顺序表中.第四个形参是插入的文件夹即左孩子上 }} else //左子目录不为空,需递归 {printf("左子目录已存在,递归创建...\n");creatFile(T->lchild, inputFile , list);}} else if(result == 2) {//5.创建在右目录下if(T->rchild == NULL) //右子目录为空,可直接创建{//5.1.先给T的右孩子分配内存空间T->rchild = (BiTree)malloc(sizeof(BiTNode));//5.2.判断 if(T->rchild == NULL) /*内存分配失败*/{printf("内存分配失败!\n");return;}else /*内存分配成功*/{strcpy(T->rchild->nameFileNode, inputFile); // 初始化新节点T->rchild->lchild = NULL; //设置左指针T->rchild->rchild = NULL; //设置右指针T->rchild->parent = T;  // 设置父指针printf("文件夹 '%s' 创建成功!\n", inputFile);InsertFileData(list, inputFile, T , *(T->rchild)); // 添加到顺序表中}} else //右子目录不为空,需递归 {printf("右子目录已存在,递归创建...\n");creatFile(T->rchild, inputFile, list);}}else {//6.取消创建 printf("取消创建操作。\n");return;}
}
/*---------------------------------------黄黄---------------------------------------*//*---------------------------------------青格勒---------------------------------------*/
//删除文件夹(结点)即删除二叉树中结点的函数->1次只删1个文件夹,删两个会出现父级路径和子文件夹都删了  
/*形参需要文件夹二叉树、要删除的文件夹名称、文件夹顺序表*/
void deleteFile(BiTree &T, char deleteFileName[50], FileList &list)
{// 1.首先在顺序表中查找要删除的文件夹int deleteIndex = -1;for(int i = 0; i < list.numFile; i++){if( strcmp(list.data[i].nameFile, deleteFileName) == 0){//代表查找成功 deleteIndex = i;break;}}// 2.如果未找到,直接返回if(deleteIndex == -1){printf("删除失败,文件夹 '%s' 不存在!\n", deleteFileName);return;}//3.在二叉树中查找要删除的结点 BiTree deleteNode = NULL; //要删除的结点即要删除的文件夹 BiTree parentNode = NULL; //要删除的文件夹的父级路径 int isLeftChild = 0; // 0:不是左孩子 1:是左孩子//3.1.使用层次遍历查找要删除的节点->使用到了队列->类似线性查找 BiTree queue[100]; //队列->长度为100,类型为文件夹二叉树 int front = 0, rear = 0; //front为头指针,rear为尾指针 queue[rear++] = T; //初始时访问根结点,根结点T入队->注:是先赋值,再rear++(rear++得出的rear就指向了下一个插入的位置) //3.2.循环遍历文件夹二叉树->只要头指针小于尾指针,就说明队列里有文件夹,就需要继续处理 while(front < rear){//3.2.先处理头指针,把头指针设为当前处理的文件夹current,然后front++(代表下次处理后一个文件夹) BiTree current = queue[front++];//3.3.对比当前处理的文件夹与要删除的文件夹是否同名 if( strcmp(current->nameFileNode, deleteFileName) == 0){//3.4.找到了要删除的文件夹,赋值给deleteNode,并跳出循环 deleteNode = current;break;}//3.4.此时意味着没有找到要删除的文件夹,让其左子树、右子树依次入队列进行查找 if(current->lchild != NULL){//先赋值,再rear++ queue[rear++] = current->lchild;}if(current->rchild != NULL){//先赋值,再rear++ queue[rear++] = current->rchild;}}//3.5.判空 if(deleteNode == NULL){printf("删除失败,在二叉树中未找到文件夹 '%s'!\n", deleteFileName);return;}//4.获取父节点信息parentNode = deleteNode->parent;//4.1.判空 if(parentNode != NULL){//4.2.父结点不为空 if(parentNode->lchild == deleteNode){//4.3.意味着要删除的文件夹deleteNode在其父级路径的左孩子上 isLeftChild = 1;}else{//4.4.意味着要删除的文件夹deleteNode在其父级路径的右孩子上isLeftChild = 0;}}//5.检查要删除的节点是否有子节点if(deleteNode->lchild != NULL || deleteNode->rchild != NULL){printf("删除失败,文件夹 '%s' 包含子文件夹,请先删除子文件夹!\n", deleteFileName);return;}//6.从二叉树中删除节点//6.1.删除的是根节点if(parentNode == NULL) {printf("警告:正在删除根节点!\n");free(T);T = NULL;}else //6.2.删除非根节点{if(isLeftChild){//6.3.此时说明要删除是父级路径的左子树 parentNode->lchild = NULL;}else{//6.4.此时说明要删除是父级路径的右子树 parentNode->rchild = NULL;}//6.5.清空 free(deleteNode);}//7.从顺序表中删除对应的文件夹数据//7.1 首先删除所有以该文件夹为父节点的子文件夹for(int i = 0; i < list.numFile; i++){//7.2.找到了孤立的文件夹 if(list.data[i].parentIndex == deleteIndex){printf("警告:发现孤立的子文件夹 '%s',正在清理...\n", list.data[i].nameFile);}}//7.3.移动顺序表中的文件夹,覆盖要删除的元素(删除最后1个文件夹时无需移动)for(int i = deleteIndex; i < list.numFile - 1; i++){//7.4.把后一个文件夹移动到当前文件夹 strcpy(list.data[i].nameFile, list.data[i + 1].nameFile);//7.5.更改父级路径索引 list.data[i].parentIndex = list.data[i + 1].parentIndex;//7.6.更新父索引:如果父索引大于删除索引,需要减1->减1才能移动指向前1位(因为删除了1个文件夹) if(list.data[i].parentIndex > deleteIndex){list.data[i].parentIndex--;}}// 7.3 更新顺序表计数即顺序表中文件夹个数减1 list.numFile--;// 8.更新所有父索引指向被删除节点的子节点->遍历查找是否有父索引等于删除索引的for(int i = 0; i < list.numFile; i++){//8.1.找到了父索引指向删除索引的 if(list.data[i].parentIndex == deleteIndex){//8.2.设置为根节点或无父节点list.data[i].parentIndex = -1; printf("警告:文件夹 '%s' 的父文件夹已被删除,已将其父索引重置\n", list.data[i].nameFile);}}printf("文件夹 '%s' 删除成功!\n", deleteFileName);// 9.打印删除后的顺序表状态(用于调试)printf("删除后顺序表状态:\n");for(int i = 0; i < list.numFile; i++){printf("索引%d: 名称为%s, 父索引为%d\n", i, list.data[i].nameFile, list.data[i].parentIndex);}
}//带交互的删除函数包装器->进入删除操作的函数 
void deleteFileInteractive(BiTree &T, FileList &list)
{//1.判空 if(list.numFile == 0){printf("当前没有文件夹可删除!\n");return;}//2.此时文件夹顺序表不为空,打印 printf("当前所有文件夹:\n");for(int i = 0; i < list.numFile; i++){//2.1.打印当前文件夹名称 printf("%d. %s", i + 1, list.data[i].nameFile);//2.2.打印当前文件夹的父级路径->根结点无需打印父级路径 if(list.data[i].parentIndex != -1){printf(" (父文件夹: %s)", list.data[list.data[i].parentIndex].nameFile);}printf("\n");}//3.输入要删除的文件夹的名称 printf("请输入要删除的文件夹名称:");char deleteFileName[50];scanf("%s", deleteFileName);//4.调用deleteFile函数进行删除 deleteFile(T, deleteFileName, list);
}
/*---------------------------------------青格勒---------------------------------------*//*---------------------------------------吴佳峻---------------------------------------*/
//查找文件夹(结点)的函数
/*形参需要文件夹顺序表、要查找的文件夹的名称*/
void findFile(FileList list,char findFileName[50])
{//1.遍历顺序表查找是否存在 for( int i = 0; i < list.numFile; i++ ){//2.记录对比结果 int result = strcmp( list.data[i].nameFile , findFileName);//3.判断 if(result == 0) /*查找成功->找出当前文件夹完整路径*/{printf("找到文件夹 '%s'\n", findFileName);// 3.1.构建路径栈->打印完整路径,用栈,因为最后找到磁盘,但磁盘先打印,为栈 char pathStack[100][50]; // 存储路径组件int stackTop = 0;// 3.2.当前文件夹入栈strcpy( pathStack[stackTop], list.data[i].nameFile);stackTop++;// 3.3.回溯父路径int fatherIndex = list.data[i].parentIndex; //记录父级文件夹索引 while(fatherIndex != -1) //等于-1时意味着找到根目录,停止循环{strcpy( pathStack[stackTop], list.data[fatherIndex].nameFile);stackTop++;fatherIndex = list.data[fatherIndex].parentIndex;}// 3.4.从根节点开始拼接完整路径printf("完整路径: ");for(int j = stackTop - 1; j >= 0; j--) //从栈顶开始 {printf("%s", pathStack[j]);if(j > 0) printf("\\");}printf("\n");return;}}// 4.查找失败printf("查找失败,该文件夹 '%s' 不存在\n", findFileName);
} //初始化文件夹顺序表的函数
void initFileList(FileList *list, int capacity) 
{//1.创建连续的存储空间 list->data = (FileData*)malloc(sizeof(FileData) * capacity);//2.初始时顺序表没有任何文件夹 list->numFile = 0;//3.初始动态数组当前最大容量  list->capacity = capacity;
}//初始化文件夹二叉树的函数
void initBiTree(BiTree &T,FileList &list) //不是BiTree *T,而是BiTree &T,传地址 
{//1.申请根结点存储空间->根结点为结点,用BiTNode申请空间,最终要是BiTree型即树 T = (BiTree)malloc( sizeof(BiTNode) );//2.根结点赋值strcpy( T->nameFileNode , "D盘" );//3.一开始只有根结点,根结点的初始左、右孩子指针都为NULLT->lchild = NULL;T->rchild = NULL;//4.根结点的父指针指向NULLT->parent = NULL; //5.把根结点放入文件夹顺序表/*对于根结点需要特殊处理,在InsertFileData函数中第四个参数BiTNode parent是BiTNode型,因此传第四个参数时不能直接传T,因为T是BiTree型,由于此时是根结点,父指针必为NULL,所以可以定义一个BiTNode类型的变量,让其父指针为NULL*/BiTNode parentT;parentT.parent = NULL; InsertFileData(list,T->nameFileNode,T,parentT);
} 
/*---------------------------------------吴佳峻---------------------------------------*/int main()
{//1.创建文件夹顺序表->可以是全局变量,也可以是局部变量 FileList list; /*注:全局变量必须有初值*///2.初始化文件夹顺序表->函数调用必须在main函数里 initFileList(&list,1); /*初始化容量为1*//*list->data:指向一块可以容纳1个FileNode的连续内存空间list->numFile = 0:当前实际存储的文件夹个数,初始时为0list->capacity = 1:数组的最大容量,表示当前最多可以存储1个FileNode*///3.创建文件夹二叉树->初始为一个空树 BiTree root=NULL; //4.初始化文件夹二叉树initBiTree(root,list); //界面 printf("------------------------------------------- \n");printf("    1.创建文件夹           2.删除文件夹 \n");printf("    3.查找文件夹           4.退出 \n");printf("------------------------------------------- \n");while(true){printf("请输入接下来的操作编号:");int choose;scanf("%d",&choose);printf("------------------------------------------- \n");switch(choose){case 1:{//输入信息printf("请输入新创建的文件夹名称:");char inputFile[50];scanf("%s",inputFile); creatFile(root,inputFile,list);printf("------------------------------------------- \n");break;}case 2:{// 修改这里的调用deleteFileInteractive(root, list);printf("------------------------------------------- \n");break;}case 3:{//输入信息printf("请输入要查找的文件夹:"); char findFileName[50];scanf("%s",findFileName);findFile(list,findFileName);printf("------------------------------------------- \n");break;}		case 4:{exit(0);}default:{printf("该操作不存在 \n");printf("------------------------------------------- \n");break;}		}}return 0;
}

http://www.dtcms.com/a/568505.html

相关文章:

  • 互联网大学生创新创业项目计划书seo网址查询
  • 同时打开两个浏览器页面,关闭 A 页面的时候,要求 B 页面同时关闭,怎么实现?
  • 什么是react?
  • Arbess零基础学习 - 使用Arbess+GitLab实现 React.js 项目自动化构建/主机部署
  • 从事网站开发需要的证书网页设计免费网站推荐
  • 任何数据结构的构造或初始化,都应指定大小,避免数据结构无限增长吃光内存【示例】
  • 【开题答辩实录分享】以《基于java的宿舍楼洗衣机预约管理系统》为例进行答辩实录分享
  • 如何在iPhone 17/16/15上显示电池百分比
  • 网站换主机引擎网站推广法
  • 【普中STM32F1xx开发攻略--标准库版】-- 第 13 章 STM32 位带操作
  • MySQL绿色版完整教程:下载、安装、配置与远程访问
  • 集合(开发重点)
  • 如何通过第三方API接口获取拼多多店铺信息?
  • ⸢ 拾贰 ⸥⤳ 实战攻防演练:红蓝对抗 有效性检验
  • Flutter 与 Native的比较
  • 做网站要用到什么泰安有哪些景点
  • Java EE - Thread类的基本使用
  • 社会真相社会现实丛林社会强者思维社会关系价值交换社会法则社会圈子社会阶层电子书籍PDF
  • 轻量化的网络模型:SqueezeNet 详解与复现(已解决)
  • Adobe Acrobat DC PDF如何批量文本替换
  • 帝国cms 微信小程序获取手机号码的api接口
  • 南昌网站搭建服务免费涨1000粉丝网站
  • linux USB摄像头不停掉线问题
  • 本地开发调试企业微信回调接口不顺畅?利用 CPolar 实现内网穿透,快速建立公网访问通道
  • 金融数仓项目介绍
  • 《投资-154》Beta(贝塔系数)是金融领域中用于衡量资产(如股票、基金、投资组合)系统性风险的核心指标,它反映了资产相对于市场整体波动的敏感程度。
  • 【开发技能】借助Aspose.Words,用C#开发一个Markdown到 Word的转换器
  • React 中 useCallback 的基本使用和原理解析
  • 做网站架构深圳精美网站设计
  • OpenCV(十九):图像的加法运算