【数据结构】遍历二叉树(递归思想)-->赋源码

news2024/11/28 7:40:50

欢迎来到我的Blog,点击关注哦💕

前言

二叉树遍历是指按照一定的顺序访问二叉树中的每个节点,使得每个节点恰好被访问一次。遍历是二叉树上最重要的运算之一,是二叉树上进行其他运算的基础。

一、二叉树遍历概念

在这里插入图片描述

二叉树遍历分类

  • 前序遍历 :根节点–>左子树–>右子树。在前序遍历时,首先访问根节点,然后依次访问左子树和右子树。
  • 中序遍历 : 左子树–>根节点–>右子树。在中序遍历时,首先访问左子树,然后访问根节点,最后访问右子树。
  • 后序遍历:左子树–>右子树–>根节点。在后序遍历时,首先访问左子树和右子树,然后访问根节点。
  • 层序遍历: 由顶层到底层,一层一层遍历。

二叉树其他操作

树节点的个数树深度树 k 层的个数查找节点

二、二叉树遍历实现

我们以下面为例子:

1
2
3
4
5
6
7
8
9
2_right_NULL
3_left_NULL

2.1 二叉树建立

1.定义一个结构体,分别有左右两个指针。

2.为每一个节点创建孔家。

3.创建二叉树,并如上图连接。

//定义结构体

typedef int BTTypeData;

typedef struct BinaryTree
{
	BTTypeData data;

	struct BinaryTree* left;
	struct BinaryTree* right;
}BinaryTree;

//创建空间

BinaryTree* BuyBinaryTree(BTTypeData x)
{
	BinaryTree* node = (BinaryTree*)malloc(sizeof(BinaryTree));
	if (node == NULL)
	{
		perror("malloc fail");
		return NULL;
	}

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

	return node;
}

//建树

BinaryTree* CreateBinaryTree()
{

	BinaryTree* node1 = BuyBinaryTree(1);
	BinaryTree* node2 = BuyBinaryTree(2);
	BinaryTree* node3 = BuyBinaryTree(3);
	BinaryTree* node4 = BuyBinaryTree(4);
	BinaryTree* node5 = BuyBinaryTree(5);
	BinaryTree* node6 = BuyBinaryTree(6);
	BinaryTree* node7 = BuyBinaryTree(7);
	BinaryTree* node8 = BuyBinaryTree(8);
	BinaryTree* node9 = BuyBinaryTree(9);

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


	return node1;
}

2.2 前序遍历

在递归实现中,前序遍历的基本思想是对于每一个节点,先访问该节点,然后对其左子树进行前序遍历,最后对其右子树进行前序遍历。如果当前节点为空,则直接返回。这种方法的优点是代码简洁明了,易于理解,但缺点是可能导致栈溢出,特别是在处理深度较大的二叉树时。

遍历结果:1–> 2–> 3 –>7 –>4 –>5 –>6–> 8 –>9

