数据结构------二叉树简单介绍及实现

news2024/9/20 14:43:25

如果不是满二叉树或者完全二叉树,就要用链式存储

//搜索二叉树:左子树的所有值比根小,右子树的所有值比根大

//                      实现查找,最多找高度次(类似二分法)

//二分查找存在的问题:排序;必须对数组操作,插入删除不方便。

//同一个函数不同的值递归占用的空间是一样的,因为销毁了之后再接着用

//不能递归的深度太深,不然会导致栈溢出

//这段二叉树的递归代码编译完了之后是一份指令,这份指令会自己调用自己,不断建立栈帧,然后销毁栈帧

//一些基本知识点

满二叉树每层节点个数构成一个等比数列

增加一个度为1的节点,一定减少一个度为0的节点。增加一个度为2的节点,一定增加一个度为0的,减少一个度为1的。因为0变到1再变到2。

//由性质3得:

//注意:完全二叉树度为1的节点只可能为1或0

//用满二叉树公式来推,计算一个大概的范围

//根据前序.中序序列写出二叉树

//前序确定根,中序分割左右子树

//一定注意7是右子树,因为中序是左根右

//递归的逻辑过程

//递归的物理过程

//通过ebp(高地址,用来保存主调函数的下一行指令)和esp(低地址,不断建立栈帧开辟空间)

//static静态变量只初始化一次,在多次调用的时候会出现问题,可以改为指针或全局变量(最好不要用),全局变量每次使用的时候记得进行初始化

//求节点个数采用分治思想:分而治之,上一层来指挥下一层

//求叶子节点个数:

//这样写就出错了,当该树为空或者没有左/右结点的时候,访问空指针的下一个节点就崩溃了

//所以应该单独讨论节点为空的时候

//求二叉树高度:

//错误做法:效率问题,超出时间限制

计算左/右子树高度值,左边递归到6,6的左右节点都为0,然后6的值为1。

然后回溯到3,3的左子树返回0,右子树返回1,相比较右子树高度大,即计算右子树高度+1,又因为此时并没有保存6的高度为1这个值,还要继续计算3的右子树6的左子树和右子树的高度值再比较然后再回溯到3,把值+1赋值给3这个节点。

然后3向上回溯到2,2的左子树的高度值为2,右子树高度值为0,相比较应该取左子树的高度值。但此时这个值并没有保存下来,应该再计算3的高度值,此时3的高度值未知,要比较3的左右子树的高度值......(计算方法同上一段)

//综述:节点深度越深,该节点计算次数成倍数增加

//正确做法(把值记录下来):

//总的代码:

//实现二叉树
typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;

BTNode* BuyNode(int x)
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	if (node == NULL)
	{
		perror("malloc fail");
		return NULL;
	}

	node->data = x;
	node->left = NULL;
	node->right = NULL;

	return node;
}

BTNode* CreatBinaryTree()
{
	BTNode* node1 = BuyNode(1);
	BTNode* node2 = BuyNode(2);
	BTNode* node3 = BuyNode(3);
	BTNode* node4 = BuyNode(4);
	BTNode* node5 = BuyNode(5);
	BTNode* node6 = BuyNode(6);
	BTNode* node7 = BuyNode(6);


	node1->left = node2;
	node1->right = node4;
	node2->left = node3;
	node4->left = node5;
	node4->right = node6;
	node5->right = node7;

	return node1;
}

//遍历只需要注意顺序就好,打印的都是data
//前序遍历
void PrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}

	printf("%d ", root->data);
	PrevOrder(root->left);
	PrevOrder(root->right);
}
//中序遍历
void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}

	InOrder(root->left);
	printf("%d ", root->data);
	InOrder(root->right);
}

int fun(int n)
{
	if (n == 0)
		return 0;

	return fun(n - 1) + n;
}

// 错误示范
//错因:不能用静态变量,因为如果调用多次这个函数的话,size是一直累加的
//     不能计算出每一次调用时的节点个数
//int TreeSize(BTNode* root)
//{
//	static int size = 0;
//	if (root == NULL)
//		return 0;
//	else
//		++size;
//
//	TreeSize(root->left);
//	TreeSize(root->right);
//
//	return size;
//}
//以下两种解法太复杂
//解法1:把它变成全局变量,并且要注意在每次主函数中调用该函数之前要把size初始化为零
//int size = 0;
//int TreeSize(BTNode* root)
//{
//	if (root == NULL)
//		return 0;
//	else
//		++size;
//
//	TreeSize(root->left);
//	TreeSize(root->right);
//
//	return size;
//}
//解法2:把size的指针传进去,通过指针解引用再++来改变size的值
//void TreeSize(BTNode* root, int* psize)
//{
//	if (root == NULL)
//		return 0;
//	else
//		++(*psize);
//
//	TreeSize(root->left, psize);
//	TreeSize(root->right, psize);
//}

