【数据结构】二叉树的链式结构,二叉树的遍历,求节点个数以及高度

news2024/11/15 18:54:26

目录

1. 二叉树链式结构的概念

2. 二叉树的遍历

2.1 前序遍历

2.2 中序遍历

2.3 后序遍历

2.4 层序遍历

3. 二叉树的节点个数以及高度

3.1 二叉树节点个数

3.2 二叉树叶子节点个数

3.3 二叉树的高度

3.4 二叉树第k层节点个数

3.5 二叉树查找值为x的节点

4.  二叉树的创建和销毁

4.1 二叉树的销毁

4.2 通过前序遍历的数组构建二叉树

4.3 判断是否是完全二叉树

5. 编程题

5.1 相同的树

5.2 单值二叉树

5.3 对称二叉树

5.4 二叉树的前序遍历

5.5 另一棵树的子树

6. 选择题


1. 二叉树链式结构的概念

由空树,根节点,根的左子树,根的右子树组成。


2. 二叉树的遍历

2.1 前序遍历

访问根结点的操作发生在遍历其左右子树之前(根左右)。当根节点为NULL时返回。

1 2 3 N N N 4 5 N N 6 N N(空可以省略)

1. 先访问根节点,然后访问根的左子树。

2. 如果根的左子树不为空就把左子树的第一个节点作为根继续往下。

3. 左子树访问完后就访问右子树。

void PreOrder(BTNode* root)
{
	if (root == NULL) return;

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

2.2 中序遍历

访问根结点的操作发生在遍历其左右子树之中(左根右)。当根节点为NULL时返回。

N 3 N 2 N 1 N 5 N 4 N 6 N(N可以省略) 

1. 先访问根节点的左子树。

2. 将左子树的第一个节点作为根节点继续访问根的左子树。

3. 当左子树为空就返回访问根,然后访问根的右子树。

void InOrder(BTNode* root)
{
	if (root == NULL) return;

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

2.3 后序遍历

访问根结点的操作发生在遍历其左右子树之后

N N 3 N 2 N N 5 N N 6 4 1

void PostOrder(BTNode* root)
{
	if (root == NULL) return;

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

2.4 层序遍历

1. 要借助队列。

2. 每个队列节点里面的数据是二叉树节点的指针。

3. 第一步,一开始,当二叉树根节点不为空就入队列。

4. 第二步,当队列不为空就不断出队列,并带入队头数据的左右节点,前提是他们不为空。

void LevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);

	//一开始,当二叉树根节点不为空就入队列。
	if (root != NULL) QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		printf("%d ", front->data);
		if(front->left != NULL) QueuePush(&q, front->left);
		if(front->right != NULL) QueuePush(&q, front->right);
	}
	printf("\n");

	QueueDestroy(&q);
}

3. 二叉树的节点个数以及高度

3.1 二叉树节点个数

1. 返回右子树的节点个数和左子树的节点个数并加上自己。

2. 遇到空节点返回0。

int BinaryTreeSize(BTNode* root)
{
	//遇到空节点返回0。
	if (root == NULL) return 0;

	//返回右子树的节点个数和左子树的节点个数并加上自己。
	return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;	 
}

3.2 二叉树叶子节点个数

1. 找自己的左子树和右子树。

2. 找到叶子就返回1。

int BinaryTreeLeafSize(BTNode* root)
{
	//空节点返回0
	if (root == NULL) return 0;

	//找到叶子就返回1。
	if (root->left == NULL && root->right == NULL) return 1;

	//找自己的左子树和右子树。
	return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}

3.3 二叉树的高度

1. 遇到空节点返回0。

2. 返回左右子树较大值,并加1也就是加上自己。

int BTHeight(BTNode* root)
{
	//遇到空节点返回0。
	if (root == NULL) return 0;

	//返回左右子树较大值,并加1也就是加上自己。
	int lefthigh = BTHeight(root->left);
	int righthigh = BTHeight(root->right);
	return max(lefthigh, righthigh) + 1;
}