//前序遍历
void PreOrder(BinaryTree* root)
{
	
	
	if (root == NULL)
	{
		//printf("NULL ");
		return;
	}

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

2.2 中序遍历

首先对左子树进行中序遍历,然后访问根节点,最后对右子树进行中序遍历。

遍历结果:3 –>7–>2–> 1–> 5–> 4–>8–> 6–> 9

void InOrder(BinaryTree* root)
{


	if (root == NULL)
	{
		//printf("NULL ");
		return;
	}

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

}

2.3 后序遍历

递归函数首先访问左子树,然后访问右子树,最后访问根节点。如果当前节点为空,则直接返回。

遍历结果:7–> 3–> 2–> 5–> 8 –>9 –>6 –>4 –>1

//后序遍历
void PostOrder(BinaryTree* root)
{


	if (root == NULL)
	{
		//printf("NULL ");
		return;
	}

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

}

2.4 层序遍历

在二叉树的层序遍历是指按照树的层次顺序,从上到下、从左到右逐层访问二叉树的节点。这种遍历方式可以帮助我们了解二叉树的结构布局,特别是在处理树状数据结构时非常有用。

利用队列的特点,有关队列可参考 栈和队列

  • 将根节点入队。

  • 当队列不为空时,从队列中取出一个节点,访问该节点。

  • 将该节点的左右子节点(如果存在)入队。

  • 重复步骤2和3,直到队列为空。

遍历结果:1–> 2 –>4 –>3 –>5 –>6 –>7 –>8 –>9

//层序遍历

void LevelOrder(BinaryTree* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	Queue TBT;
	QueueInit(&TBT);

	if (root)
		QueuePush(&TBT, root);
	
	while (!QueueEmpty(&TBT))
	{
		BinaryTree* front = QueueTop(&TBT);
		QueuePop(&TBT);
		printf("%d ", front->data);

		if (front->left)
			QueuePush(&TBT, front->left);
		if (front->right)
			QueuePush(&TBT, front->right);

	}

	QueueDestroy(&TBT);

}

2.5 二叉树的节点个数

利用递归的方法,左右子树调用,如果该节点为NULL 便会返回0,否则返回1。

//树的结点个数

int TreeSize(BinaryTree* root)
{

	return root == 0 ? 0:TreeSize(root->left) + TreeSize(root->right) + 1;

}

2.6 二叉树的深度

利用 leftright记录左右子树的个数,然后比较 选择较大的一个。

如图:在这里插入图片描述

//树的高度

int TreeHeight(BinaryTree* root)
{
	if (root == NULL)
	{
		return 0;
	}

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

	return left > right ? left + 1 : right + 1;

}

2.7 二叉树第K层的个数

假设查找第三层,K为3 ,每次递归K–,知道K== 1 的时候 返回1。

//层的个数

int TreeKLevel(BinaryTree* root, int k)
{
	if (root == NULL)
	{
		return 0;
	}

	if (k == 1)
	{
		return 1;
	}


	return TreeKLevel(root->left, k - 1) + TreeKLevel(root->right, k - 1);


}

2.8 二叉树查找结点

节点的查找,如果节点为NULL饭后NULL,如果此节点的data等于x,返回节点的地址。

//查找节点

BinaryTree* TreeFind(BinaryTree* root, BTTypeData x)
{

	if (root == NULL)
	{
		return NULL;
	}

	if (root->data == x)
	{
		return root;
	}

	BinaryTree* lret = TreeFind(root->left, 7);
	if (lret)
		return lret;
	BinaryTree* rret = TreeFind(root->right, 7);
	if (rret)
		return rret;
	return NULL;
}

源码

queue.c

#define _CRT_SECURE_NO_WARNINGS

#include "queue.h"



//初始化
void QueueInit(Queue* ps)
{
	assert(ps);

	ps->head = ps->tail = NULL;

	ps->szie = 0;

}

//销毁
void QueueDestroy(Queue* ps)
{
	assert(ps);
	QNode* cur = ps->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}

	ps->head = ps->tail = NULL;
	ps->szie = 0;
}

//入队
void QueuePush(Queue* ps,QDataType x)
{
	assert(ps);

	QNode* newcode = (QNode*)malloc(sizeof(QNode));
	if (newcode == NULL)
	{
		perror("malloc fail");
		return ;
	}
	newcode->next = NULL;
	newcode->data = x;

	if (ps->head == NULL)
	{
		ps->head = ps->tail = newcode;
		
	}
	else

	{
		
		ps->tail->next = newcode;
		ps->tail = newcode;
	}

	ps->szie++;

}

//删除
void QueuePop(Queue* ps)
{
	assert(ps);
	assert(ps->head != NULL);
	assert(!QueueEmpty(ps));

	if (ps->head->next == NULL)
	{
		free(ps->head);
		ps->head = ps->tail = NULL;
	}
	else
	{
		QNode* next = ps->head->next;
		free(ps->head);
		ps->head = next;

	}
	ps->szie--;
}

//大小
int QueueSize(Queue* ps)
{
	assert(ps);

	return ps->szie;
}

//判空队
bool QueueEmpty(Queue* ps)
{
	assert(ps);

	return ps->szie == 0;
}

//出队头
QDataType QueueTop(Queue* ps)
{
	assert(ps);
	assert(!QueueEmpty(ps));

	return ps->head->data;
}

//出队尾
QDataType QueueBack(Queue* ps)
{
	assert(ps);

	return ps->tail->data;
}



queue.h

#pragma once

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>

typedef struct BinaryTree* QDataType;

typedef struct QNode
{
	struct QNode* next;
	QDataType data;

}QNode;

typedef struct Queue
{
	QNode*head;
	QNode*tail;
	 
	int szie;
}Queue;


//单链表的实现,FIFO

