数据结构之二叉树的基本实现

news2024/11/25 23:33:39

在我们之前已经了解的堆这样的完全二叉树的实现,也对树型结构有了一些了解,那么今天我们来看看二叉树的一些性质。

因为二叉树是一种每个节点至多只有两个子树(即二叉树的每个节点的度不大于2),并且二叉树的子树有左右之分,其次序不能任意颠倒,因此它的结构也是比较独特的。

目录

1.二叉树的结构定义

2.节点构造

3.节点生成树

3.二叉树的遍历方式

先序遍历:

中序遍历:

后序遍历

层次遍历:

4.求树的所有节点个数

5.求叶子节点个数

6.求二叉树树深度

7.二叉树第K层节点个数

8.返回值为x的节点


1.二叉树的结构定义

二叉树是一种每个节点至多只有两个子树(即二叉树的每个节点的度不大于2),并且二叉树的子树有左右之分,其次序不能任意颠倒。

//定义树的节点
typedef int DATAtype;
typedef struct TreeNode
{
	DATAtype data;
	struct TreeNode* leftchild;
	struct TreeNode* rightchild;
}BTnode;

2.节点构造

简单的节点构造,如同链表的结点,不同的是这里有两个节点表示左孩子与右孩子。

//构造树的节点
BTnode* CreateNode(DATAtype x)
{
	BTnode* newnode = (BTnode*)malloc(sizeof(BTnode));
	if (newnode == NULL)
	{
		perror("malloc fali");
		return NULL;
	}
	newnode->data = x;
	newnode->leftchild = NULL;
	newnode->rightchild = NULL;
	return newnode;
}

3.节点生成树

我们是通过链接节点之间形成树的逻辑关系,这里的树如图:

 先链接了六个节点,之后又添加了一个节点

//利用节点生成一个树
BTnode* TreeCreat()
{
	BTnode* node1=CreateNode(1);
	BTnode* node2=CreateNode(2);
	BTnode* node3=CreateNode(3);
	BTnode* node4=CreateNode(4);
	BTnode* node5=CreateNode(5);
	BTnode* node6=CreateNode(6);
	BTnode* node7 = CreateNode(6);
	//建立连接关系
	node1->leftchild = node2;
	node1->rightchild = node4;
	node2->leftchild = node3;
	node4->leftchild = node5;
	node4->rightchild = node6;
	node6->leftchild = node7;
	//返回根
	return node1;
}

3.二叉树的遍历方式

二叉树的遍历方式主要有四种,分别是先序遍历、中序遍历、后序遍历和层次遍历。123

先序遍历:

先访问根节点,再访问左子树,最后访问右子树。

//前序遍历
void Preverorder(BTnode*root)
{
	//根 左子树 右子树
	if (root == NULL)
	{
		return;
	}
	printf("%d ", root->data);
	Preverorder(root->leftchild);
	Preverorder(root->rightchild);

}


中序遍历:

先访问左子树,再访问根节点,最后访问右子树。

void Inorder(BTnode* root)
{
	// 左子树 根  右子树
	if (root == NULL)
	{
		return;
	}
	
	Preverorder(root->leftchild);
	printf("%d ", root->data);
	Preverorder(root->rightchild);

}


后序遍历

:先访问左子树,再访问右子树,最后访问根节点。

void Postorder(BTnode* root)
{
	// 左子树 右子树 根 
	if (root == NULL)
	{
		return;
	}

	Preverorder(root->leftchild);
	Preverorder(root->rightchild);
	printf("%d ", root->data);
	
}


层次遍历:

按照从上到下、从左到右的顺序依次访问每个节点。

层序遍历我们使用队列实现,思路:先进先出,上一层出队时带下一层节点入队。

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include"queue.h"
#define CRT_SECURE_NO_WARNINGS 1

//定义树的节点
typedef int DATAtype;
typedef struct TreeNode
{
	DATAtype data;
	struct TreeNode* leftchild;
	struct TreeNode* rightchild;
}BTnode;

