数据结构:9、二叉树

在上堆中已经介绍了什么是二叉树,所以这里直接写二叉树实现。

1、二叉树的构建

二叉树的构建第一步肯定是初始化,也就是构建这棵树,这里是利用前序遍历构建的,因为这里是利用链表形式创建的二叉树,所以这里就是和之前文章一样,先是申请地址的函数,紧接着就是递归去申请空间,因为构建的树是字符型,所以这里在#号停下构建并且递归返回,销毁也是递归销毁,因为左节点和右节点最后肯定为空,所以可以直接判断这两个节点,代码如下

//申请地址
BTNode* BuyNode(BTDataType* a)
{BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL){perror("malloc fail");return NULL;}newnode->data = *a;newnode->left = NULL;newnode->right = NULL;return newnode;
}// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a,int* pi)
{if (a[*pi] == '#'){(*pi)++;return NULL;}BTNode* root = BuyNode(&a[*pi]);(*pi)++;root->left = BinaryTreeCreate(a, pi);root->right = BinaryTreeCreate(a, pi);return root;
}// 二叉树销毁
void BinaryTreeDestory(BTNode* root)
{if (root == NULL)return;BinaryTreeDestory(root->left);BinaryTreeDestory(root->right);free(root);
}

2、二叉树的前序遍历

这个前序遍历就是按照根左节点右节点的形式去打印数据当判断到当前地址为空时也就是说这个节点到头了,就可以直接返回接着递归了,所以这种就是打印前序遍历的,代码如下。

void BinaryTreePrevOrder(BTNode* root)
{if (root == NULL){printf("N ");return ;}printf("%c ", root->data);BinaryTreePrevOrder(root->left);	BinaryTreePrevOrder(root->right);
}

3、二叉树的中序遍历

这个和前序遍历没多大区别,不同的就是打印位置变了,如下代码,就是先遍历左节点,紧接着就是在左节点遍历完返回打印,一直到根节点,最后咋递归遍历右节点打印。

void BinaryTreeInOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}BinaryTreeInOrder(root->left);printf("%c ", root->data);BinaryTreeInOrder(root->right);
}

4、二叉树的后续遍历

后续遍历说白了就是先遍历左节点然后是右节点最后是根节点,代码如下。

void BinaryTreePostOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}BinaryTreePostOrder(root->left);BinaryTreePostOrder(root->right);printf("%c ", root->data);
}	

5、二叉树的层序遍历

这个就不是利用递归了,他是利用队列的先进先出的特性进行遍历的,就是根节点出队的时候带进左节点和右节点,然后左节点出的时候带入左节点的左节点和右节点,这样循环下去就可以遍历整个树,代码如下,队列代码文章末会附上。

