【数据结构】二叉树(2)

news2024/12/26 23:49:01

目录

1. 二叉树的遍历

前序遍历

中序遍历

后序遍历

2. 计算二叉树中的节点个数

3. 计算二叉树中叶子节点个数

4. 计算二叉树的深度

5. 计算二叉树第k层节点个数

6. 二叉树基础练习

7. 二叉树的创建

8. 二叉树的销毁

9. 层序遍历

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


1. 二叉树的遍历

二叉树遍历(traversal)是按照一定的次序访问二叉树中的所有节点,并且每个节点仅被访问一次的过程。它是二叉树最基本的运算,是二叉树中所有其他运算实现的基础。

  1. 前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
  2. 中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。
  3. 后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。

由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为根、根的左子树和根的右子树。NLR、LNR和LRN分别又称为先根遍历、中根遍历和后根遍历。

前序遍历递归图解:

代码实现

前序遍历

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

中序遍历

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

后序遍历

//后序遍历
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("空 ");
		return;
	}
	PostOrder(root->left);	
	PostOrder(root->right);
	printf("%d ", root->data);
}

以中序遍历为例,递归展开图: 

代码实现: 

#include<stdio.h>
#include<stdlib.h>
typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType data;//数据元素
	struct BinaryTreeNode* left;//指向左孩子
	struct BinaryTreeNode* right;//指向右孩子
}BTNode;

BTNode* BuyNodee(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* CreateBinaryTree()
{
	BTNode* node1 = BuyNodee(1);
	BTNode* node2 = BuyNodee(2);
	BTNode* node3 = BuyNodee(3);
	BTNode* node4 = BuyNodee(4);
	BTNode* node5 = BuyNodee(5);
	BTNode* node6 = BuyNodee(6);
	BTNode* node7 = BuyNodee(7);

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

	return node1;
}

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

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

//后序遍历
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("空 ");
		return;
	}
	PostOrder(root->left);	
	PostOrder(root->right);
	printf("%d ", root->data);
}

int main()
{
	BTNode* root = CreateBinaryTree();
	//前序遍历
	PrevOrder(root);
	printf("\n");
	//中序遍历
	InOrder(root);
	printf("\n");
	//后序遍历
	PostOrder(root);
	printf("\n");

	return 0;
}

运行结果:

2. 计算二叉树中的节点个数

递归思想:

如果二叉树为空,节点个数为0。

如果二叉树不为空,二叉树节点个数=左子树节点个数 + 右子树节点个数 +1

代码实现:

//节点个数
int TreeSize(BTNode* root)
{
	return root == NULL ? 0 :
		TreeSize(root->left) + TreeSize(root->right) + 1;
}

3. 计算二叉树中叶子节点个数

递归思想:

如果二叉树为空,返回0。

如果二叉树不为空,左右子树为空,返回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);
}

4. 计算二叉树的深度

递归思想:

如果二叉树为空,二叉树的深度为0。

如果二叉树不为空,二叉树的深度 = max(左子树深度,右子树深度)+1。 

代码实现: 

//二叉树的深度
int TreeHeight(BTNode* root)
{
	if (root == NULL)
		return 0;
	int height1 = TreeHeight(root->left);
	int height2 = TreeHeight(root->right);
	return height1 > height2 ? height1+1 : height2+1;
}

5. 计算二叉树第k层节点个数

递归思想:

如果二叉树为空,返回0。

如果二叉树不为空且k=1,返回1。

如果二叉树不为空且k>1,返回左子树中k-1层节点个数加右子树中k-1层节点个数。

代码实现:

//计算二叉树第k层节点个数
int TreeLevelKSize(BTNode* root,int k)
{
	if (root == NULL)
		return 0;
	if (k == 1)
		return 1;
	return TreeLevelKSize(root->left, k - 1)
	   + TreeLevelKSize(root->right, k - 1);
}

 在栈中大致过程

6. 二叉树基础练习

题目1 单植二叉树【链接】

题目2 相同的树【链接】

题目3 对称二叉树【链接】

题目4 二叉树的前序遍历【链接】

题目5 二叉树的中序遍历【链接】

题目6 二叉树的后序遍历【链接】

题目7 另一棵树的子树【链接】

7. 二叉树的创建

二叉树的构建及遍历【链接】

代码实现 :

#include <stdio.h>
typedef struct BinaryTreeNode
{
    struct BinaryTreeNode* left;
    struct BinaryTreeNode* right;
    char val;
}BTNode;

BTNode* CreateTree(char*a,char*pi)
{
    if(a[(*pi)]=='#')
    {
        (*pi)++;
        return NULL;
    }   

    BTNode* root=(BTNode*)malloc(sizeof(BTNode));
    root->val=a[(*pi)++];
    root->left=CreateTree(a,pi);
    root->right=CreateTree(a,pi);
        return root;
}

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