//构造树的节点
BTnode* CreateNode(DATAtype x)
{
	BTnode* newnode = (BTnode*)malloc(sizeof(BTnode));
	if (newnode == NULL)
	{
		perror("malloc fali");
		return NULL;
	}
	newnode->data = x;
	newnode->leftchild = NULL;
	newnode->rightchild = NULL;
	return newnode;
}
//利用节点生成一个树
BTnode* TreeCreat()
{
	BTnode* node1=CreateNode(1);
	BTnode* node2=CreateNode(2);
	BTnode* node3=CreateNode(3);
	BTnode* node4=CreateNode(4);
	BTnode* node5=CreateNode(5);
	BTnode* node6=CreateNode(6);
	BTnode* node7 = CreateNode(6);
	//建立连接关系
	node1->leftchild = node2;
	node1->rightchild = node4;
	node2->leftchild = node3;
	node4->leftchild = node5;
	node4->rightchild = node6;
	node6->leftchild = node7;
	//返回根
	return node1;
}

 层序遍历:

//层序遍历
void leverorder(BTnode* root)
{
	LTnode p;
	Queueinit(&p);
	Queuedestroy(&p);
	//先入根节点
	if (root)
	{
		LTpush(&p, root);
	}
	while (!LTempety(&p))
	{
		//队中数据全是树节点指针型
		BTnode* front = LTfront(&p);
			LTpop(&p);//出队头

			printf("%d", front->data);
         //判断孩子节点
			if (front->leftchild)
			{
				LTpush(&p, front->leftchild);
			}
			if (front->rightchild)
			{
				LTpush(&p, front->rightchild);
			}
	}
	printf("\n");
}

4.求树的所有节点个数

这里有两种方法,除了定义全局变量利用计数的方法来计算树的节点个数,但还需注意全局变量使用后需置零,其次我们也是利用递归的返回值累加计算出节点个数。

//求树的所有节点个数
int size = 0;
int Binarytreesize(BTnode* root)
{
	/*分治思想  从左子树到右子树再到根*/
	if (root == NULL)
	{
		return 0;
	}
	return (1 + Binarytreesize(root->leftchild) + Binarytreesize(root->rightchild));


	/*if (root)
	{
		size++;
		Binarytreesize(root->leftchild);
		Binarytreesize(root->rightchild);
	}
	return size;*/
}

5.求叶子节点个数

寻找递归条件,叶子节点没有左右孩子,否则就不返回一,符合条件的返回一相加。注意递归中返回值的设定。

//求叶子节点个数
int BTreeleavessize(BTnode* root)
{
	//自己的左子树与左右子树为空
	if (root == NULL)
	{
		return 0;
	}
	if (root->leftchild == NULL && root->rightchild == NULL)
	{
		return 1;
	}
	else
	{
		return BTreeleavessize(root->leftchild) + BTreeleavessize(root->rightchild);
	}
}

6.求二叉树树深度

分治思想,两边同时遍历,每有一层加一,左孩子层数与右孩子层数中较大的那个就是深度。

//求二叉树的深度
int BTreeheight(BTnode* root)
{
	//左右同时遍历,选最大的哪一个
	if (root == NULL)
	{
		return 0;
	}
	//这里注意用变量保存一下左 右子树的数目
	int left = BTreeheight(root->leftchild) + 1;
	int right= BTreeheight(root->rightchild) + 1;
	if (left > right)
	{
		return left;
	}
	else
	{
		return right;
	}
}

7.二叉树第K层节点个数

这里的递归主要是找的第k层,利用k==1作为递归返回条件。

//二叉树第k层结点的个数
int BTree_knumber(BTnode* root,int k)
{
	//分情况讨论
	if (root == NULL)
	{
		return 0;
	}
	if (k==1)
	{
		return 1;
	}

	return  BTree_knumber(root->leftchild, k - 1) +
			BTree_knumber(root->rightchild, k - 1);

	
	
}

8.返回值为x的节点

这里的难度在与返回值,我们知道在递归里面函数返回值不能直接返回,我们需要判断,对于返回值是需要我们好好检查的,在这里,我们从根,左孩子,右孩子的顺序逐个判断,对于左右孩子并保存返回值,来确定是当前节点。

//返回为x的树节点
BTnode* BTreenode(BTnode* root, DATAtype x)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->data == x)
	{
		return root;
	}
	
	BTnode* left = BTreenode(root->leftchild,x);
	
	if (left->data==x)
	{
		return left;
	}
	BTnode* right = BTreenode(root->rightchild,x);
	if (right->data==x)
	{
		return right;
	}
	return NULL;
}