3.4 二叉树第k层节点个数

思路:对于第一层是找第k层,对于第二层是找k-1层,对于第k层就是找当前层,不断让子树去找,每下去一层k就减一,当k==1时就是第k层。

1. k必须大于0。

2. 遇到空节点返回0。

3. 当k == 1返回1。

4. 继续找左右子树。

int BinaryTreeLevelKSize(BTNode* root, int k)
{
	//1. k必须大于0。
	assert(k > 0);

	//2. 遇到空节点返回0。
	if (root == NULL) return 0;

	//3. 当k == 1返回1。
	if (k == 1) return 1;

	//4. 继续找左右子树。
	return BinaryTreeLevelKSize(root->left, k-1) + BinaryTreeLevelKSize(root->right, k-1);
}

3.5 二叉树查找值为x的节点

1. 遇到值相等就返回该节点,遇到空节点就返回空。

2. 先判断根节点的值是否等于x,如果等于就返回根节点,不等于就找自己的左右子树。

3. 记录左右子树的结果,谁找到了就返回,都没找到就返回空。

BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL) return NULL;
	if (root->data == x) return root;

	BTNode* left = BinaryTreeFind(root->left, x); 
	if (left != NULL) return left;
	BTNode* right = BinaryTreeFind(root->right, x);
	if (right != NULL) return right;

	return NULL;
}

4.  二叉树的创建和销毁

4.1 二叉树的销毁

1. 利用后序的思想,先释放左子树再释放右子树最后释放自己。

2. 在函数外置空,调用的人自己置空。

void BinaryTreeDestory(BTNode* root)
{
	if (root == NULL) return;
	BinaryTreeDestory(root->left);
	BinaryTreeDestory(root->right);
	free(root);
}

4.2 通过前序遍历的数组构建二叉树

链接:二叉树遍历_牛客题霸_牛客网

1. 用%s接收字符串。

2. 利用前序思想构建二叉树,将当前数组下标对应的值作为根的值构建节点,然后数组下标加一,再然后就去构建他的左子树和右子树。

3. 遇到#代表是空,下标加一然后返回空。

#include <stdio.h>

typedef char BTDataType;
typedef struct BTNode
{
	BTDataType data;
	struct BTNode* left;
	struct BTNode* right;
}BTNode;

BTNode* BuyNode(BTDataType x)
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	if (node == NULL)
	{
		perror("malloc");
		return NULL;
	}
	node->data = x;
	node->left = node->right = NULL;

    return node;
}

BTNode* Insert(char* arr, int* pi)
{
    if(arr[*pi] == '#')
    {
        (*pi)++;
        return NULL;
    }
    BTNode* root = BuyNode(arr[*pi]);
    (*pi)++;
    root->left = Insert(arr, pi);
    root->right = Insert(arr, pi);
    return root;
}

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

int main() 
{
    char arr[100];
    scanf("%s", arr);

    int i = 0;
    BTNode* root = Insert(arr, &i);

    InOrder(root);

    return 0;
}

4.3 判断是否是完全二叉树

1. 完全二叉树每一层都是连续的

2. 利用层序遍历的思想,将二叉树节点作为数据插入队列,遇到数据为空就结束遍历。

3. 判断队列剩下的数据有无非空,全都是空证明是连续的,有非空证明不连续。

bool BinaryTreeComplete(BTNode* root)
{
	Queue q;
	QueueInit(&q);

	if(root != NULL) QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front == NULL) break;

		QueuePush(&q, front->left);
		QueuePush(&q, front->right);
	}

	while (!QueueEmpty(&q))
	{ 
		if (QueueFront(&q) != NULL)
		{
			QueueDestroy(&q);
			return false;
		}
		QueuePop(&q);
	}

	QueueDestroy(&q);
	return true;
}

5. 编程题

5.1 相同的树

链接:. - 力扣(LeetCode)

思路:分治子问题。

1. 根节点值相等就比较他们的左子树和右子树。

