数据结构:树(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;
}

逻辑结构就是这样的: 

 这里链式结构比较简单,就不过多的介绍了。主要是后面的遍历,那些题目需要用到递归思想,有些难。

二.二叉树的遍历

1.前序遍历

开始前序遍历之前,我们需要先认识一下什么是前序遍历。前序又叫前根,意思就是在我们遍历二叉树的时候按照  根->左子树->右子树的顺序进行遍历。

依旧是这个图我先来解释一下,如果按照前序遍历的话我们的顺序是怎么样的(这里的N代表的是空树)。我们首先从1开始,这里的1就是根,所以它就是第一个被遍历的,然后到左子树,左子树又可以拆分成根和子树,所以它也是根,算是第二个被遍历的。然后又到左子树,这里是3,它同时被分成根和子树,他自己算是第三个被遍历的,然后再到左子树,这里就是已经是空树了,所以第四个被遍历的是N。到这里就没有左子树了,所以我们要到3的右子树开始遍历,这里也是N,所以这里右子树的N就是第五个被遍历的。

文字太多,换图再看一下:

按照这种遍历的方式,完全遍历完的过程其实就是1,2,3,N,N,N,4,5,N,6,N,N,6,N,N.

当然肯定要用代码来实现一下:

void PreOrder(BTNode* root)
{if (root == NULL){printf("N ");//如果树为NULL,就打印Nreturn;}printf("%d ", root->data);//先把N打印出来PreOrder(root->left);//运用递归实现,再次调用一下这个函数PreOrder(root->right);
}

再加上主函数,我们可以打印到屏幕上:

int main()
{BTNode* root = CreatBinaryTree();PreOrder(root);printf("\n");return 0;
}

这也跟上面我们手动遍历的一样。

2.中序遍历

中序遍历的遍历顺序是左子树->根->右子树。还是上面的二叉树,如果用中序遍历的话会是什么结果呢?

 

 遍历的过程也就是:N,3,N,2,N,1,N,5,N,6,N,4,N,6,N.

当然也要用代码实现一下:

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

加上主函数后我们可以打印出来我们预测的结果:

int main()
{BTNode* root = CreatBinaryTree();InOrder(root);printf("\n");return 0;
}

3.后序遍历 

知道了前面的两种遍历规律,那么这一种当然就是左子树->右子树->根。它的遍历我们也可以很轻松的推测出来:

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

代码也很简单:

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

打印出来也就是

这些遍历只是一些简单的递归。 

三.求二叉树全部结点个数

这个题目一看可能就会有思路,比如我在遍历的时候添加一个计数器count。但是要注意一下,我们在遍历的时候用的是递归,不是循环。我们的count如果是局部变量那么这个值不能存储。如果用静态或者全局变量了话也是可以的,我们可以先看一下用静态变量或者全局变量写的样子:

全局:

int size = 0;
int BinaryTreeSize(BTNode* root)
{if (root == NULL)return 0;else++size;BinaryTreeSize(root->left);BinaryTreeSize(root->right);return size;
}

静态:

int BinaryTreeSize(BTNode* root)
{static int size = 0;if (root == NULL)return 0;else++size;BinaryTreeSize(root->left);BinaryTreeSize(root->right);return size;
}

当然指针也可以。 

这样写当然可以,但是有一个问题,如果我多调用这个函数,那么size的值就会递增,不会自己清零,我们就需要自己手动置为0。如果是这样的话,是不是有点麻烦了。

那么我们可以想一想其他的方式来写。既然我们要求全部结点个数,那么递归肯定是离不开的。如果是空树,我们就返回0,如果不是空树,我们就把左子树的结点个数加上右子树的节点个数再加上1(这个1就是根).也就是说,我们就只求左右子树的结点个数,根就是我们加的那个1.注意:根都可以分为左子树和右子树,左子树和右子树同时也是根。

我们就可以写代码了:

int BinaryTreeSize(BTNode* root)
{return root == NULL ? 0 : BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}

虽然只是一行,但是它的递归的运用的十分巧妙,它会沿着左子树的方向一直到空树,然后再去右子树,如果右子树也是空树,那么它返回的结果就是1.也就代表这是1个结点。

加上主函数就可以很轻易的求出结点个数:

int main()
{BTNode* root = CreatBinaryTree();printf("TreeSize:%d\n", BinaryTreeSize(root));printf("TreeSize:%d\n", BinaryTreeSize(root));printf("TreeSize:%d\n", BinaryTreeSize(root));return 0;
}

具体左子树的遍历规则就在这里: 

 

四.求二叉树叶子结点个数 

叶子结点其实就是没有子树的节点。就是求二叉树最后一层的结点个数,这个就比较简单了,直接看代码:

int BinaryTreeLeafSize(BTNode* root)
{if (root == NULL)return 0;if (root->left == NULL && root->right == NULL)//左右子树都是空树,就说明这是个叶子结点return 1;return BinaryTreeLeafSize(root->left)+BinaryTreeLeafSize(root->right);
}

 加上主函数把结果打印在屏幕上:

int main()
{BTNode* root = CreatBinaryTree();printf("TreeLeafSize:%d\n", BinaryTreeLeafSize(root));return 0;
}

根据上图我们也可以看出,这个二叉树的叶子结点的个数就是3.

 五.求二叉树的高度

既然我们要找二叉树的高度,我们就应该知道我们找的是二叉树的最大高度,我们只需要找到左右子树的的最大高度就行。

int TreeHeight(BTNode* root)
{if (root == NULL)return 0;int TreeLeft = TreeHeight(root->left);int TreeRight = TreeHeight(root->right);return TreeLeft > TreeRight ? TreeLeft + 1 : TreeRight + 1;
}

有一点需要注意的是,我们需要提前把每个树的高度给存起来。如果不存的话,后面用三目表达式求值的时候就会重复的调用这个函数,代码的效率会大大降低。

六.单值二叉树

这是一道OJ题,链接为单值二叉树

其实就是判断一个二叉树里面的值是不是都是一样的,如果一样返回true,不一样返回false.

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     struct TreeNode *left;*     struct TreeNode *right;* };*/
bool isUnivalTree(struct TreeNode* root) {if(root==NULL)return true;if(root->left && root->left->val!=root->val)return false;if(root->right && root->right->val!=root->val)return false;return isUnivalTree(root->left)&&isUnivalTree(root->right);
}