void BinaryTreeLevelOrder(BTNode* root)
{Queue q;QueueInit(&q);if (root)QueuePush(&q, root);int levelSize = 1;while (!QueueEmpty(&q)){// 一层一层出while (levelSize--){BTNode* front = QueueFront(&q);QueuePop(&q);printf("%c ", front->data);if (front->left)QueuePush(&q, front->left);if (front->right)QueuePush(&q, front->right);}printf("\n");levelSize = QueueSize(&q);}printf("\n");QueueDestroy(&q);
}

6、二叉树的一些小功能

如二叉树的节点个数,这个就可以直接遍历到空节点然后返回的时候+1就可以判断出来了。

二叉树的叶子节点个数,这个也是遍历到最后一层,但是他的返回就是只有为叶子时才返回1然后左右遍历相加就可以得出。

这个就是遍历左右两边在返回时计算自己这边多高,然后谁高返回谁。

查找第k层的节点数,这个就是递归的--k,当k等于1时就到了这层,然后去计算这层有几个节点数然后左右两边一加就可以得出。

查找某个值,这里就是去遍历,然后找到了这个值后记录这个值然后进行返回这个值的地址。

判断这个树是否是完全二叉树,完全二叉树的概念在堆里面写了,他就是利用层序遍历会带出后续节点的特性去判断,当是完全二叉树时不会出现中间是空的情况。

// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{if (root == NULL)return 0;return BinaryTreeSize(root->left) +BinaryTreeSize(root->right) + 1;
}// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root)
{if (root==NULL)return 0;if (root->left == NULL && root->right == NULL){return 1;}return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}//二叉树高度
int BinaryTreeHigh(BTNode* root)
{if (root == NULL){return 0;}int LeftHigh = BinaryTreeHigh(root->left);int RightHigh = BinaryTreeHigh(root->right);return LeftHigh > RightHigh ? LeftHigh + 1 : RightHigh + 1;
}// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{assert(k > 0);if (root == NULL){return 0;}if (k == 1){return 1;}return BinaryTreeLevelKSize(root->left, k - 1)+ BinaryTreeLevelKSize(root->right, k - 1);
}// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{if (root == NULL){return NULL;}if (root->data == x){return root;}BTNode* ret1=BinaryTreeFind(root->left,x);if (ret1)return ret1;BTNode* ret2=BinaryTreeFind(root->right,x);if (ret2)return ret2;return NULL;
}// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root)
{Queue q;QueueInit(&q);if (root)QueuePush(&q, root);int levelSize = 1;while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);if (front == NULL)break;QueuePush(&q, front->left);QueuePush(&q, front->right);}// 前面遇到空以后,后面还有非空就不是完全二叉树while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);if (front){QueueDestroy(&q);return false;}}QueueDestroy(&q);return true;
}

7、测试代码、运行结果以及全部代码

这里测试是吧上文所有案例都带上了。

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "BT.h"
#include "QL.h"int main()
{char arr[] = { "ABD##E#H##CF##G##" };int pi = 0;BTNode* root = BinaryTreeCreate(arr, &pi);BinaryTreePrevOrder(root);printf("\n");BinaryTreeInOrder(root);printf("\n");BinaryTreePostOrder(root);printf("\n");BinaryTreeLevelOrder(root);printf("\n");printf("%d\n", BinaryTreeSize(root));printf("%d\n", BinaryTreeLeafSize(root));printf("%d\n", BinaryTreeHigh(root));printf("%d\n", BinaryTreeLevelKSize(root,3));printf("%d\n", BinaryTreeLevelKSize(root,4));BTNode* root1 = BinaryTreeFind(root, 'E');printf("%c\n",root1->data );printf("%d\n", BinaryTreeComplete(root));BinaryTreeDestory(root);root = NULL;return 0;
}