2. 根节点值不相等直接返回false。

3. 接下来比结构,同时走到空意味着前面的结构和值是相等的,一个为空一个不为空证明结构不相等。 

bool isSameTree(struct TreeNode* p, struct TreeNode* q) 
{
    if(p == NULL && q == NULL) return true;
    if(p == NULL || q == NULL) return false;
    if(p->val != q->val) return false;
    
    return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}

5.2 单值二叉树

链接:. - 力扣(LeetCode) 

思路:

1. 将根节点和自己的左右孩子比较,注意左右孩子可能为空。

2. 相等则往下交给自己的左右子树。

bool isUnivalTree(struct TreeNode* root) 
{
    if(root == NULL) return true;
    if(root->left != NULL && root->val != root->left->val) return false;
    if(root->right != NULL && root->val != root->right->val) return false;

    return isUnivalTree(root->left) && isUnivalTree(root->right);
}

5.3 对称二叉树

链接: . - 力扣(LeetCode)

思路:

1. 根节点的左右子树要形成镜像对称。

2. 需要写一个子函数去比较左右子树是否对称。

3. 左子树的左边和右子树的右边对应,左子树的右边和右子树的左边对应。

bool isSameTree(struct TreeNode* p, struct TreeNode* q) 
{
    if(p == NULL && q == NULL) return true;
    if(p == NULL || q == NULL) return false;
    if(p->val != q->val) return false;
    
    return isSameTree(p->left, q->right) && isSameTree(p->right, q->left);
}

bool isSymmetric(struct TreeNode* root) 
{
    return isSameTree(root->left, root->right);    
}

5.4 二叉树的前序遍历

链接: . - 力扣(LeetCode)

思路:

1. 题目给个returnSize代表节点的个数。需要自己求。

2. 利用求的节点个数开空间。

3. 再写一个子函数进行前序遍历,将根值放入数组中,下标要传址。

void _preorderTraversal(struct TreeNode* root, int* ret, int* i)
{
    if(root == NULL) return;

    ret[(*i)++] = root->val;
    _preorderTraversal(root->left, ret, i);
    _preorderTraversal(root->right, ret, i);
}

int Size(struct TreeNode* root)
{
    if(root == NULL) return 0;
    else return 1 + Size(root->left) + Size(root->right);
}

int* preorderTraversal(struct TreeNode* root, int* returnSize) 
{
    *returnSize = Size(root);
    int* tmp = (int*)malloc(sizeof(int)*(*returnSize));
     
    int i = 0; 
    _preorderTraversal(root, tmp, &i);
    
    return tmp;
}

5.5 另一棵树的子树

链接: . - 力扣(LeetCode)

思路:

1. 遍历root,将root每个节点和subroot比较。

2. 注意,遍历到空意味着前面的比较都不相等。subroot也不可能为空。

bool isSameTree(struct TreeNode* p, struct TreeNode* q) 
{
    if(p == NULL && q == NULL) return true;
    if(p == NULL || q == NULL) return false;
    if(p->val != q->val) return false;
    
    return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}

bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot)
{
    if(root == NULL) return false;
    
    if(isSameTree(root, subRoot) == true) return true;

    return isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot); 
}

6. 选择题

1.某完全二叉树按层次输出(同一层从左到右)的序列为 ABCDEFGH 。则该完全二叉树的前序序列为()

A. ABDHECFG

B. ABCDEFGH

C. HDBEAFCG

D. HDEBFGCA

答:A

2.二叉树的先序遍历和中序遍历如下:先序遍历:EFHIGJK; 中序遍历:HFIEJKG.则二叉树根结点为()

A. E

B. F

C. G

D. H

答:A

3.设一课二叉树的中序遍历序列:badce,后序遍历序列:bdeca,则二叉树前序遍历序列为____。

A. adbce

B. decab

C. debac

D. abcde

答:D

4.某二叉树的后序遍历序列与中序遍历序列相同,均为 ABCDEF ,则按层次输出(同一层从左到右)的序列为

