实验 2:树形数据结构的实现与应用

news/2024/5/10 10:55:15/文章来源:https://blog.csdn.net/Carefree_State/article/details/130758288
  • 东莞理工学院的同学可以借鉴,请勿抄袭

1.实验目的

通过实验达到:

  1. 理解和掌握树及二叉树的基本概念;

  2. 理解和掌握二叉树的顺序存储结构、链式存储结构;

  3. 理解和掌握采用二叉链式存储结构下二叉树的各种遍历操作的思想及 其应用;

  4. 加深对堆栈、队列的概念及其典型操作思想的理解;

  5. 掌握典型二叉树操作算法的算法分析。

2. 实验题目:二叉树的建立、遍历及其应用

设树结点的元素类型为 ElemType(可以为 char 或 int),采用二叉链(或三叉 链,即双亲孩子)存储,实现以下二叉树的各种基本操作的程序:

① 编写一个创建二叉树的函数,通过文件读取方式,建立不少于 10 个结点 的二叉树 T(建议用递归方式创建);

② 给定元素 x,在二叉树中查找该元素 x,若找到则返回该结点的指针;

③ 用凹入表示法打印该二叉树(可以是图 8-2 的形式或者 8.4.3 中的逆时针 旋转 90°,一个先序,一个中序 RDL);

④ 用非递归方式先序遍历方式输出树 T 的结点;(用到栈)

⑤ 用中序或后序遍历方式输出树 T 的结点;

⑥ 用层次遍历方式输出树 T 的结点;(用到队列)

⑦ 输出树 T 的深度;

⑧ 输出树 T 的叶子结点或非叶子结点;

⑨ 主函数设计菜单,通过菜单选择相应的函数调用实现以上各项操作。(在 实验报告中请画出测试的二叉树。) 附加题:(每完成一个额外附加 5 分,上限 10 分)

① 8-32 判断该二叉树是否为完全二叉树(层次遍历);

② 8-34 根据顺序存储建立二叉链存储的二叉树(与第 1 个操作类似);

③ 哈夫曼树编码问题的设计和实现(双亲孩子表示法+flag)。

一个表达式二叉树的例子:在这里插入图片描述

2.1. 数据结构设计

typedef char ElemType;typedef struct Node {ElemType value;struct Node* left;struct Node* right;
}Node;

2.2. 主要操作算法设计与分析

2.2.1. 读文件建立树函数

Node* createTreeByFile();

Node* createTreeByOrder(char string[]);

Node* createNode();

返回类型:Node*;

是否有参数:无

步骤:

  1. fopen打开文件读取字符串,此字符串是这种格式:“-+a##*b##-c##d##/e##f##”
    • (麻烦老师说清楚点,我都不知道你是要我以层序遍历序列构造,还是以前中序或者后中序序列构造,还是以这种来构造…)
  2. 定义一个全局变量j记录字符串被读取到哪个下标
  3. 进入函数后,判断j下标是否为“#”,是则返回NULL,如果不是,调用createNode构造一个节点root
  4. 递归调用一次,将其赋值给root左孩子
  5. 再递归调用一次,将其赋值给root右孩子
  6. 返回root

算法时间复杂度:

  • 时间复杂度为O(N);
  • 空间复杂度为O(log2N);

2.2.2 返回x值对应节点的指针函数

Node* findNode(Node* root, ElemType value);

返回类型:Node*;

是否有参数:二叉树的根节点,键值x

步骤:

  • root为NULL直接返回
  • root对应值为x,返回root
  • 递归调用左孩子,返回的值不为空则返回左孩子指针
  • 递归调用右孩子,返回的值不为空则返回右孩子指针
  • 否则返回空,没有找到

算法时间复杂度:

  • 时间复杂度为O(N);
  • 空间复杂度为O(log2N);

2.2.3. 凹入法打印二叉树函数

void incurvatePrint(char preorder[], char DRLorder[]);

buildTree(preorder, DRLorder);

Node* buildByIndex(char preorder[], char inorder[], int start, int end);