到这里我介绍了二叉树的遍历,还有二叉树的一些简单题。感谢大家的观看,如有错误还请多多指出。

这篇关于数据结构:树(3)【二叉树链式结构实现】【二叉树的前序,中序,后序遍历】【求二叉树全部结点个数】【求二叉树叶子结点个数】【求二叉树的深度】【单值二叉树】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/997704

相关文章

使用Python和OpenCV库实现实时颜色识别系统

《使用Python和OpenCV库实现实时颜色识别系统》:本文主要介绍使用Python和OpenCV库实现的实时颜色识别系统,这个系统能够通过摄像头捕捉视频流,并在视频中指定区域内识别主要颜色(红... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间详解

PostgreSQL中MVCC 机制的实现

《PostgreSQL中MVCC机制的实现》本文主要介绍了PostgreSQL中MVCC机制的实现,通过多版本数据存储、快照隔离和事务ID管理实现高并发读写,具有一定的参考价值,感兴趣的可以了解一下... 目录一 MVCC 基本原理python1.1 MVCC 核心概念1.2 与传统锁机制对比二 Postg

SpringBoot整合Flowable实现工作流的详细流程

《SpringBoot整合Flowable实现工作流的详细流程》Flowable是一个使用Java编写的轻量级业务流程引擎,Flowable流程引擎可用于部署BPMN2.0流程定义,创建这些流程定义的... 目录1、流程引擎介绍2、创建项目3、画流程图4、开发接口4.1 Java 类梳理4.2 查看流程图4

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

C++高效内存池实现减少动态分配开销的解决方案

《C++高效内存池实现减少动态分配开销的解决方案》C++动态内存分配存在系统调用开销、碎片化和锁竞争等性能问题,内存池通过预分配、分块管理和缓存复用解决这些问题,下面就来了解一下... 目录一、C++内存分配的性能挑战二、内存池技术的核心原理三、主流内存池实现:TCMalloc与Jemalloc1. TCM

OpenCV实现实时颜色检测的示例

《OpenCV实现实时颜色检测的示例》本文主要介绍了OpenCV实现实时颜色检测的示例,通过HSV色彩空间转换和色调范围判断实现红黄绿蓝颜色检测,包含视频捕捉、区域标记、颜色分析等功能,具有一定的参考... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间

Python实现精准提取 PDF中的文本,表格与图片

《Python实现精准提取PDF中的文本,表格与图片》在实际的系统开发中,处理PDF文件不仅限于读取整页文本,还有提取文档中的表格数据,图片或特定区域的内容,下面我们来看看如何使用Python实... 目录安装 python 库提取 PDF 文本内容:获取整页文本与指定区域内容获取页面上的所有文本内容获取

基于Python实现一个Windows Tree命令工具

《基于Python实现一个WindowsTree命令工具》今天想要在Windows平台的CMD命令终端窗口中使用像Linux下的tree命令,打印一下目录结构层级树,然而还真有tree命令,但是发现... 目录引言实现代码使用说明可用选项示例用法功能特点添加到环境变量方法一:创建批处理文件并添加到PATH1

Java使用HttpClient实现图片下载与本地保存功能

《Java使用HttpClient实现图片下载与本地保存功能》在当今数字化时代,网络资源的获取与处理已成为软件开发中的常见需求,其中,图片作为网络上最常见的资源之一,其下载与保存功能在许多应用场景中都... 目录引言一、Apache HttpClient简介二、技术栈与环境准备三、实现图片下载与保存功能1.

canal实现mysql数据同步的详细过程

《canal实现mysql数据同步的详细过程》:本文主要介绍canal实现mysql数据同步的详细过程,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的... 目录1、canal下载2、mysql同步用户创建和授权3、canal admin安装和启动4、canal