A. FEDCBA

B. CBAFED

C. DEFCBA

D. ABCDEF 

答:A

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

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

相关文章

数造科技荣登“科创杯”领奖台,开启数据驱动新篇章!

8月27日&#xff0c;第十三届中国创新创业大赛(海南赛区)暨海南省第十届“科创杯”创新创业大赛决赛在海口圆满落幕。数造科技凭其在大数据管理领域的专业技术实力&#xff0c;荣获成长企业组三等奖。 突出重围&#xff0c;崭露头角 海南省“科创杯”创新创业大赛是在中国科技…

安科瑞ADL系列导轨式多功能电能表 带外置互感器 CE认证

产品概述&#xff1a; ‌安科瑞ADL系列导轨式多功能电能表‌是安科瑞企业微电网能效管理事业部推出的一款智能仪表&#xff0c;主要针对光伏并网系统、微逆系统、储能系统、交流耦合系统等新能源发电系统设计。这款电能表具有高精度、体积小、响应速度达100ms&#xff0c;以及…

噪音消除模块调研

一.原理 1.1降噪 noisereduce 库的 reduce_noise 函数使用的是一种基于频谱减法的噪声消除算法。它通过分析音频的频谱&#xff0c;识别出噪声成分&#xff0c;并尝试将这些噪声成分从音频信号中去除&#xff0c;从而提升信号的清晰度。 1.2 动态范围压缩&#xff08;预加重&am…

Ollama:本地大语言模型解决方案

在人工智能领域&#xff0c;大语言模型&#xff08;LLM&#xff09;因其在自然语言处理上的强大能力而备受瞩目。然而&#xff0c;这些模型往往需要大量的计算资源和网络连接&#xff0c;限制了它们在本地环境的应用。Ollama 的推出&#xff0c;为这一问题提供了解决方案。作为…

基于C语言实现文件压缩与解压缩算法

引言 随着互联网的发展&#xff0c;数据传输和存储的需求日益增长&#xff0c;文件压缩技术成为提高数据处理效率的关键技术之一。压缩技术不仅可以减少存储空间的需求&#xff0c;还能加快数据在网络中的传输速度。霍夫曼编码作为一种有效的无损数据压缩算法&#xff0c;广泛…

如何为你的 LLM 应用选择最合适的 Embedding 模型

如果你正在构建 2024 年的生成式人工智能&#xff08;GenAI&#xff09;应用&#xff0c;你现在可能已经听过几次 "嵌入&#xff08;embedding&#xff09; "这个词了&#xff0c;而且每周都能看到新的嵌入模型上架。 那么&#xff0c;为什么会有这么多人突然关心起嵌…

ElasticSearch 集群索引和分片的CURD

一、ES集群的索引 背景&#xff1a;Elasticsearch会对所有输入的文本进行处理&#xff0c;建立索引放入内存中&#xff0c;从而提高搜索效率。在这一点上ES优于MYSQL的B树的结构&#xff0c;MYSQL需要将索引放入磁盘&#xff0c;每次读取需要先从磁盘读取索引然后寻找对应的数据…

OpenAI Gym custom environment: Discrete observation space with real values

题意&#xff1a;OpenAI Gym 自定义环境&#xff1a;具有实数值的离散观测空间 问题背景&#xff1a; I would like to create custom openai gym environment that has discrete state space, but with float values. To be more precise, it should be a range of values wi…

翻译软件 Fastrans 开发日志 #2

就过了几天&#xff0c;我的 Fastrans 项目&#xff08; https://github.com/YaoqxCN/Fastrans &#xff09;又更新了两个版本&#xff0c;现在是 v1.1.1。&#xff08;求个 star 谢谢&#xff01;&#xff09; 上次我初步实现了 Fastrans 的翻译功能以及 UI&#xff0c;可以看…

【C++ Primer Plus习题】8.1