int main() 
{
   char a[100];
   scanf("%s",a);
   char i=0;
   BTNode* root=CreateTree(a,&i);
   InOrder(root);

    return 0;
}

8. 二叉树的销毁

代码实现:

//二叉树的销毁(后序遍历)
void TreeDestory(BTNode* root)
{
	if (root == NULL)
		return;
	TreeDestory(root->left);
	TreeDestory(root->right);
	free(root);
}

9. 层序遍历

从上到下,从左到右依次将每个数放入到队列中,然后按顺序依次打印就是想要的结果。
1、首先将二叉树的根节点push到队列中,判断队列不为NULL,就输出队头的元素。
2、判断节点是否有孩子,如果有就将孩子push到队列中。

代码实现:

由于要访问每个节点的左右孩子,所以队列的元素类型为节点的指针。Queue.h【链接】

#include"Queue.h"

//层序遍历
void TreeLevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	if (root)
		QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);

		printf("%d ", front->data);

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

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

基本思想:

按照层序遍历,遇到空也进队列,出队列出到空时,就开始判断,后面是全空就是完全二叉树,后面有非空就不是完全二叉树。例:

//判断二叉树是否是完全二叉树
bool TreeComplete(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	if (root)
		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))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front)//如果有非空,就不是完全二叉树
		{
			return false;
		}
	}

	QueueDesTroy(&q);
	return true;
}

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

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

相关文章

mysql | limit X, -1 早已不可使用,本身也是一个错误

一、背景 需求&#xff1a;使用 mysql 时&#xff0c;需要获取第 X 条数据之后的所有数据。 这时&#xff0c;首先想到的就是利用 limit 来实现。 早期的部分文章或者资料中&#xff0c;提到可以使用&#xff1a; limit X,-1 例如&#xff0c;获取第一条后的所有数据&…

C++:探索AVL树旋转的奥秘

文章目录 前言 AVL树为什么要旋转&#xff1f;一、插入一个值的大概过程1. 插入一个值的大致过程2. 平衡因子更新原则3. 旋转处理的目的 二、左单旋1. 左单旋旋转方式总处理图2. 左单旋具体会遇到的情况3. 左单旋代码总结 三、右单旋1. 右单旋旋转方式总处理图2. 右单旋具体会遇…

开发一套ERP 第二弹

前后端分离 一起做,发现会有点问题,有时候分不太清楚 可以使用 naive ui admin 作为前端 menu 的配置在mock 中,在mock 中修改为自己需要的选项即可,mock 中返回的是前端需要测试的数据接口 同理自己需要的API也可以定义到 api 中&#xff0c;然后在mock 中配置返回的结果;然后…

cangjie (仓颉) vscode环境搭建

sdk下载 下载中心-仓颉编程语言官网 可选择半年更新版&#xff0c;不用申请。目前版本&#xff1a;0.53.13 &#xff0c;选择不同平台压缩包下载解压到任意位置即可 补充下载&#xff0c;vscode插件解压后&#xff0c;在vscode扩展中选择从vsix安装&#xff0c;安装后新增名为…

ES6 、ESNext 规范、编译工具babel

ES6 、ESNext 规范、编译工具简介 ES6ES&#xff08;ECMAScript&#xff09; vs JS常量进一步探讨 obj对象的扩展面试&#xff1a;使对象属性也不能更改——Object.freeze(obj) 解构deconstruction变量的解构赋值&#xff1a;数组解构赋值&#xff1a;对象解构赋值&#xff1a;…

SQL 语句执行计划中的连接方式

SQL 语句执行计划中的连接方式 join操作 join操作基本分为3大类&#xff1a;外连接&#xff08;细分为&#xff1a;左连接&#xff08;Left outer join/ left join&#xff09;、右连接&#xff08;right outer join/ right join&#xff09;、全连接&#xff08;full outer …

数据结构第一讲

数据结构定义 算法的定义 什么是好算法&#xff1f; 空间复杂度 时间复杂度 例子1 打印1到N之间的正整数 有递归和循环两种方法实现。 但是在数字变大后&#xff0c;递归的方法会导致内存占用过多而崩溃。 而循环则不会 例子2 写程序给定多项式在X处的值 从里往外算的算…

--- 文件IO java ---

文本文件和二进制文件 文件再底层其实就是以一段二进制数据的形式储存的&#xff0c;当我用记事本打开文件时&#xff0c;有些文件会出现乱码&#xff0c;这就是二进制文件&#xff0c;而有一些文件是特殊的&#xff0c;他以特定的编码方式&#xff08;比如ascll&#xff09;可…