//求节点个数
//采用分治递归的思想
//1.该节点不存在:节点数为零
//2.该节点存在,节点数=左子树节点数+右子树节点数+1
int TreeSize(BTNode* root)
{
	return root == NULL ? 0 :
		TreeSize(root->left) + TreeSize(root->right) + 1;
}

//求叶子节点个数
int TreeLeafSize(BTNode* root)
{
	if (root == NULL)
		return 0;

	if (root->left == NULL && root->right == NULL)
		return 1;

	return TreeLeafSize(root->left)
		+ TreeLeafSize(root->right);
}

//求深度(树高)
int TreeHeight(BTNode* root)
{
	if (root == NULL)
		return 0;

	int leftHeight = TreeHeight(root->left);
	int rightHeight = TreeHeight(root->right);

	return leftHeight > rightHeight ?
		leftHeight + 1 : rightHeight + 1;
}

// 有效率问题
int TreeHeight(BTNode* root)
{
	if (root == NULL)
		return 0;

	return TreeHeight(root->left) > TreeHeight(root->right) ?
		TreeHeight(root->left) + 1 : TreeHeight(root->right) + 1;
}

//int fmax(int x, int y)
//{
//	return x > y ? x : y;
//}

//int TreeHeight(BTNode* root)
//{
//	if (root == NULL)
//		return 0;
//
//	return fmax(TreeHeight(root->left), TreeHeight(root->right)) + 1;
//}

int main()
{
	BTNode* root = CreatBinaryTree();
	PrevOrder(root);
	printf("\n");

	InOrder(root);
	printf("\n");

	//递归太深导致栈溢出
	//printf("%d\n", fun(10000));

	/*int size = 0;
	TreeSize(root, &size);
	printf("TreeSize:%d\n",size);

	size = 0;
	TreeSize(root, &size);
	printf("TreeSize:%d\n", size);*/

	printf("TreeSize:%d\n", TreeSize(root));
	printf("TreeLeafSize:%d\n", TreeLeafSize(root));
	printf("TreeHeight:%d\n", TreeHeight(root));

	return 0;
}

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

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

相关文章

【C++】——多态详解

目录 1、什么是多态? 2、多态的定义及实现 2.1多态的构成条件 ​2.2多态语法细节处理 2.3协变 2.4析构函数的重写 2.5C11 override 和 final关键字 2.6重载—重写—隐藏的对比分析 3、纯虚函数和抽象类 4、多态的原理分析 4.1多态是如何实现的 4.2虚函数…

TESSY创建需要高级桩的测试用例

需要打高级桩的情况如下: 1) 使用到桩函数的返回值; 2) 如果函数有形参,并且需要接口传参检测; 我们以tessy5.1 IDE为例,给大家展示编写一个需要高级桩的测试用例过程。 1、前期的准备工作 可以参考以下文章&…

mac命令行分卷压缩与合并

mac下默认可用命令行分卷压缩 例:一个900k的压缩包名为hello.zip,将其分割为每500K一个zip zip - hello.zip | split -b 500k -a 3 - file.zip.part_ 其他可自定义分割体积,如 -b 10m -b 10g k,m,g无视大小写 打包结果如图所示 分卷合并 #合成一个大文件 cat file.zip.part…

中电信翼康基于Apache Dolphinscheduler重构“星海·济世医疗数据中台”实践经验分享

文章作者:尚志忠 编辑整理:曾辉 行业背景 随着大数据、云计算、5G、人工智能等技术的快速发展,以及医疗信息化建设的不断深入,数据中台作为打通医疗数据融合壁垒、实现数据互通与共享、构建高效数据应用的关键信息平台&#xf…

U 盘显示需要格式化才能用?一针见血的修复方法在这里!速看!

在日常使用电脑的过程中,我们常常会遇到各种让人头疼的问题,其中之一就是当插入 U 盘时,突然弹出提示 “U 盘需要格式化才能使用”。这可让很多人慌了神,毕竟 U 盘里可能存储着重要的文件资料。别着急,下面就为大家介绍…

基于eBPF的procstat软件追踪程序垃圾回收(GC)事件

在性能敏感的应用程序中,偶尔遇到程序无故卡顿是开发者们常见的挑战之一。这种现象可能会表现为突然的延迟、系统响应时间增加、吞吐量的下降。这类问题的根源可能是编程语言的垃圾回收(Garbage Collection,GC)导致,尤…

超易用的AI训练页面!训练推理一体化助你快速炼制AI模型!

