二叉树的实现(详解,数据结构)

目录

一,二叉树需要实现的功能

二,下面是各功能详解

0.思想:

1.创建二叉树结点:

2.通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树

3.二叉树销毁:

4.前序遍历:

5.中序遍历:

6.后序遍历:

 7.层序遍历:

1.先实现队列的基本功能:

2.基于队列实现层序:

8.计算各类结点数量:

1.计算二叉树结点数量:

2.计算叶子结点数量:

3.计算K层结点数量:

9.二叉树查找值为X的结点:

10.判断二叉树是否为完全二叉树:


一,二叉树需要实现的功能

// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi);
// 二叉树销毁
void BinaryTreeDestory(BTNode** root);
// 二叉树节点个数
int BinaryTreeSize(BTNode* root);
// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root);
// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k);
// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);
// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root);
// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root);
// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root);
// 层序遍历
void BinaryTreeLevelOrder(BTNode* root);
// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root);

二,下面是各功能详解

0.思想:

下面很多功能都涉及分治的思想(分治法是算法常用的解题方法之一,是将一个大的问题拆分为若干小的问题。)

1.创建二叉树结点:

//重命名存储变量类型,方便更改
typedef char BTDataType;typedef struct BinaryTreeNode
{BTDataType _data;struct BinaryTreeNode* _left;struct BinaryTreeNode* _right;
}BTNode;

2.通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树

// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi) {if (*pi >= n || a[*pi] == '#') {(*pi)++;return NULL;}BTNode* Node = (BTNode*)malloc(sizeof(BTNode));if (Node == NULL) {perror("BinaryTreeCreate::malloc");exit(0);}Node->_data = a[*pi];(*pi)++;Node->_left = BinaryTreeCreate(a, n, pi);Node->_right = BinaryTreeCreate(a, n, pi);return Node;
}

按照以上所给数组描述,我们创建出的二叉树:

3.二叉树销毁:

二叉树的存储类似链表,可以由前面的结点找到后面的结点,因此二叉树的销毁也是由后向前销毁会方便很多,所以我们采取后序来销毁二叉树

// 二叉树销毁
void BinaryTreeDestory(BTNode** root) {if (*root == NULL) {return;}BinaryTreeDestory(&(*root)->_left);BinaryTreeDestory(&(*root)->_right);free(*root);*root = NULL;
}

4.前序遍历:

        i、先访问根结点;

        ii、再前序遍历左子树;

        iii、最后前序遍历右子树;

算法实现:

// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root) {if (root != NULL) {printf("%c ", root->_data);BinaryTreePrevOrder(root->_left);BinaryTreePrevOrder(root->_right);}
}

5.中序遍历:

        i、中序遍历左子树;

        ii、访问根结点;

        iii、中序遍历右子树

算法实现:

// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root) {if (root != NULL) {BinaryTreeInOrder(root->_left);printf("%c ", root->_data);BinaryTreeInOrder(root->_right);}
}

6.后序遍历:

        i、后序遍历左子树

        ii、后序遍历右子树

        iii、访问根结点

 算法实现:

// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root) {if (root != NULL) {BinaryTreePostOrder(root->_left);BinaryTreePostOrder(root->_right);printf("%c ", root->_data);}
}

 7.层序遍历:

设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。

思路:层序遍历需要用到队列的知识,就是先将根结点入队,判断队列是否为空,循环将队首元素出队的同时队首元素子节结点入队

算法实现:

1.先实现队列的基本功能:
typedef BTNode QDataType;
// 链式结构:表示队列 
typedef struct QListNode
{struct QListNode* _next;QDataType* _data;
}QNode;
// 队列的结构 
typedef struct Queue
{QNode* _front;QNode* _rear;
}Queue;
// 初始化队列 
void QueueInit(Queue* q) {assert(q);q->_front = NULL;q->_rear = NULL;
}
int QueueEmpty(Queue* q);
// 队尾入队列 
void QueuePush(Queue* q, QDataType* data) {assert(q);QNode* tmp = (QNode*)malloc(sizeof(QNode));if (tmp == NULL) {perror("QueuePush:malloc");return;}tmp->_data = data;tmp->_next = NULL;if (QueueEmpty(q)) {q->_front = tmp;q->_rear = tmp;}q->_rear->_next = tmp;q->_rear = tmp;
}
// 队头出队列 
void QueuePop(Queue* q) {if (QueueEmpty(q)) {printf("Pop: Queue is empty\n"); // 更清晰的错误信息  exit(0);}q->_front = q->_front->_next;//free(tmp);
}
// 获取队列头部元素 
QDataType* QueueFront(Queue* q) {return q->_front->_data;
}
// 获取队列队尾元素 
QDataType* QueueBack(Queue* q) {return q->_rear->_data;
}
// 获取队列中有效元素个数 
int QueueSize(Queue* q) {QNode* cur = q->_front;int size = 0;while (cur) {size++;cur = cur->_next;}return size;
}
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q) {assert(q);if (q->_front == NULL) {return 1;}return 0;
}
// 销毁队列 
void QueueDestroy(Queue* q) {assert(q);while (!QueueEmpty(q)) {QueuePop(q);}
}
2.基于队列实现层序:
// 层序遍历
void BinaryTreeLevelOrder(BTNode* root) {Queue* queue = (Queue*)malloc(sizeof(Queue));BTNode* front;QueueInit(queue);if (root) {QueuePush(queue, root);}while (!QueueEmpty(queue)) {front = QueueFront(queue);if (front->_left){QueuePush(queue, front->_left);}if (front->_right){QueuePush(queue, front->_right);}printf("%c ",front->_data);QueuePop(queue);}printf("\n");QueueDestroy(queue);
}