BT.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "BT.h"
#include "QL.h"//申请地址
BTNode* BuyNode(BTDataType* a)
{BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL){perror("malloc fail");return NULL;}newnode->data = *a;newnode->left = NULL;newnode->right = NULL;return newnode;
}// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a,int* pi)
{if (a[*pi] == '#'){(*pi)++;return NULL;}BTNode* root = BuyNode(&a[*pi]);(*pi)++;root->left = BinaryTreeCreate(a, pi);root->right = BinaryTreeCreate(a, pi);return root;
}// 二叉树销毁
void BinaryTreeDestory(BTNode* root)
{if (root == NULL)return;BinaryTreeDestory(root->left);BinaryTreeDestory(root->right);free(root);
}// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{if (root == NULL)return 0;return BinaryTreeSize(root->left) +BinaryTreeSize(root->right) + 1;
}// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root)
{if (root==NULL)return 0;if (root->left == NULL && root->right == NULL){return 1;}return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}//二叉树高度
int BinaryTreeHigh(BTNode* root)
{if (root == NULL){return 0;}int LeftHigh = BinaryTreeHigh(root->left);int RightHigh = BinaryTreeHigh(root->right);return LeftHigh > RightHigh ? LeftHigh + 1 : RightHigh + 1;
}// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{assert(k > 0);if (root == NULL){return 0;}if (k == 1){return 1;}return BinaryTreeLevelKSize(root->left, k - 1)+ BinaryTreeLevelKSize(root->right, k - 1);
}// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{if (root == NULL){return NULL;}if (root->data == x){return root;}BTNode* ret1=BinaryTreeFind(root->left,x);if (ret1)return ret1;BTNode* ret2=BinaryTreeFind(root->right,x);if (ret2)return ret2;return NULL;
}// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root)
{if (root == NULL){printf("N ");return ;}printf("%c ", root->data);BinaryTreePrevOrder(root->left);	BinaryTreePrevOrder(root->right);
}// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}BinaryTreeInOrder(root->left);printf("%c ", root->data);BinaryTreeInOrder(root->right);
}// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}BinaryTreePostOrder(root->left);BinaryTreePostOrder(root->right);printf("%c ", root->data);
}	
// 层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{Queue q;QueueInit(&q);if (root)QueuePush(&q, root);int levelSize = 1;while (!QueueEmpty(&q)){// 一层一层出while (levelSize--){BTNode* front = QueueFront(&q);QueuePop(&q);printf("%c ", front->data);if (front->left)QueuePush(&q, front->left);if (front->right)QueuePush(&q, front->right);}printf("\n");levelSize = QueueSize(&q);}printf("\n");QueueDestroy(&q);
}// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root)
{Queue q;QueueInit(&q);if (root)QueuePush(&q, root);int levelSize = 1;while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);if (front == NULL)break;QueuePush(&q, front->left);QueuePush(&q, front->right);}// 前面遇到空以后,后面还有非空就不是完全二叉树while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);if (front){QueueDestroy(&q);return false;}}QueueDestroy(&q);return true;
}

BT.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#include <string.h>
typedef char BTDataType;
typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}BTNode;
//申请地址
BTNode* BuyNode(BTDataType* a);
// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, 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);
//二叉树的高度
int BinaryTreeHigh(BTNode* root);

QL.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "QL.h"// 初始化队列 
void QueueInit(Queue* pq)
{assert(pq);pq->phead = NULL;pq->ptail = NULL;pq->size = 0;
}// 队尾入队列 
void QueuePush(Queue* pq, QDataType data)
{assert(pq);QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc fail");return;}newnode->data = data;newnode->next = NULL;if (pq->ptail == NULL){assert(pq->phead==NULL);pq->phead = pq->ptail = newnode;}else{pq->ptail->next = newnode;pq->ptail = newnode;}pq->size++;
}// 队头出队列 
void QueuePop(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));if (pq->phead->next == NULL){free(pq->phead);pq->phead = pq->ptail = NULL;}else{QNode* next = pq->phead->next;free(pq->phead);pq->phead = next;}pq->size--;
}// 获取队列头部元素 
QDataType QueueFront(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->phead->data;
}// 获取队列队尾元素 
QDataType QueueBack(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->ptail->data;
}// 获取队列中有效元素个数 
int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->size==0;
}// 销毁队列 
void QueueDestroy(Queue* pq)
{assert(pq);QNode* cur = pq->phead;while (cur){QNode* next = cur->next;free(cur);cur = next;}pq->phead = pq->ptail = NULL;pq->size = 0;
}

QL.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef int QDataType;
// 链式结构:表示队列 
typedef struct QueueNode
{struct QueueNode* next;QDataType data;}QNode;// 队列的结构 
typedef struct Queue
{QNode* phead;QNode* ptail;int size;
}Queue;// 初始化队列 
void QueueInit(Queue* pq);
// 队尾入队列 
void QueuePush(Queue* pq, QDataType data);
// 队头出队列 
void QueuePop(Queue* pq);
// 获取队列头部元素 
QDataType QueueFront(Queue* pq);
// 获取队列队尾元素 
QDataType QueueBack(Queue* pq);
// 获取队列中有效元素个数 
int QueueSize(Queue* pq);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
bool QueueEmpty(Queue* pq);
// 销毁队列 
void QueueDestroy(Queue* pq);

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

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

相关文章

redis常用五大数据类型

