• 需求分析

在图书、操作系统文件夹、学生等管理系统中,目录管理是必要环节,如何高效搜寻与低复杂度存储是实现这一环节的关键性问题。本课程设计需完成一种基于多叉树结构简单目录管理系统,该系统能以交互式界面进行创建目录、删除目录、查找目录、修改目录、层次遍历目录、深度遍历目录及退出管理系统操作。

    • 设计目的

(1)完成一种简单的目录管理系统,灵活运用自己所学的数据结构知识。

(2)系统的观点和软件开发一般规范进行软件开发,巩固、深化理论知识,提高编程水平,并在此过程中培养严谨的科学态度和良好的工作作风。

    • 需求概述

完成一种简单的目录管理系统,进行高效搜寻与低复杂度存储,其具体功能需求如下:

  1. 交互性强:能够从终端进行人机交互。

  1. 创建目录:能够已一种高效的数据结构进行数据的存储。

  1. 删除目录:能够删除对应的目录信息。

  1. 查找目录:能够查找对应的目录信息,

  1. 修改目录:能够修改对应的目录信息。

  1. 层次遍历目录:能够层次遍历目录信息。

  1. 深度遍历目录:能够深度遍历目录信息。

  1. 退出管理系统:能够退出管理系统。

    • 需求说明

完成一种简单的目录管理系统,进行高效搜寻与低复杂度存储。系统能够以交互式界面完成目录的查询、添加、修改、删除、排序等功能,主界面如下图1-1所示。

图1-1 主界面

    • 概要设计

本节以上述需求明确具体数据结构类型,数据存储方式及功能函数封装。由目录管理系统的特性分析可知,一个父级目录下可以有多个子级目录,多个子级目录并没有顺序关系。因此,本课程设计采取了多叉树的数据结构及进行存储数据,以层次遍历显示所有文件,以深度遍历找到根目录到叶子目录的最长文件路径。

    • 数据类型的定义

  1. 定义多叉树的节点结构体,代码如下表2-1所示。

表2-1 多叉树的节点结构体源码