void print(Node* root, int n);

int search(char inorder[], int start, int end, char key);

返回类型:无返回值;

是否有参数:有,传入前序序列与DRL序列

步骤:

  1. incurvatePrint函数内调用buildTree函数获取二叉树,传入两个序列
  2. 调用buildByIndex函数获取二叉树,传入两个序列,以及0和strlen(inorder) - 1(from,to)
  3. 前序遍历序列的第一个值,就是根节点,在DRL中找到这个根节点下标,左边为右子树,右边为左子树,分别递归调用buildByIndex函数
  4. from > end 返回NULL
  5. 最终incurvatePrint调用print函数,传入root和0(n)用凹入法打印二叉树
  6. 每进入一层递归,传入的第二个参数都会加1
  7. 在打印root对应值之前,要递归函数,传入右孩子和n+1,之后要打印n个缩进,打印root值后打印回车符,调用递归函数,传入左孩子和n+1

算法时间复杂度:

  • 时间复杂度为O(N2);
  • 空间复杂度为O(log2N);

2.2.4. 非递归先序打印树函数

栈基本函数:

typedef struct Stack {int size;int capacity;Node** arr;
}Stack;
Stack newStack() {Node** arr = calloc(N, sizeof(Node*));Stack stack = { 0, N, arr };return stack;
}
void push(Stack* ps, Node* value) {if (ps->size == ps->capacity) {ps->arr = (Node**)realloc(ps->arr, 2 * ps->size * sizeof(Node*));ps->capacity *= 2;}ps->arr[ps->size] = value;(ps->size)++;
}
Node* pop(Stack* ps) {if (ps->size == 0) {printf("666,空了\n");return NULL;}return ps->arr[--(ps->size)];
}
int isEmptyStack(Stack* ps) {return ps->size == 0;
}

void preorderNormal(Node* root);

返回类型:无返回值;

是否有参数:有,传入二叉树根节点

步骤:

  1. 建立栈,打印根节点root,(为NULL则return)
  2. 定义cur为root的左孩子
  3. 进入循环,条件:栈不为空或者cur不为空
  4. 进入循环:如果左孩子不为空,压栈并打印节点对应值,cur=cur->left
  5. 循环停止cur赋值为栈弹出来的节点的右孩子
  6. 进入循环判断
  7. 结束循环,则打印结束

算法时间复杂度:

  • 时间复杂度为O(N);
  • 空间复杂度为O(log2N);

2.2.5. 中序遍历和后序遍历函数

void inorder(Node* root);

void postorder(Node* root);

无返回值,有参数,二叉树根节点

步骤:

  1. 根节点为NULL不打印
  2. 依次调用递归函数,传入左孩子和右孩子
  3. 中序遍历则是在两次调用之间,后序遍历则是两次调用之后

复杂度分析:

时间复杂度:O(N)

空间复杂度:O(logN)

2.2.6. 层序遍历函数

常用队列函数:

typedef struct Queue {DataType* arr;int size;int capacity;
}Queue;
Queue createQueue() {DataType* arr = (DataType*)calloc(N, sizeof(DataType));Queue queue = { arr, 0, N };return queue;
}void offer(Queue* pq, DataType value) {if (pq->size == pq->capacity) {pq->arr = (DataType*)realloc(pq->arr, 2 * pq->size * sizeof(DataType));pq->capacity *= 2;}pq->arr[pq->size] = value;(pq->size)++;
}DataType poll(Queue* pq) {if (isEmptyQueue(pq)) {printf("队列空\n");exit(0);}DataType ret = pq->arr[0];(pq->size)--;memmove(pq->arr, pq->arr + 1, pq->size * sizeof(DataType));return ret;
}DataType peek(Queue* pq) {if (isEmptyQueue(pq)) {printf("队列空\n");exit(0);}return pq->arr[0];
}int isEmptyQueue(Queue* pq) {return pq->size == 0;
}

void levelOrder(Node* root);

无返回值,传入参数为二叉树根节点