模型训练页面展示 AI绘画的热度也不是一天两天了。之前很火的粘土画风转换、AI漫画风格图像等等也都是由AI绘画来实现的。但要想训练一个模型需要很多繁琐的步骤,甚至很多小白都找不到训练模型的资源。 不过现在这个问题已经不需要担心了,厚德云推出了一…

vue websocket 使用

基于webSocket通信的库主要有 socket.io,SockJS 关于SockJS的使用 先安装 sockjs-client 和 stompjs npm install sockjs-client npm install stompjs import SockJS from sockjs-client; import Stomp from stompjs; export default { data () { …

一文看懂Elasticsearch的技术架构:高效、精准的搜索神器

一、概述 Elasticsearch 以其强大的全文本搜索功能而闻名。速度之所以这么快,因为 Elasticsearch 核心采用的是倒排索引;它功能之所以这么强大,是因为采用了可调相关度分数、高级查询 DSL 以及可提升搜索能力的诸多功能。 然而全文本搜索只是…

OpenCV特征检测(4)检测图像中的角点函数cornerHarris()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 Harris 角点检测器。 该函数在图像上运行 Harris 角点检测器。类似于 cornerMinEigenVal 和 cornerEigenValsAndVecs,对于每个像素 (…

LeetCode[中等] 54.螺旋矩阵

给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。 思路:定义方向数组,按照顺时针顺序:右(0,1),下(1,0),左(0,-1),上(0,-1) 从矩阵的左上角开始遍历…

卷积参数量计算公式

1. 普通卷积(Standard Convolution) 普通卷积的参数量计算包括卷积核的权重和可能的偏置项。 2. 深度卷积(Depthwise Convolution) 深度卷积是逐通道的卷积操作,每个输入通道都有一个独立的卷积核。 3. 逐点卷积&…

骨传导耳机哪个牌子好?盘点口碑最好的5款骨传导耳机!

在快节奏的现代生活中,耳机成为了我们与外界沟通的重要桥梁,无论是在通勤路上、健身锻炼,还是在工作学习中,耳机都扮演着不可或缺的角色。而在众多耳机类型中,骨传导耳机以其独特的声音传导方式和健康舒适的佩戴体验&a…

C语言中的assert断言

Assert断言 断言是程序中处理异常的一种高级形式。可以在任何时候启用和禁用断言验证,因此可以在测试时启用断言,而在部署时禁用断言。同样,程序投入运行后,最终用户在遇到问题时可以重新启用断言。 用法: #…

Qt窗口——QDockWidget

文章目录 浮动窗口浮动窗口使用示例 浮动窗口 QDockWidget浮动窗口可以认为是子窗口,每一个子窗口都可以停靠在四周,像Qt Creator页面,就很多的子窗口: 浮动窗口使用示例 创建: QDockWidget* dockWidget new QDock…

宝马I-Plus手动变速器、K手动变速器、G手动变速器解析

(一) I-Plus手动变速器 1、技术特点 (1)改进齿轮组件结构。I-Plus手动变速器采用第四挡(直接挡)高转速方案,这样可以在保持轴中心距不变的前提下减小啮合力。由此提高驱动力矩后,使得在带有N53B3000发动机的528i车型上首次使用 I 手动变速器。 对啮合面几…

Python精选200Tips:151-155

实战项目 P151--气象数据爬取技术栈:数据爬虫P152--求解数独问题技术栈:代码逻辑+回溯法P153--疾病传播模型的100天模拟技术栈:SIR 模型(易感-感染-恢复模型)P154--复杂函数的最值求解技术栈:粒子群优化算法P155-- 评论情感分析技术栈:snownlp和jieba的应用运行系统:ma…

Opencv+Cuda编译的保姆级别教程

OpencvCuda编译的保姆级别教程 一、环境总览二、环境准备2.1 opencv和opencv扩展2.2 cuda环境下载2.2.1 首先电脑要有英伟达的显卡2.2.2 然后查看显卡驱动版本2.2.3 下载Cuda Toolkit工具包2.2.4 下载Cudnn库 2.3 CMake下载 三、CMake配置步骤3.1 加载路径第一次Configure3.1.1…

前端——表格、列表标签

今天我们来学习一下web开发里面的表格标签、列表标签 常用快捷键&#xff1a; shift alt 下 复制粘贴选中内容 表格标签 table HTML 表格由 <table> 标签来定义。 HTML 表格是一种用于展示结构化数据的标记语言元素。 每个表格均有若干行&#xff08;由 <tr>…

yolov5测试代码

一般源码的测试代码涉及很多文件&#xff0c;因项目需要写一个独立测试的代码。传入的是字典 import time import cv2 import os import numpy as np import torch from modules.detec.models.common import DetectMultiBackend from modules.detec.utils.dataloaders import …