问题: 解答: #include <iostream> using namespace std;void print(const char* str) {cout << str << endl; }void print(const char* str,int size) {static int count 0;count;for (int i 0; i < count; i){cout << str << endl;} }int…

机器学习数学公式推导之线性回归

文章目录 线性回归一、最小二乘法1.1 范数的概念1.2 最小二乘法的推导1.3 几何意义 二、噪声为高斯分布的 MLE2.1 LSE&#xff08;最小二乘估计&#xff09;2.2 MLE&#xff08;极大似然估计&#xff09;2.3 LSE与MLE的联系与区别 三、权重先验也为高斯分布的 MAP四、正则化4.1…

APO的接口级拓扑 VS Dynatrace ServiceFlow

在可观测性系统中&#xff0c;几乎所有的产品都会提供拓扑功能。大部分用户在初看这个拓扑之时都会觉得非常有用&#xff0c;但是一旦真实落地使用&#xff0c;就感觉这个拓扑比较鸡肋。这篇文章重点探讨APO团队是如何考虑让用户能够更好的使用拓扑&#xff0c;真正发挥出拓扑的…

OpenCV绘图函数(14)图像上绘制文字的函数putText()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在图像上绘制指定的文本字符串。 cv::putText 函数在图像上绘制指定的文本字符串。无法使用指定字体渲染的符号会被问号&#xff08;?&#xff…

从理论层面设计简单的电池管理系统(BMS)

前言 最近阅读了《便携式设备的电池电源管理》和《大规模锂离子电池管理系统》这两本书&#xff0c;都是比较容易入门的BMS书籍&#xff0c;书中作者做了很多深层次的思考&#xff0c;所以我摘抄了一些部分&#xff1b;同时结合我个人的项目经验及一些理解&#xff0c;整理成这…

中核武汉首位“数字员工”报到,实在智能提供RPA技术解决方案

近期新员工入职季&#xff0c;中核武汉核电运行技术股份有限公司&#xff08;以下简称“中核武汉”&#xff09;迎来了一位“看不见的新同事”——公司首位数字员工“武小数”。“武小数”基于先进的机器人流程自动化技术&#xff08;RPA&#xff09;诞生&#xff0c;结合OCR图…

c++线程库操作

一、函数介绍 1、构造函数 无参构造函数&#xff1a; thread thd thread(); 有参构造函数&#xff1a; template<class Fn, class... Arg> Fn&#xff1a;可调用对象&#xff08;函数指针&#xff0c;仿函数&#xff0c;lambda表达式&#xff0c;包装器&#xff09…

掌握 ERP 进销存系统源码,实现企业精准管理 带源代码包以及搭建部署教程

系统概述 ERP 进销存系统源码是一套基于先进技术架构开发的企业管理解决方案。它涵盖了企业采购、销售、库存管理等核心业务领域&#xff0c;通过信息化手段实现了数据的实时共享、流程的优化整合以及决策的科学支持。 该系统源码采用了模块化设计理念&#xff0c;各个模块之…

传输层(多路复用与解复用)

目录 1.概述传输层服务 传输服务和协议 传输层 VS 网络层 类比&#xff1a;两个家庭的通信 Internet传输层提供的服务 2.多路复用与解复用 多路复用/解复用 多路复用的工作原理 无连接&#xff08;UDP&#xff09;多路复用 UDP多路复用例子 UDP多路解复用例子 面向连…

【Python报错已解决】ValueError: cannot reindex from a duplicate axis

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引言&#xff1a; 当处理Pandas数据框&#xff08;DataFrame&#xff09;时&#xff0c;你是否遇到过ValueError: cannot reind…

零知识证明-公钥分发方案DH((六)

前言 椭圆曲线配对&#xff0c;是各种加密构造方法(包括 确定性阀值签名、zk-SNARKs以及相似的零知识证明)的关键元素之一。椭圆曲线配对(也叫“双线性映射”)有了30年的应用历史&#xff0c;然而最近这些年才把它应用在密码学领域。配对带来了一种“加密乘法”的形式&#xff…