//初始化
void QueueInit(Queue* ps);
//销毁
void QueueDestroy(Queue* ps);
//入队
void QueuePush(Queue* ps, QDataType x);
//删除
void QueuePop(Queue* ps);
//大小
int QueueSize(Queue* ps);
//判空队
bool QueueEmpty(Queue* ps);
//出队头
QDataType QueueTop(Queue* ps);
//出队尾
QDataType QueueBack(Queue* ps);

travelling_binary_tree

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include "queue.h"

//定义结构体

typedef int BTTypeData;

typedef struct BinaryTree
{
	BTTypeData data;

	struct BinaryTree* left;
	struct BinaryTree* right;
}BinaryTree;

//创建空间

BinaryTree* BuyBinaryTree(BTTypeData x)
{
	BinaryTree* node = (BinaryTree*)malloc(sizeof(BinaryTree));
	if (node == NULL)
	{
		perror("malloc fail");
		return NULL;
	}

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

	return node;
}

//建树

BinaryTree* CreateBinaryTree()
{

	BinaryTree* node1 = BuyBinaryTree(1);
	BinaryTree* node2 = BuyBinaryTree(2);
	BinaryTree* node3 = BuyBinaryTree(3);
	BinaryTree* node4 = BuyBinaryTree(4);
	BinaryTree* node5 = BuyBinaryTree(5);
	BinaryTree* node6 = BuyBinaryTree(6);
	BinaryTree* node7 = BuyBinaryTree(7);
	BinaryTree* node8 = BuyBinaryTree(8);
	BinaryTree* node9 = BuyBinaryTree(9);

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


	return node1;
}

//前序遍历
void PreOrder(BinaryTree* root)
{
	
	
	if (root == NULL)
	{
		//printf("NULL ");
		return;
	}

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

//中序遍历

void InOrder(BinaryTree* root)
{


	if (root == NULL)
	{
		//printf("NULL ");
		return;
	}

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

}

//后序遍历
void PostOrder(BinaryTree* root)
{


	if (root == NULL)
	{
		//printf("NULL ");
		return;
	}

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

}

//层序遍历

void LevelOrder(BinaryTree* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	Queue TBT;
	QueueInit(&TBT);

	if (root)
		QueuePush(&TBT, root);
	
	while (!QueueEmpty(&TBT))
	{
		BinaryTree* front = QueueTop(&TBT);
		QueuePop(&TBT);
		printf("%d ", front->data);

		if (front->left)
			QueuePush(&TBT, front->left);
		if (front->right)
			QueuePush(&TBT, front->right);

	}

	QueueDestroy(&TBT);

}

//树的结点个数

int TreeSize(BinaryTree* root)
{

	return root == 0 ? 0:TreeSize(root->left) + TreeSize(root->right) + 1;

}

//树的高度

int TreeHeight(BinaryTree* root)
{
	if (root == NULL)
	{
		return 0;
	}

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

	return left > right ? left + 1 : right + 1;

}

//层的个数

int TreeKLevel(BinaryTree* root, int k)
{
	if (root == NULL)
	{
		return 0;
	}

	if (k == 1)
	{
		return 1;
	}


	return TreeKLevel(root->left, k - 1) + TreeKLevel(root->right, k - 1);


}

//查找节点

BinaryTree* TreeFind(BinaryTree* root, BTTypeData x)
{

	if (root == NULL)
	{
		return NULL;
	}

	if (root->data == x)
	{
		return root;
	}

	BinaryTree* lret = TreeFind(root->left, 7);
	if (lret)
		return lret;
	BinaryTree* rret = TreeFind(root->right, 7);
	if (rret)
		return rret;
	return NULL;
}

int main()
{
	BinaryTree* root = CreateBinaryTree();


	PreOrder(root);
	printf("\n");
	InOrder(root);
	printf("\n");
	PostOrder(root);
	printf("\n");
	LevelOrder(root);
	printf("\n");


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

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

	printf("TreeKLevel : %d\n", TreeKLevel(root, 3));

	printf("TreeFind : %p\n", TreeFind(root, 1));




	return 0; 
}

}

//查找节点

BinaryTree* TreeFind(BinaryTree* root, BTTypeData x)
{

if (root == NULL)
{
	return NULL;
}

if (root->data == x)
{
	return root;
}

BinaryTree* lret = TreeFind(root->left, 7);
if (lret)
	return lret;
BinaryTree* rret = TreeFind(root->right, 7);
if (rret)
	return rret;
return NULL;

}