步骤:

  1. 根节点为NULL,则return
  2. 建立队列queue,根节点入队列
  3. 进入循环,条件:队列不为空
  4. Node* tmp接受出队列元素
  5. 打印tmp的值,将tmp的左孩子如队列,右孩子入队列(如果为NULL则不用)
  6. 直到出循环

复杂度分析:

时间复杂度:O(N)

空间复杂度:O(log2N)

2.2.7. 输出树的深度

int getHeight(Node* root);

返回int深度,传入二叉树根节点

步骤:

  1. root为NULL返回
  2. 调用两次递归函数,依次传入左孩子和右孩子
  3. 返回两个递归函数的返回值中的最大值加1

复杂度分析:

时间复杂度:O(N)

空间复杂度:O(log2N)

2.2.8. 输出树 T 的叶子结点或非叶子结点

void printLeafNode(Node* root);

void printNotLeaf(Node* root);

无返回值,传入二叉树根节点

步骤:

  1. root为NULL,return
  2. root不为NULL,
    1. printLeafNode函数如果root左右孩子都为NULL,则打印
    2. printNotLeaf函数中如果root左右孩子不全为NULL,则打印
  3. 调用两次递归函数,依次传入左孩子和右孩子

复杂度分析:

时间复杂度:O(N)

空间复杂度:O(log2N)

2.2.9. 判断该二叉树是否为完全二叉树

int isCompleteTree(Node* root)

返回int是与否,传入二叉树根节点

步骤:

  1. 如果root为NULL,返回1
  2. 定义队列queue,根节点入队列
  3. 进入循环,循环条件是queue不为空队列
  4. Node* cur接受出队列元素
  5. 如果cur不为NULL,左右孩子入队列
  6. 否则,一直出队列,如果队列中出现非NULL值,则返回0,否则返回1
  7. 若循环结束,返回1

复杂度分析:

时间复杂度:O(N)

空间复杂度:O(log2N)

2.2.10. 层序遍历序列构造二叉树(用2.2.9的类似操作)

Node* createTreeByLevelOrder(char string[]);

返回二叉树根节点,传入字符数组

步骤:

  1. 只要数组不为空,就先入队数组首元素,并用这个值创建二叉树的root。
  2. 然后进入循环,循环条件为队列不为空,取出队头元素,队头出队。
  3. 只要数组还有元素,就先给刚刚拿出的对头元素创建左孩子,然后左孩子入队。
  4. 同上,再创建右孩子,右孩子入队。
  5. 结束一次循环。回到2

复杂度分析:

时间复杂度:O(N)

空间复杂度:O(log2N)

2.2.11. main函数


int main() {printf("===================================\n");Node* root = createTreeByFile();printf("===================================\n");Node* XTree = findNode(root, '*');printf("===================================\n");printf("凹入法打印:\n");incurvatePrint("-+a*b-cd/ef", "f/e-d-c*b+a");printf("===================================");printf("\n非递归前序:");preorderNormal(root);printf("\n递归前序:");preorder(root);printf("\nXTree前序:");preorder(XTree);printf("\n===================================");printf("\n递归中序:");inorder(root);printf("\n递归后序:");postorder(root);printf("\n===================================");printf("\n层序:");levelOrder(root);printf("\n===================================");printf("\n深度:%d", getHeight(root));printf("\n===================================");printf("\n叶子节点:");printLeafNode(root);printf("\n非叶子节点:");printNotLeaf(root);printf("\n===================================\n");printf("root%s完全二叉树", isCompleteTree(root) ? "是" : "不是");printf("\n===================================\n");levelOrder(createTreeByLevelOrder("123456789"));
}

2.3. 程序运行过程及结果

在这里插入图片描述

5. 总结

  • 在这个过程中遇到很多问题,例如空指针异常,结果与预计结果不符
  • 但是只要好好调试,总是能解决问题
  • 对于递归的重点就是转化为子问题,整体性的思想
  • 非递归实现则需要结合栈或者队列!

6. 附录:源代码