8.计算各类结点数量:

1.计算二叉树结点数量:
// 二叉树节点个数
int BinaryTreeSize(BTNode* root) {if (root == NULL) {return 0;}else {return BinaryTreeSize(root->_left) + BinaryTreeSize(root->_right) + 1;}
}
2.计算叶子结点数量:
// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root) {if (root == NULL) {return 0;}if (root->_left == NULL && root->_right == NULL) {return 1;}else {return BinaryTreeLeafSize(root->_left) + BinaryTreeLeafSize(root->_right);}
}
3.计算K层结点数量:
// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k) {if (root == NULL) {return 0;}if (k == 1) {return 1;}return BinaryTreeLevelKSize(root->_left, k - 1) + BinaryTreeLevelKSize(root->_right, k - 1);
}

9.二叉树查找值为X的结点:

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x) {if (root==NULL) {return NULL;}if (root->_data == x) {return root;}BTNode* r1 = BinaryTreeFind(root->_left, x);if (r1 != NULL) {return r1;}return BinaryTreeFind(root->_right, x);
}

10.判断二叉树是否为完全二叉树:

根据完全二叉树的定义,具有n个结点的完全二叉树与满二叉树中编号从1~n的结点一一对应。
算法思想:采用层次遍历算法,将所有结点加入队列(包括空结点)。遇到空结点时,查看其后是否有非空结点。若有,则二叉树不是完全二叉树。

判断二叉树是否为完全二叉树是二叉树层序遍历的基本用途之一,也要借助队列来实现;

算法实现:

// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root) {Queue queue;QueueInit(&queue);if (root) {QueuePush(&queue, root);}while (!QueueEmpty(&queue)) {BTNode* front = QueueFront(&queue);QueuePop(&queue);if (front == NULL) {break;}QueuePush(&queue, front->_left);QueuePush(&queue, front->_right);}while (!QueueEmpty(&queue)) {BTNode* front = QueueFront(&queue);QueuePop(&queue);if (front) {QueueDestroy(&queue);return 0;}}QueueDestroy(&queue);return 1;
}

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

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

相关文章

RabbitMQ之顺序消费

什么是顺序消费 例如:业务上产生者发送三条消息, 分别是对同一条数据的增加、修改、删除操作, 如果没有保证顺序消费,执行顺序可能变成删除、修改、增加,这就乱了。 如何保证顺序性 一般我们讨论如何保证消息的顺序性&…

3GPP官网下载协议步骤

1.打开官网 https://www.3gpp.org/ 2.点击 3.在界面选择要找的series,跳转到查找界面 以V2X通信协议为例,论文中通常会看到许多应用: [7] “Study on evaluation methodology of new Vehicle-to-Everything (V2X) use cases for LTE and NR…

3.2Java全栈开发前端+后端(全栈工程师进阶之路)-前端框架VUE3框架-企业级应用- Vuex

Vuex简介 Vuex概述 Vuex是一个专门为Vue.js应用程序开发的状态管理模式, 它采用集中式存储管理所有组件的公共状态, 并以相应的规 则保证状态以一种可预测的方式发生变化. 试想这样的场景, 比如一个Vue的根实例下面有一个根组件名为App.vue, 它下面有两个子组件A.vue和B.vu…

022、Python+fastapi,第一个Python项目走向第22步:ubuntu 24.04 docker 安装mysql8集群、redis集群(三)

这次来安装mysql8了,以前安装不是docker安装,这个我也是第一次,人人都有第一次嚒 前言 前面的redis安装还是花了点时间的,主要是网上教程,各有各的好,大家千万别取其长处,个人觉得这个环境影响…

ASP.NET网上车辆档案管理系统

摘 要 本文采用基于Web的Asp.net技术,并与sql server 2000数据库相结合,研发了一套车辆档案管理系统。该系统扩展性好,易于维护。简化了车辆档案设计流程,去除了冗余信息。汽车销售企业可以通过本系统完成整个销售及售后所有档案…

python爬虫实战