int main()
{
BinaryTree* root = CreateBinaryTree();

PreOrder(root);
printf("\n");
InOrder(root);
printf("\n");
PostOrder(root);
printf("\n");
LevelOrder(root);
printf("\n");


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

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

printf("TreeKLevel : %d\n", TreeKLevel(root, 3));

printf("TreeFind : %p\n", TreeFind(root, 1));




return 0; 

}


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

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

相关文章

【机器学习】LightGBM: 优化机器学习的高效梯度提升决策树

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 LightGBM: 优化机器学习的高效梯度提升决策树引言一、LightGBM概览二、核心技术…

微服务开发与实战Day08 - Elasticsearch

一、初始Elasticsearch 高性能分布式搜索引擎 1. 认识和安装 1.1 认识 Lucene是一个Java语言的搜索引擎类库&#xff0c;是Apache公司的顶级项目&#xff0c;由DougCutting于1999年研发。官网地址&#xff1a;Apache Lucene - Welcome to Apache Lucene Lucene的优势&…

誉天教育近期开班计划(6月15日更新)

云计算HCIP 周末班 2024/6/15 田老师 售前IP-L3 周末班 2024/6/15 陈老师 RHCA442 晚班 2024/6/17邹老师 数通HCIE 晚班 2024/6/24阮老师 云计算HCIE直通车晚班 2024/6/25 曾老师 售前IT-L3 周末班 2024/6/29 伍老师 数通HCIP 晚班 2024/7/1杨老师 存储直通车 晚班 2024/7/1 高…

【ARMv8/ARMv9 硬件加速系列 3 -- SVE 指令语法及编译参数详细介绍】

文章目录 SVE 汇编语法SVE 单通道谓词SVE 测试代码 SVE 软件和库支持SVE 编译参数配置-marcharmv8-alseprofilememtagsve2-aessve2-bitpermcryptosve2sve2-sha3sve2-sm4 SVE 汇编语法 在介绍 SVE 汇编指令语法之前&#xff0c;先介绍下如何判断自己所使用的芯片是否实现了SVE功…

算法01 递推算法及相关问题详解【C++实现】

目录 递推的概念 训练&#xff1a;斐波那契数列 解析 参考代码 训练&#xff1a;上台阶 参考代码 训练&#xff1a;信封 解析 参考代码 递推的概念 递推是一种处理问题的重要方法。 递推通过对问题的分析&#xff0c;找到问题相邻项之间的关系&#xff08;递推式&a…

践行国产化替代,优刻得私有云勇当先锋

编辑&#xff1a;阿冒 设计&#xff1a;沐由 阳泉&#xff0c;十万火急&#xff01; 位于太行山西麓的山西省阳泉市&#xff0c;是一座历史悠久、底蕴深厚、资源丰富的名城&#xff0c;拥有超百万常住人口&#xff0c;国内生产总值在2022年成功跨越千亿元大关。然而&#xff0c…

leetcode 56合并区间

思路 合并就是首先应该按照left左边界排序&#xff0c;排完序以后&#xff0c;如果i的左边界小于等于i-1的右边界&#xff0c;说明有重合&#xff0c;此时这两个可以合并&#xff0c;右边界应该取最大值。 代码 排序 我是定义了一个类,存储左右边界&#xff0c;先将数组转化…

传输层udp和tcp协议格式

UDP协议 UDP协议端格式 udp的前八个字节是报头&#xff0c;后面部分就是有效载荷。而目的端口号就保证了udp向应用层交付的问题。 而针对于报头和有效载荷分离是根据固定八字结的报头长度。数据的长度就是取决于报头中udp长度字段的大小来确定udp报文长度&#xff0c;因此也可…

【Matlab编程学习】 | matlab语言编程基础:常用图形绘制基础学习

&#x1f3a9; 欢迎来到技术探索的奇幻世界&#x1f468;‍&#x1f4bb; &#x1f4dc; 个人主页&#xff1a;一伦明悦-CSDN博客 ✍&#x1f3fb; 作者简介&#xff1a; C软件开发、Python机器学习爱好者 &#x1f5e3;️ 互动与支持&#xff1a;&#x1f4ac;评论 &…

C++面向对象程序设计 - 函数库