目录 Key 字符串String 常用命令 列表List 常用命令 集合Set 常用命令 Hash哈希 键值对集合 有序集合Zset Redis新数据类型 Key set key value...添加keykeys *查看当前库中所有的keyexist key该key是否存在type keykey的类型del key删除keyunlink key根据value选择非阻塞…

C++ UML类图

参考文章&#xff1a; &#xff08;1&#xff09;C UML类图详解 &#xff08;2&#xff09;C基础——用C实例理解UML类图 &#xff08;3&#xff09;C设计模式——UML类图 &#xff08;4&#xff09;[UML] 类图介绍 —— 程序员&#xff08;灵魂画手&#xff09;必备画图技能之…

2 使用GPU理解并行计算

2.1 简介 本章旨在对并行程序设计的基本概念及其与GPU技术的联系做一个宽泛的介绍。本章主要面向具有串行程序设计经验&#xff0c;但对并行处理概念缺乏了解的读者。我们将用GPU的基本知识来讲解并行程序设计的基本概念。 2.2 传统的串行代码 绝大多数程序员是在串行程序占据…

手撕算法-二叉树的最大深度

描述&#xff1a;分析&#xff1a;求以节点root为根节点的树的最大深度。可以进行拆分&#xff1a;root为根节点的树的最大深度 max(左子树的最大深度, 右子树最大深度&#xff09;1 截止条件是节点为空&#xff0c;深度为0&#xff1b; 代码&#xff1a; public int maxDep…

HarmonyOS如何创建及调用三方库

介绍 本篇主要向开发者展示了在Stage模型中&#xff0c;如何调用已经上架到三方库中心的社区库和项目内创建的本地库。效果图如下&#xff1a; 相关概念 Navigation&#xff1a;一般作为Page页面的根容器&#xff0c;通过属性设置来展示页面的标题、工具栏、菜单。Tabs&#…

Java + sa-token统一身份认证开发笔记

官网地址&#xff1a;Sa-Token 统一认证服务端 直接用的官网的demo&#xff0c;稍加改动&#xff0c;因为要前后端分离&#xff0c;加了一个H5Controller&#xff0c;官网也有详细介绍&#xff0c;这一部分不难&#xff0c;照着做就行了 配置文件&#xff1a; # Sa-Token 配…

vo、po、dto、bo、pojo、entity

VO&#xff1a;Value Object&#xff0c;值对象。 通常用于业务层之间的数据传递&#xff0c;由new创建&#xff0c;由GC回收&#xff1b;例如&#xff1a;将商品信息和用户信息重新用一个对象封装起来。和PO一样也是仅仅包含数据而已&#xff0c;但应是抽象出的业务对象&…

全网良心开源知识库:AI学习者的宝藏之地

导语&#xff1a;在这个信息爆炸的时代&#xff0c;想要入门AI&#xff0c;找到最一流的学习资源并非易事。然而&#xff0c;有一个地方&#xff0c;能让你免费学习AI&#xff0c;获取最顶尖的知识&#xff0c;还能加入最优秀的AI学习圈。今天&#xff0c;我要向大家推荐的&…

Jumpserver 堡垒机用户启用双因子登录

前言&#xff1a; 堡垒机双因子登录 堡垒机往往是内部权限的集合体&#xff0c;拿到了堡垒机的用户账号密码&#xff0c;很容易就顺藤摸瓜攻破各种应用系统&#xff0c;除了常规的用户名复杂密码的要求外&#xff0c;我们常常都要求采用双因子的登录方式。双因子最常见的就是账…

【Qt学习笔记】(六)界面优化

界面优化 1 QSS1.1 背景介绍1.2 基本语法1.3 QSS设置方式1.3.1 指定控件样式设计1.3.2 全局样式设置1.3.3 使用 Qt Designer 编辑样式 1.4 选择器1.4.1选择器概况1.4.2 子控件选择器&#xff08;Sub-Controls&#xff09;1.4.3伪类选择器(Pseudo-States) 1.5 样式属性1.5.1 盒模…