typedef struct node_t{char*name; // 节点名int n_children; // 子节点个数int level;// 记录该节点在多叉树中的层数structnode_t** children; // 指向其自身的子节点,children一个数组,该数组中的元素时node_t*指针} NODE; // 对结构体重命名
  1. 实现一个栈,用于输出目录时,以子目录到根目录的顺序进行输出,代码如下表2-2所示。

表2-2 栈结构体源码

typedef struct stack_t{NODE**array; // array是个数组,其元素为NODE*型指针intindex; // 指示栈顶元素intsize; // 栈的大小} STACK; // 重命名
  1. 实现一个队列,用于层次遍历及深度遍历进行输出,代码如下表2-3所示。

表2-3 队列结构体源码

typedef struct queue_t{NODE**array; // array是个数组,其内部元素为NODE*型指针inthead; // 队列的头inttail; // 队列的尾intnum;// 队列中元素的个数intsize; // 队列的大小} QUEUE;
    • 功能模块结构图

根据需求分析,为满足用户的功能需求,将系统设计为以下三大模块:

  1. 显示模块:交互式界面显示。

(2) 功能模块:实现目录的管理,如创建、删除、查找、修改、遍历等功能。

系统结构如 图 2-4所示:

图2-4 系统结构图

    • 功能模块

为了实现上述功能模块,分别在多叉树数据结构上定义了多个函数,本系统定义的函数和功能如下表2-5所示:

表2-5 函数与功能对应表

函数名称

功能说明

void* util_malloc(int size)

内存分配函数。

char* util_strdup(char* src)

字符串赋值函数。

FILE* util_fopen(char* name, char* access)

打开文件函数。

STACK* STACKinit(int size)

栈的初始化。

int STACKempty(STACK* sp)

判断栈是否为空。

int STACKpush(STACK* sp, NODE* data)

压栈操作。

int STACKpop(STACK* sp, NODE** data_ptr)

弹栈操作。

void STACKdestroy(STACK* sp)

栈的销毁。

QUEUE* QUEUEinit(int size)

队列初始化。

int QUEUEenqueue(QUEUE* qp, NODE* data)

入队操作。

int QUEUEdequeue(QUEUE* qp, NODE** data_ptr)

出队操作

int QUEUEempty(QUEUE* qp)

判断队列是否为空。

void QUEUEdestroy(QUEUE* qp)

队列的销毁。

NODE* create_node()

生成多叉树节点。

NODE* search_node_r(char name[M], NODE* head)

按照节点名字查找。

void read_file(NODE** head, char* filename)

从文件中读取多叉树,并建立多叉树。

void f1(NODE* head)

层次遍历。

void free_tree_r(NODE* head)

销毁树。

void f2(NODE* head, char* str, char** strBest, int level)

深度遍历。

void Welcome()

显示界面

void Create()

输入节点数据。

int main(int argc, char* argv[])

主界面。

    • 详细设计

本节在概要设计的基础上,对每个模块内部逻辑处理部分进行详细设计。下面分别讲述核心模块具体实现方法及对应流程图。

    • 主界面

本模块旨在以良好的交互式界面,提供给客户更好的操作体验。采取了while循环内部判断,根据按键判断以调用相应的处理函数,若未定义按键则需要进入等待直到按出指定按键才会进入下一次循环,具体代码如下表3-1所示。

表3-1 主界面源码

while(1){ system("cls"); // 清屏 Welcome();//重新显示界面 int i, cho; scanf("%d",&i); if(1 == i)Create();//if(2 == i)Delete();//if(3 == i)Search();//if(4 == i)Alter(); if(5 == i)Traversal1(); if(6 == i)Traversal2(); if(7 == i){printf("\n欢迎您再次使用本系统\n\n");break;}printf("\n返回请输入0\n"); begin: //goto 标志位 scanf("%d",&cho); if(0 == cho){ continue; } else{ printf("您的输入有误,请重新输入\n"); goto begin;//goto 到指定标志位 begin }}
    • 创建多叉树

本次设计通过外部文件与内部存储结合的方式构造了多叉树。需要在交互界面以父节点、子节点个数及子节点名称的顺序进行输入,输入后的数据存放在 data.txt文本中。通过调用data.txt文本数据来进行多叉树的构建,部 分源码如下表3-2所示,流程图如下图3-3所示。

表3-2 创建多叉树源码

图3-3 创建多叉树流程图

    • 查找多叉树

方式一:通过对文本操作,搜寻指定字符串是否存在。

方式二:遍历多叉树,判断字符名是否相同,具体代码如下表3-4所示。

表3-4查找多叉树源码

NODE*search_node_r(char name[M], NODE* head){NODE* temp = NULL;int i = 0; if (head != NULL){if (strcmp(name, head->name) == 0)// 如果名字匹配{temp = head;}else // 如果不匹配,则查找其子节点{for (i = 0; i n_children && temp == NULL/*如果temp不为空,则结束查找*/; ++i){temp = search_node_r(name,head->children[i]); // 递归查找子节点}}} return temp; // 将查找到的节点指针返回,也有可能没有找到,此时temp为NULL}
    • 删除多叉树

通过对文本操作,搜寻指定字符串是否存在后,删除对应节点。

    • 修改多叉树

通过对文本操作,搜寻指定字符串是否存在,修改对应节点名称。

    • 层次遍历多叉树

通过队列对父节点进行存储,若不为空出队操作,让其子节点入队,递归实现。为了良好的用户体验,采取的栈的存储结构,以子节点先输出、父节点后输出的顺序进行显示,具体源码如下表3-5所示。

表3-5层次遍历多叉树源码

voidf1(NODE* head){NODE* p = NULL;QUEUE* q = NULL; // 定义一个队列STACK* s = NULL; // 定义一个栈int i = 0; q = QUEUEinit(100); // 将队列初始化大小为100s = STACKinit(100); // 将栈初始化大小为100head->level = 0; // 根节点的深度为0// 将根节点入队列QUEUEenqueue(q, head); // 对多叉树中的节点的深度值level进行赋值// 采用层次优先遍历方法,借助于队列while (QUEUEempty(q) == 0) // 如果队列q不为空{QUEUEdequeue(q, &p); // 出队列for (i = 0; i n_children;++i){p->children[i]->level =p->level + 1; // 对子节点深度进行赋值:父节点深度加1QUEUEenqueue(q,p->children[i]);// 将子节点入队列}STACKpush(s, p); // 将p入栈} while (STACKempty(s) == 0) // 不为空{STACKpop(s, &p); // 弹栈fprintf(stdout, "第%d层 目录名为:%s\n",p->level, p->name);} QUEUEdestroy(q); // 消毁队列STACKdestroy(s); // 消毁栈}
    • 深度遍历多叉树

具体代码如下表3-6所示。

表3-6 深度遍历多叉树源码

voidf2(NODE* head, char* str, char** strBest, int level){inti = 0; char* tmp = NULL;if (head == NULL){return;}tmp = (char*)util_malloc((strlen(str) +strlen(head->name) + 1/*原程序中未加1*/) * sizeof(char));sprintf(tmp, "%s%s", str, head->name);if (head->n_children == 0){if (*strBest == NULL || strlen(tmp)> strlen(*strBest)){free(*strBest);*strBest = util_strdup(tmp);}}for (i = 0; i n_children;++i){f2(head->children[i], tmp, strBest,level + 1);}free(tmp);} 

4运行结果

这里将展示部分功能的运行结果。

4.1 主界面

主界面如下图4-1所示。

图4-1 主界面

4.2 主菜单界面

添加节点界面如下图4-2所示。

图4-2 添加节点界面

4.3 层次遍历界面

层次遍历界面如下图4-3所示。

图4-3 层次遍历界面

4.4 深度遍历界面

深度遍历界面如下图4-4所示。

图4-4 深度遍历界面

代码内容

源码可私信摸鱼哥,免费获取(点个关注即可白嫖)