C语言程序中各种功能基本上都是由函数来实现的&#xff0c;在C语言的发展过程中建立了功能丰富的函数库&#xff0c;C从C语言继承了些函数功能。如果要用函数库中的函数&#xff0c;就必须在程序文件中包含文件中有关的头文件&#xff0c;在不同的头文件中&#xff0c;包含了不…

解决Unity-2020 安卓异形屏黑边

背景 Unity 2020.3.17 版本开发的游戏&#xff0c;打apk包&#xff0c;发现两个问题 如图下午所示&#xff0c;实体白色导航栏&#xff0c;阻挡了整个安卓UI界面&#xff0c;难看还影响美观。 安卓系统 12-13 版本手机&#xff0c;异形屏。一侧安全区黑边遮挡&#xff0c;占空间…

pyinstall打包exe报错

1- 报错 Please install pywin32-ctypes. 前提&#xff1a;python安装路径中已经安装了pywin32-ctypes。 运行pyinstaller报错 PyInstaller cannot check for assembly dependencies. Please install pywin32-ctypes. 解决思路&#xff1a; python安装路径下Lib\site-packa…

远程连接路由器:方法大全与优缺点解析

远程连接路由器的方式主要有以下几种&#xff0c;以下是每种方式的详细说明及其优缺点&#xff1a; 使用Web浏览器登录 方法&#xff1a;通过配置路由器的远程管理功能&#xff0c;允许用户通过互联网浏览器访问路由器的管理界面。用户只需输入路由器的公网IP地址或域名&#…

JavaSE 面向对象程序设计 包装类 纯理论详解以及相关综合练习

包装类 实质 基本数据类型对应的引用数据类型 把基本数据类型变成对象 创建对象后 在栈内存里开辟空间 在堆内存里开辟空间 成员变量记录数值 栈内存记录对象的地址 包装类就是创建一个对象&#xff0c;对象记录相应的数据值 用一个对象把数据包装起来 作用 Java中万…

[leetcode]将二叉搜索树转化为排序的双向链表

. - 力扣&#xff08;LeetCode&#xff09; /* // Definition for a Node. class Node { public:int val;Node* left;Node* right;Node() {}Node(int _val) {val _val;left NULL;right NULL;}Node(int _val, Node* _left, Node* _right) {val _val;left _left;right _rig…

新火种AI|苹果终于迈进了AI时代,是创新还是救赎?

作者&#xff1a;一号 编辑&#xff1a;美美 苹果的AI战略&#xff0c;能够成为它的救命稻草吗&#xff1f; 苹果&#xff0c;始终以其独特的创新能力引领着行业的发展方向。在刚结束不久的2024年的全球开发者大会&#xff08;WWDC&#xff09;上&#xff0c;苹果再次证明了…

iSlide软件下载附加详细安装教程

​iSlide 是一款基于 PPT 的插件工具&#xff0c;包含 52 个设计辅助功能&#xff0c;9 大在线资源库&#xff0c;超 50 万专业 PPT 模板/素材 支持 macOS 和 Windows 系统&#xff08;兼容 Office 和 WPS&#xff09;。 可以对一组元素&#xff08;文本框&#xff0c;图形&…

制作自己的 @OnClick、@OnLongClick(告别 setOnClickListener,使用注解、反射和动态代理)

前言 前面我们说过 ButterKnife 这个库&#xff0c;这个库实现不仅实现了 View 的绑定&#xff0c;而且还提供了大量的注解如 BindView、OnClick、OnLongClick 等来简化开发过程中事件绑定。而这些功能的实现是通过 APT 也就是注解处理器&#xff0c;在编译期间生成 Java 代码…

GStreamer——教程——基础教程2:GStreamer concepts

基本教程2&#xff1a;GStreamer概念 1&#xff0c;目标 之前的教程展示了如何自动构建管道。现在我们将手动构建一条pipeline&#xff1a;初始化每一个element并将它们连接起来。在此过程中&#xff0c;我们将学习&#xff1a; 什么是GStreamer元素以及如何创建一个。 如何…

redis设计与实现(五)RDB与AOF持久化

RDB持久化 因为Redis是内存数据库&#xff0c;它将自己的数据库状态储存在内存里面&#xff0c;所以如果不想办法将储存在内存中的数据库状态保存到磁盘里面&#xff0c;那么一旦服务器进程退出&#xff0c;服务器中的数据库状态也会消失不见。 为了解决这个问题&#xff0c;…