代码地址:码云连接

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_303057.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PMP课堂模拟题目及解析(第11期)

101. 一家咨询公司的负责人启动一个项目来扩大公司提供的服务数量,这公司具有竞争优势、出色的企业知识以及卓越的声誉,高管团队担心与增加新服务相关的负面业务结果的可能性。若要评估负面业务结果的可能性和影响,项目经理应该使用什么&…

Eolink 出席 QECon 深圳站,共同探讨软件质量和效能发展

5月12日至13日,由 QECon 组委会和深圳市软件行业协会联合主办的「QECon全球软件质量&效能大会」成功召开,作为国内 API 全生命周期解决方案的领军者,Eolink 受邀参加此次大会。 大会中,Eolink SaaS 产品负责人崔嘉杰、高级售…

以SpringMVC入门案例分析服务器初始化过程、单次请求流程

文章目录 1,SpringMVC概述2,SpringMVC入门案例2.1 需求分析2.2 案例制作步骤1:创建Maven项目步骤2:补全目录结构步骤3:导入jar包步骤4:创建配置类步骤5:创建Controller类步骤6:使用配置类替换web.xml步骤7:配置Tomcat环境步骤8:启动运行项目步骤9:浏览器…

知行之桥2023版本发布

我们很高兴地宣布知行之桥EDI系统2023版本正式发布。本次发布的知行之桥2023版(版本号:8518)包含了新的企业级功能,以下是新版本的一些亮点: 1.新增了概览页面,支持查看消息的整个生命周期,添加…

chatgpt赋能Python-python3_5怎么算

Python3|5是如何计算的? 介绍 Python是一种高级编程语言,许多开发人员喜欢使用它来构建各种应用程序,从网站到机器学习应用程序。然而,在使用Python编写代码时,很多人都会遇到一个问题:Python3|5计算是如…

数组【C语言】

目录 一维数组的创建和初始化 数组创建 数组的初始化 一维数组的使用 一维数组在内存中的存储 二维数组的创建与初始化 二维数组的创建 二维数组的初始化 二维数组的使用 二维数组在内存中的存储 数组越界 数组名作为函数参数 数组名 一维数组的创建和初始化 数组…

springboot+java+jsp校园二手书旧书交易交换系统

前台功能:用户进入系统可以对首页、书籍信息、校园公告、个人中心、后台管理等功能进行操作; 后台主要是管理员,管理员功能包括主页、个人中心、学生管理、发布人管理、书籍分类管理、书籍信息管理、交易信息管理、交换信息管理、系统管理等&…

Git回滚详解

文章目录 git restore撤销工作区文件更改撤销暂存区文件更改 git checkoutgit revert冲突解决具体操作 git resetreset 的作用第 1 步:移动 HEAD(--soft)第 2 步:更新暂存区(--mixed)第 3 步:更…

chatgpt赋能Python-python3_2__1

Python3-2<<1&#xff1a; 了解运算符的使用和优先级 Python是一种优雅而高效的编程语言&#xff0c;而Python3-2<<1是一个关于运算符优先级的例子&#xff0c;值得我们深入探讨。 在这篇文章中&#xff0c;我们将介绍Python3中运算符的优先级&#xff0c;并对其中…

海康机器视觉工业相机客户端MVS-常用功能CCM

什么是CCM? CCM是一种功能。 CCM矩阵是通过对每一个RGB分量乘以一个校正矩阵来实现色彩校正。当图像经过白平衡处理后,图像整 体会显得比较黯淡,同时多种颜色可能存在不同程度地偏离其标准值。此时需要对图像的色彩乘以校正 矩阵来修正各颜色至其标准值,使图像的整体色彩更…

chatgpt赋能Python-python3gui

Python3 GUI- 让你的应用程序更酷炫 随着技术的发展&#xff0c;图形用户界面(Graphical User Interface, GUI)已经成为软件开发过程中不可或缺的一部分。Python3是一个用于快速开发应用程序的强大编程语言&#xff0c;支持多种GUI库。本文将为您介绍Python3 GUI的一些基本概念…

