博主主页:LiUEEEEE
C语言专栏
数据结构专栏
力扣牛客经典题目专栏
1、前言
在探讨如何通过代码实现对二叉树节点个数和高度问题求解前,需提前告知准备工作内容以及二叉树组成。
以手搓二叉树为例,下方代码和图展示的是本文讨论问题的二叉树例子。
- 结点结构及相关定义展示:
typedef int TreeDataType;
typedef struct TreeNode
{
TreeDataType val;
struct TreeNode* left;
struct TreeNode* right;
}TNode;
TNode* BuyNode(TreeDataType x);创建二叉树结点
TNode* CreateTree();串连结点组成树
- BuyNode
TNode* BuyNode(TreeDataType x)
{
TNode* tmp = (TNode*)malloc(sizeof(TNode));
if (tmp == NULL)
{
perror("BuyNode: malloc fail");
return NULL;
}
tmp->val = x;
tmp->left = tmp->right = NULL;
return tmp;
}
- CreateTree
TNode* CreateTree()
{
TNode* node1 = BuyNode(1);
TNode* node2 = BuyNode(2);
TNode* node3 = BuyNode(3);
TNode* node4 = BuyNode(4);
TNode* node5 = BuyNode(5);
TNode* node6 = BuyNode(6);
node1->left = node2;
node1->right = node3;
node2->left = node4;
node2->right = node5;
node3->left = node6;
return node1;
}
再此基础上我们所构建的书逻辑图如下所示:
PS.图中子树未连接部分均为NULL。
2、本文讨论问题内容
本文所讨论问题为:
- 1.二叉树结点个数
- 2.二叉树叶子结点个数
- 3.二叉树第k层结点个数
- 4.二叉树的高度
相关定义如下:
二叉树结点个数
int BinaryTreeSize(TNode* root);
二叉树叶子结点个数
int BinaryTreeLeafSize(TNode* root);
二叉树第k层结点个数
int BinaryTreeLevelKSize(TNode* root, int k);
二叉树的高度
int BinaryTreeHigh(TNode* root);
二叉树查找值为x的结点
TNode* BinaryTreeFind(TNode* root, TDataType x);
3、二叉树结点个数
针对于求二叉树结点的问题,可以归结为求一棵树的根节点个数加左子树结点个数再加右子树结点个数,及我们把每一个结点和与之对应的子结点都当作一颗新树,使用递归的方法对其求解,示意图和过程如下所示。
欲求以1为根的树的结点个数,及求得以2为根的树结点个数 + 以3为根的树的结点个数 + 1(根节点)即可。
欲求以2为根的树的结点个数,及求得以4为根的树结点个数 + 以5为根的树的结点个数 + 1(根节点)即可。
欲求以3为根的树的结点个数,及求得以4为根的树结点个数 + 以3的右子树的结点个数 + 1(根节点)即可。
. . . . . . .
依此类推,当遇到空结点,直接返回0即可。
- 故通过递归的思想,我们所编写的代码如下所示:
int BinaryTreeSize(TNode* root)
{
return root == 0 ? 0 : BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}
4、二叉树叶子节点个数
针对于求叶子节点个数的问题同样使用递归的思想,示意图和过程如下所示:
通过图示可知,叶子结点与其他结点的不同在于,叶子节点的左右子树皆为空,当遇见子树皆为空时就返回1,若子树不为空,则将其左右子树作为新的根进行新一轮叶子结点的计算。
- 其代码如下所示:
int BinaryTreeLeafSize(TNode* root)
{
if (root == NULL)
return 0;
if (root->left == NULL && root->right == NULL)
return 1;
else
return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}
5、二叉树第K层结点个数
针对于求二叉树第K层结点个数,同样使用递归的方法进行。
若我们将二叉树根节点看作第1层。
那么求第K层结点个数就相当于求以根节点为根的树的第K层结点个数。
对应于第二层就相当于求以第二层为根的树的第K-1层结点个数。
依次类推,直到相当于求第K层的第1层个数。
- 其代码如下所示:
int BinaryTreeLevelKSize(TNode* root, int k)
{
if (root == NULL)
return 0;
if (k == 1 && root != NULL)
return 1;
else
return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}
6、二叉树的高度
对于二叉树的高度(深度),概念中是指二叉树叶子节点所在位置为二叉树整体的最大高度。
因此对于本文示例所给二叉树,在求解高度时,所算高度为左子树和右子树中最大的高度 + 1(根节点也算一个高度),并将此规律衔接递归思想应用到每一颗字数之中。
其示意图及过程如下:
- 其代码如下所示:
int BinaryTreeHigh(TNode* root)
{
if (root == NULL)
return 0;
return BinaryTreeHigh(root->left) > BinaryTreeHigh(root->right) ? BinaryTreeHigh(root->left) + 1 : BinaryTreeHigh(root->right) + 1;
}
但对于上文代码我们可以发现,在依次递归的过程中同样的函数重复调用了,在对于递归深度较浅的结构时,其效率不会受重复调用的影响,但对于递归深度较大,且较为复杂的结构时,效率会大打折扣,故对此代码进行优化,以避免重复调用。
int BinaryTreeHigh(TNode* root)
{
if (root == NULL)
return 0;
int left = BinaryTreeHigh(root->left);
int right = BinaryTreeHigh(root->right);
return left > right ? left + 1 : right + 1;
}
7、二叉树查找值为x的结点
对于查找值为x的结点,同样是递归的思想,如果在二叉树中没有值为x的结点,直接返回NULL,在递归过程中,如若遇到空指针,则直接返回NULL,若寻找到了值为x的结点,返回此结点地址,若递归过程中所传结点不为空且值不为所求值x,则返回其左节点递归结果,或右结点递归结果。
- 其代码如下所示:
TNode* BinaryTreeFind(TNode* root, TDataType x)
{
if (root == NULL)
return NULL;
if (root->val == x)
return root;
TNode* rst1 = BinaryTreeFind(root->left, x);
if (rst1)
return rst1;
TNode* rst2 = BinaryTreeFind(root->right, x);
if (rst2)
return rst2;
return NULL;
}
8、完整代码展示
- Tree.h
typedef int TDataType;
typedef struct TreeNode
{
TDataType val;
struct TreeNode* left;
struct TreeNode* right;
}TNode;
TNode* BuyNode(TDataType x);
TNode* CreateTree();
二叉树结点个数
int BinaryTreeSize(TNode* root);
二叉树叶子结点个数
int BinaryTreeLeafSize(TNode* root);
二叉树第k层结点个数
int BinaryTreeLevelKSize(TNode* root, int k);
二叉树高度
int BinaryTreeHigh(TNode* root);
二叉树查找值为x的结点
TNode* BinaryTreeFind(TNode* root, TDataType x);
- Tree.c
#include"Tree.h"
TNode* BuyNode(TDataType x)
{
TNode* tmp = (TNode*)malloc(sizeof(TNode));
if (tmp == NULL)
{
perror("BuyNode: malloc fail");
return NULL;
}
tmp->val = x;
tmp->left = tmp->right = NULL;
return tmp;
}
TNode* CreateTree()
{
TNode* node1 = BuyNode(1);
TNode* node2 = BuyNode(2);
TNode* node3 = BuyNode(3);
TNode* node4 = BuyNode(4);
TNode* node5 = BuyNode(5);
TNode* node6 = BuyNode(6);
node1->left = node2;
node1->right = node3;
node2->left = node4;
node2->right = node5;
node3->left = node6;
return node1;
}
二叉树结点个数
int BinaryTreeSize(TNode* root)
{
return root == 0 ? 0 : BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}
二叉树叶子结点个数
int BinaryTreeLeafSize(TNode* root)
{
if (root == NULL)
return 0;
if (root->left == NULL && root->right == NULL)
return 1;
else
return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}
二叉树第k层结点个数
int BinaryTreeLevelKSize(TNode* root, int k)
{
if (root == NULL)
return 0;
if (k == 1 && root != NULL)
return 1;
else
return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}
二叉树高度
int BinaryTreeHigh(TNode* root)
{
if (root == NULL)
return 0;
int left = BinaryTreeHigh(root->left);
int right = BinaryTreeHigh(root->right);
return left > right ? left + 1 : right + 1;
}
//int BinaryTreeHigh(TNode* root)
//{
// if (root == NULL)
// return 0;
//
// return BinaryTreeHigh(root->left) > BinaryTreeHigh(root->right) ? BinaryTreeHigh(root->left) + 1 : BinaryTreeHigh(root->right) + 1;
//}
二叉树查找值为x的结点
TNode* BinaryTreeFind(TNode* root, TDataType x)
{
if (root == NULL)
return NULL;
if (root->val == x)
return root;
TNode* rst1 = BinaryTreeFind(root->left, x);
if (rst1)
return rst1;
TNode* rst2 = BinaryTreeFind(root->right, x);
if (rst2)
return rst2;
return NULL;
}
- TreeTest.c
#include"Tree.h"
void test()
{
TNode* root = CreateTree();
printf("二叉树结点个数为:%d个\n", BinaryTreeSize(root));
printf("二叉树叶子结点的个数为:%d个\n",BinaryTreeLeafSize(root));
int k = 1;
printf("二叉树第K层结点个数为:%d个\n",BinaryTreeLevelKSize(root, k));
printf("二叉树高度为:%d\n", BinaryTreeHigh(root));
printf("值为4的节点地址为:%p\n", BinaryTreeFind(root, 4));
}
int main()
{
test();
return 0;
}
9、结语
十分感谢您观看我的原创文章。
本文主要用于个人学习和知识分享,学习路漫漫,如有错误,感谢指正。
如需引用,注明地址。