一些测试用例:

int main()
{
	BTnode* root = TreeCreat();
	/*Preverorder(root);
	printf("\n");
	Inorder(root);
	printf("\n");
	Postorder(root);*/
	//Binarytreesize(root);
	// BTreeleavessize(root);//BTreeheight(root);
	int x = BTree_knumber(root, 2);

	printf("%d ", BTreenode(root, 2)->data);
	//printf("%d", x);
	return 0;
}

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

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

相关文章

二、Django REST Framework (DRF)序列化反序列化数据校验

参考&#xff1a; DRF 官方文档&#xff1a; Serializers - Django REST framework中文站点 为什么要学DRF和什么是REST API | 大江狗的博客 上一章&#xff1a; 一、Django REST Framework (DRF)& RESTful 风格api_做测试的喵酱的博客-CSDN博客 下一章&#xff1a;…

【C++】类和对象(中上):类的六个默认成员函数——构造函数、析构函数、拷贝构造函数!

目录 前言&#xff1a; 一、类的默认成员函数&#xff1a; 二、构造函数&#xff1a; 1.特性&#xff1a; 构造函数调用规则&#xff1a; 1.无参数的构造函数&#xff08;默认构造函数&#xff09;&#xff1a; 2.带参数的构造函数&#xff1a; 3.全缺省的构造函数&…

Qt编写视频监控系统75-计算实时码率并显示

一、前言 做监控摄像头的实时视频显示&#xff0c;一般还会要求统计实时码率显示在通道画面上&#xff0c;一个是为了测试下整个软件的性能&#xff0c;同时也看下当前到底是主码流还是子码流&#xff0c;设备到底是不是真的按照设定的码流大小来传输视频数据的。视频码率就是…

【Mysql】 数据类型

文章目录 【Mysql】 数据类型数据类型分类数值类型1. tinyint类型2. bit类型3. 小数类型 字符串类型1.char2.varchar3. 日期和时间类型4. enum 和 set 【Mysql】 数据类型 mysql中数据类型的作用&#xff1a; 约束操作者的行为更清晰的代码逻辑不同的功用 – 例如&#xff0c…

【JavaSE】Java基础语法(八)

文章目录 &#x1f353;1. 类和对象&#x1f379;&#x1f379;1.1 类和对象的关系&#x1f379;&#x1f379;1.2 类的定义 &#x1f353;2. 对象内存图&#x1f379;&#x1f379;2.1 单个对象内存图&#x1f379;&#x1f379;2.2 多个对象内存图2.3 多个对象指向相同内存图…

统计学_贾俊平——思考题第9章 分类数据分析

1&#xff0e;简述列联表的构造与列联表的分布。 答&#xff1a;列联表是将两个以上的变量进行交叉分类的频数分布表。 列联表的分布可以从两个方面看&#xff0c;一个是观察值的分布&#xff0c;又称为条件分布&#xff0c;每个具体的观察值就是条件频数&#xff1b;一个是期望…

【数据结构】树的认识

一个人的未来不是预测出来的&#xff0c;而是创造出来的。 -- 亚当詹姆斯目录 &#x1f341;前言&#xff1a; &#x1f340;一.什么是树&#xff1f; &#x1f351;二.树有什么用&#xff1f; ❤️1. 数据库 &#x1f9e1;2. 文件系统 &#x1…

chatgpt赋能python:PythonUSB摄像头-拍摄更美好的瞬间

Python USB摄像头 - 拍摄更美好的瞬间 在过去的几年中&#xff0c;摄影已经迅速成为了一种爆炸性的趋势。人们希望能够记录下人生中的美好瞬间&#xff0c;分享给全球的亲朋好友。而USB摄像头的普及与发展使得照片拍摄变得更加便利。而在这其中&#xff0c;Python也扮演了一个…

spingboot+jsp仓储型物流企业车辆运输管理系统

随着时代的进步,物流车辆运输行业也逐渐变得庞大起来。当然,物流车辆运输公司要想做大做强,就有必要有自己完整的一套物流车辆运输管理系统。这必将为物流管理公司提供规范化的管理模式,在各个部门之间有效的协调、合作过程中必将为物流车辆公司提供大量的客户生源,争取赢得最大…