MyBatis:编织数据之美的艺术

在数据库交互的舞台上&#xff0c;MyBatis就如同一位出色的编码艺术家&#xff0c;通过其独特的姿态和技巧&#xff0c;将数据库操作变得既优雅又高效。在这篇博客中&#xff0c;我们将深入研究MyBatis的使用详解&#xff0c;揭开其中的奥秘&#xff0c;感受数据之美的艺术之旅…

SpringCloud-Nacos配置管理

在nacos中添加配置文件 如何在nacos中管理配置呢&#xff1f; 然后在弹出的表单中&#xff0c;填写配置信息&#xff1a;如&#xff1a;userservice-dev.yaml 注意&#xff1a;项目的核心配置&#xff0c;需要热更新的配置才有放到nacos管理的必要。基本不会变更的一些配置…

【机器学习】基于麻雀搜索算法优化的BP神经网络分类预测(SSA-BP)

目录 1.原理与思路2.设计与实现3.结果预测4.代码获取 1.原理与思路 【智能算法应用】智能算法优化BP神经网络思路【智能算法】麻雀搜索算法&#xff08;SSA&#xff09;原理及实现 2.设计与实现 数据集&#xff1a; 多输入多输出&#xff1a;样本特征24&#xff0c;标签类别…

linux服务器上遇到杀不死的进程怎么办?

想要结束某个进程时&#xff0c;一般会先top一下找到进程号&#xff0c;然后kill xxx。 然而&#xff0c;我最近发现一个两百多兆的进程一直杀不死&#xff0c;kill完一个还会自动产生新的。 此时&#xff0c;可以用以下指令找到自己名下所有正在运行的进程&#xff0c;对症下药…

解决在命令行中输入py有效,输入python无效,输入python会跳转到microsoft store的问题| Bug

目录 如果你已经尝试过将python添加到系统变量在系统变量里把你自己的路径放到应用商店的路径之前删除windowsapps下的python.exe文件 如果你还未将python添加到系统变量没有python安装包且没有配置系统变量 如果你已经尝试过将python添加到系统变量 打开 运行&#xff0c;输入…

【linux】环境基础|开发工具|gcc|yum|vim|gdb|make|git

目录 ​编辑 Linux 软件包管理器 yum 软件包: 操作&#xff1a; 拓展&#xff1a;lrzsz简介 Linux开发工具 Linux编辑器-vim使用 vim 的基本概念 命令模式 插入模式 底行模式 vim 命令模式的操作指令 vim 底行模式的操作命令 Linux编译器-gcc/g使用 功能 格…

5_springboot_shiro_jwt_多端认证鉴权_禁用Cookie

1. Cookie是什么 ​ Cookie是一种在客户端&#xff08;通常是用户的Web浏览器&#xff09;和服务器之间进行状态管理的技术。当用户访问Web服务器时&#xff0c;服务器可以向用户的浏览器发送一个名为Cookie的小数据块。浏览器会将这个Cookie存储在客户端&#xff0c;为这个Co…

java的前缀和算法

前缀和的概念 对于一个给定的数组A&#xff0c;它的前缀和数组S中S[i]表示从第1个元素到第i个元素的总和&#xff0c;用公式表示为&#xff1a; SiA1A2A3...An 前缀和的作用 在O(1)的时间求出数组任意区间的区间和。 降低求解的复杂度 算法模板 int n10; int [] arrnew in…

【Linux】盘点广义层面上【三种最基本的进程状态】

前言 大家好吖&#xff0c;欢迎来到 YY 滴 Linux系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过Linux的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的…

SQL语句之SELECT语句

一般格式 SELECT DISTINCT/ALL 目标列表达式 //要显示的属性列 FROM 表名/视图名 //查询的对象 WHERE 条件表达式 //查询条件 GROUP BY 列名 HAVING 条件表达式 //查询结果分组 ORDER BY 列名 次序; //最终查询结果排序 文章目录 一、基本查询 1、SELECT 目标列表达…