洛谷 P1616 疯狂的采药 C语言 记忆化搜索

题目&#xff1a; https://www.luogu.com.cn/problem/P1616?contestId215526 完全背包问题&#xff0c;最后一个超出空间了。完全背包和就是无限次的拿&#xff0c;公式跟01背包差不多。 但是&#xff0c;只有当前能拿和拿不下&#xff0c;换下一个。注意要处理好边界条件。…

java基础概念37:正则表达式2-爬虫

一、定义 【回顾】正则表达式的作用 作用一&#xff1a;校验字符串是否满足规则作用二&#xff1a;在一段文本中查找满足要求的内容——爬虫 二、本地爬虫VS网络爬虫 2-1、本地爬虫 示例&#xff1a; 代码优化&#xff1a; public static void main(String[] args) {// 大…

多目标跟踪算法

文章目录 一、传统方法1. 基于卡尔曼滤波器的方法1.1 Kalman Filter(卡尔曼滤波器) 2. 基于数据关联的方法2.1 匈牙利算法 二、深度学习方法1. 基于检测的多目标跟踪1.1 SORT算法1.2 DeepSort1.3 BoT-SORT 2. 基于特征关联和增强的方法2.1 ByteTrack 3. 基于Transformer的方法3…

网络(TCP)

目录 TCP socket API 详解 bind(): 我们的程序中对myaddr参数是这样初始化的: listen(): accept(): 理解accecpt的返回值: 饭店拉客例子 connect tcp服务器和udp类似的部分代码 把套接字设置为监听状态&#xff08;listen&#xff09; 测试 查看端口号和IP地址&…

阿里云 DevOps 资源安全扫描实践

随着企业上云进程的加速&#xff0c;云资源的使用量日益增长&#xff0c;云环境中资源的安全性和稳定性成为了企业业务运营的关键要素 面对多样化的云资源和复杂的应用场景&#xff0c;传统的安全管理手段已无法完全满足企业日益严苛的安全需求。为了确保云上资源的安全性&…

WebGL进阶(十一)层次模型

理论基础&#xff1a; 效果&#xff1a; 源码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"vie…

vscode下面python调试报错ImportError: cannot import name ‘Literal‘ from ‘typing‘

1 问题描述 我在vscode下面编写python程序&#xff0c;这个程序是在一个英伟达anoconda环境下的项目。之前能运行能调试&#xff0c;最近发现只能运行ctlf5&#xff0c;但是使用f5进行调试时&#xff0c;报错“File “c:\Users\86137.vscode\extensions\ms-python.debugpy-202…

(免费送源码)计算机毕业设计原创定制:Java+JSP+HTML+JQUERY+AJAX+MySQL springboot计算机类专业考研学习网站管理系统

摘 要 大数据时代下&#xff0c;数据呈爆炸式地增长。为了迎合信息化时代的潮流和信息化安全的要求&#xff0c;利用互联网服务于其他行业&#xff0c;促进生产&#xff0c;已经是成为一种势不可挡的趋势。在大学生在线计算机类专业考研学习网站管理的要求下&#xff0c;开发一…

Android 常用命令和工具解析之GPU相关

目录 1、GPU基本信息 1.1 获取GPU基本信息 1.2 伪造GPU基本信息 2、GPU内存信息 3、经典案例 案例1&#xff1a;GPU伪造信息方案 案例2&#xff1a;GPU内存统计算法 GPU 指的是 Graphics Processing Unit&#xff0c;即图形处理单元。GPU 是一种专门用于处理图形和图像相…

day03(单片机高级)RTOS

目录 RTOS(实时操作系统) 裸机开发模式 轮询方式 前后台&#xff08;中断方式&#xff09; 改进&#xff08;前后台&#xff08;中断&#xff09;&#xff09;定时器 裸机进一步优化 裸机的其他问题 RTOS的概念 什么是RTOS 为什么要使用 RTOS RTOS的应用场景 RTOS的…

cookie反爬----普通服务器,阿里系

目录 一.常见COOKIE反爬 普通&#xff1a; 1. 简介 2. 加密原理 二.实战案例 1. 服务器响应cookie信息 1. 逆向目标 2. 逆向分析 2. 阿里系cookie逆向 1. 逆向目标 2. 逆向分析 实战&#xff1a; 无限debugger原理 1. Function("debugger").call() 2. …

C++中的erase()函数用法总结

在 C 中&#xff0c;erase() 是 std::string 和 std::vector 等容器中的成员函数&#xff0c;用于删除容器中的元素。erase可以删去容器中指定位置的元素&#xff0c;容器的size&#xff08;大小&#xff09;会改变&#xff0c;但是容器的容量不变。 常用用法&#xff1a; 1.…