6.4_7关键路径

上一节我们学的叫做AOV网&#xff08;activity on vertex&#xff09; 这一节我们是(activity on edge network) 顶点表示事件是一瞬间发生的事情。边上的权值表示完成该活动的开销。 AOE网中&#xff0c;有些事情是可以并行的。 前后活动之间存在依赖关系&#xff0c;我i们要知…

python绘制密度图

本期目录 1、绘图参数2、使用 matplotlib 库绘制密度图时常用的参数3、案例4、 运行结果python绘图往期系列文章目录 1、绘图参数 可以使用多种库来绘制密度图&#xff0c;其中最常用的是 seaborn 和 matplotlib。以下是使用 seaborn 库绘制密度图时常用的参数&#xff1a; i…

简历上,我写精通 JUC 的底气

真的假的&#xff0c;你简历上敢写精通 JUC &#xff1f; 是真学到精通了&#xff0c;还是说只学到了个皮毛就写精通&#xff0c;从而争取一个面试机会。 我相信&#xff0c;当很多人看到文章标题的第一反应也会如上面的一样&#xff0c;质疑、好奇。这很正常&#xff0c;如果…

手把手教你用Python调用彩云机器翻译API

一、引言 彩云这个小而美的机器翻译一直很低调&#xff0c;它让人眼前一亮的是之前我们分享的网页翻译插件&#xff0c;可以把外文网站翻译成英中对照的样式&#xff0c;便于我们学习。之前我们也写过文章介绍过&#xff1a; PythonFan&#xff1a;如何用Google翻译英文网页成…

c++学习——类和对象

类和对象的基本概念 类是自定义数据类型&#xff0c;是C语言的结构体进化而成的 对象是类实例化出的&#xff0c;用数据类型定义一个变量 #define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std;class Maker //这个是类 { public:int a;//成员属性…

PostgreSQL EDB 公司推出新服务,ORACLE 平移到 POSTGRESQL 一体化服务

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友会分到2群&#xff08;共…

创建本地LocalHost-SSL证书

mkcert 使用方法 mkcert 是一个开源工具&#xff0c;用于快速生成有效的本地开发证书。它可以帮助开发人员在本地环境中使用 HTTPS 加密来模拟真实的生产环境。 安装 首先&#xff0c;你需要安装 mkcert 工具。以下是在常见操作系统上安装的命令&#xff1a; macOS 使用 Homebr…

集简云数据表无需代码连接抖音的方法

使用场景 抖音作为自媒体时代的主流平台&#xff0c;越来越多的企业选择通过短视频来推广自己的产品或者吸引更多粉丝。那么随时关注抖音视频下的评论&#xff0c;了解用户的想法和需求&#xff0c;并针对不同的评论提供更好的回应是每一位运营的重点工作之一&#xff0c;但是运…

利用 PRIMO 重构 M87 黑洞图像,普林斯顿高等研究院成功将「甜甜圈」变身「金戒指」...

By 超神经 内容一览&#xff1a;2019 年&#xff0c;「事件视界望远镜 (Event Horizon Telescope&#xff0c;简称 EHT)」全球研究团队发布了人类历史上第一张黑洞照片&#xff0c;受限于当时的观测条件&#xff0c;这张黑洞图像只呈现出一个模糊不清的轮廓。近日&#xff0c;天…

研发工程师玩转Kubernetes——自动扩缩容

在《研发工程师玩转Kubernetes——使用Deployment进行多副本维护》一文中&#xff0c;我们通过Deployment实现了多副本维护——即维持在一个确定数量的副本个数。而在现实场景中&#xff0c;我们往往需要根据服务的压力&#xff0c;采用水平&#xff08;横向&#xff09;扩容的…

分享给你这几款冷门好用的工具

分享一&#xff1a;Hi HiSlide Hi HiSlide是一个在线演示文稿制作工具&#xff0c;它可以帮助用户轻松地创建出色的演示文稿。以下是该网站的一些功能和特点&#xff1a; 多种模板选择**&#xff1a;Hi HiSlide提供了多种演示文稿模板&#xff0c;适合不同行业和场合的演示需…