import requests import json yesinput(输入页数:) yesint(yes)headers {"accept": "application/json, text/plain, */*","accept-language": "zh-CN,zh;q0.9","content-type": "application/json",…

一对一WebRTC视频通话系列(三)——leave和peer-leave信令实现

本篇博客主要分为两部分,第一部分为leave信令的实现,即当有客户端离开房间后,服务端和其他在房间内的客户需知晓。第二部分为媒体协商和网络协商相关API。 本系列博客主要记录一对一WebRTC视频通话实现过程中的一些重点,代码全部进…

渗透之sql盲注(时间/boolean盲注)

sql盲注:sql盲注意思是我们并不能在web页面中看到具体的信息,我们只能通过输入的语句的真假来判断。从而拿到我们想要的信息。 我们通常使用ascii值来进行盲注。 目录 手动注入: 时间盲注: 布尔盲注: python脚本注…

【Java】基本程序设计结构(一)

前言:现在,假定已经成功安装了JDK,并且能够运行上篇示例程序。本篇将开始介绍Java程序中的基本设计结构,其中包括:一个简单的Java应用,注释,数据类型,变量与常量,运算符&…

【深度学习基础(3)】初识神经网络之深度学习hello world

文章目录 一. 训练Keras中的MNIST数据集二. 工作流程1. 构建神经网络2. 准备图像数据3. 训练模型4. 利用模型进行预测5. (新数据上)评估模型精度 本节将首先给出一个神经网络示例,引出如下概念。了解完本节后,可以对神经网络在代码上的实现有一个整体的了…

【架构系列】RabbitMQ应用场景及在实际项目中如何搭建可靠的RabbitMQ架构体系

作者:后端小肥肠 创作不易,未经允许禁止转载。 1. 前言 RabbitMQ,作为一款高性能、可靠的消息队列软件,已经成为许多企业和开发团队的首选之一。它的灵活性和可扩展性使得它适用于各种应用场景,从简单的任务队列到复杂的分布式系统…

算法设计与分析——期末1h

目录 第一章 算法的定义 算法的三要素 算法的基本性质 算法的时间复杂度数量级: 第二章 兔子繁殖问题(递推法) 猴子吃桃问题(递推法) 穿越沙漠问题(递推法(倒推)) 百钱百…

解决Maven本地仓库存在依赖包还需要远程下载的问题

背景 公司有自己maven私服,正在在私服可以使用的情况,打包是没问题的。但是这次是由于公司大楼整体因电路检修而停电,所有服务器关机,包括maven私服服务器。然后当天确有一个包需要打,这个时候发现死活打不了&#xf…

线性数据结构-手写链表-LinkList

为什么需要手写实现数据结构? 其实技术的本身就是基础的积累和搭建的过程,基础扎实 地基平稳 万丈高楼才会久战不衰,做技术能一通百,百通千就不怕有再难得技术了。 一:链表的分类 主要有单向,双向和循环链表…

飞书API(7):MySQL 入库通用版本

一、引入 在上一篇介绍了如何使用 pandas 处理飞书接口返回的数据,并将处理好的数据入库。最终的代码拓展性太差,本篇来探讨下如何使得上一篇的最终代码拓展性更好!为什么上一篇的代码拓展性太差呢?我总结了几点: 列…

福布斯AI 50榜单发布!新兴势力颠覆传统,叫板谷歌、微软

整理 | 王轶群 责编 | 唐小引 出品丨AI 科技大本营(ID:rgznai100) ChatGPT带来的生成式人工智能热浪,促使众多企业争先恐后地试图实现生成式人工智能的最新进展。一个新的帮助企业开发和部署人工智能驱动的应用程序的科技经济体系…

NFS共享存储服务

一、NFS概述 1、简介 NFS是一种基于TCP/IP传输的网络文件系统协议。 NFS 服务的实现依赖于 RPC(Remote Process Call,远端过程调用)机制,通过使用 NFS 协议,客户机可以像访问本地目录一样访问远程服务器中的共享资源…

BUUCTF——web题目练习

[极客大挑战 2019]LoveSQL 输入1 123 输入1 123 输入2 123 这里可以看出注入位置为password的后面,开始手动注入 闭合方式为1 [极客大挑战 2019]Secret File 查看页面源代码,发现里面有一个跳转页面的连接,点击进去,查看这个…

Llama改进之——SwiGLU激活函数

引言 今天介绍LLAMA模型引入的关于激活函数的改进——SwiGLU1,该激活函数取得了不错的效果,得到了广泛地应用。 SwiGLU是GLU的一种变体,其中包含了GLU和Swish激活函数。 GLU GLU(Gated Linear Units,门控线性单元)2引入了两个不同的线性层…

83、动态规划-打家劫舍

思路: 首先使用递归方式求出最优解。从每个房屋开始,分别考虑偷与不偷两种情况,然后递归地对后续的房屋做同样的决策。这种方法确保了可以找到在不触发警报的情况下可能的最高金额。 代码如下: public static int rob(int[] nu…