DS:基于鸢尾花数据集利用多种数据降维技术(PCA、SVD、MDS、LDA、T-SNE)实现三维可视化

DS&#xff1a;基于鸢尾花数据集利用多种数据降维技术(PCA、SVD、MDS、LDA、T-SNE)实现三维可视化 目录 基于鸢尾花数据集利用多种数据降维技术(PCA、SVD、MDS、LDA、T-SNE)实现三维可视化 # 1、加载示例数据集&#xff08;鸢尾花数据集&#xff09; # 2、数据预处理 # T1、…

精彩直击 | 迅镭激光参展CIBF2023年电池技术盛会

5月16日&#xff0c;全球规模最大的电池、能源行业盛会——CIBF2023第十五届中国国际电池技术展览会(以下简称2023CIBF电池展)&#xff0c;在深圳国际会展中心(宝安新馆)隆重开幕! 迅镭激光携一系列新能源自动化解决方案亮相9T263展位&#xff0c;与客户分享创新技术及自动化产…

chatgpt赋能Python-python3_10安装numpy

Python3.10安装numpy&#xff1a;一步一步教你如何轻松完成 Python3.10虽然已经发布了&#xff0c;但是有些模块还需要手动安装&#xff0c;例如numpy。在这篇文章中&#xff0c;我们将会详细介绍如何安装numpy模块&#xff0c;以及为什么要使用numpy模块。 什么是numpy模块&…

web安全第一天 ,域名,dns

第一天 什么是域名&#xff1f;域名就是网络地址 在hhtp之后的就是域名 域名在哪里注册呢 国内注册商有很多&#xff0c;在网络上搜索一下阿里云万网就可以注册 什么是二级域名和多级域名 域名通常都是www.开头 &#xff0c;而www.被称为顶级域名&#xff0c;在搜索的时候…

微服务—Redis实用篇-黑马头条项目-附近商户功能(使用GEO实现)

微服务—Redis实用篇-黑马头条项目-附近商户功能(使用GEO实现) 1、附近商户 1.1、附近商户-GEO数据结构的基本用法 GEO就是Geolocation的简写形式&#xff0c;代表地理坐标。Redis在3.2版本中加入了对GEO的支持&#xff0c;允许存储地理坐标信息&#xff0c;帮助我们根据经纬…

医院上线“报告中心”,实现报告查询“四个更好”

为进一步提升患者的就诊体验&#xff0c;不少医院部署云影像后&#xff0c;再次上线博为软件报告中心信息系统&#xff0c;患者和家属动动手指就能在自己手机上随时随地看到检查检验报告&#xff0c;彻底告别传统的纸质报告单方式&#xff0c;实现检查检验数据永久保存。 博为…

ChatGPT工作提效之在程序开发中的巧劲和指令(创建MySQL语句、PHP语句、Javascript用法、python的交互)

ChatGPT工作提效之程序开发中的巧劲 前言一、创建MySQL数据表1.创建指令2.交互评价 二、PHP交互语句1.创建指令2.交互评价 三、javascript的交互用法1.创建指令2.交互评价 四、python的交互1.创建指令2.交互评价 总结 前言 ChatGPT是一个基于GPT模型训练的聊天机器人&#xff…

车辆管理系统的设计与实现

背景 4S店车辆系统&#xff0c;为用户随时随地查看4S店车辆信息提供了便捷的方法&#xff0c;更重要的是大大的简化了管理员管理4S店车辆信息的方式方法&#xff0c;更提供了其他想要了解4S店车辆信息及运作情况以及挑选方便快捷的可靠渠道。相比于传统的管理方法&#xff0c;…

解说天下之操作系统

解说天下之操作系统 本文由桌案drawon (https://www.drawon.cn)&#xff0c;云晶&#xff08;https://www.yunjingxz.com&#xff09;创始人根据多年从业经验&#xff0c; 从操作系统的起源&#xff0c;应用分类&#xff0c; 设计分类&#xff0c;以及资源使用角度对操作系统进…