概述
本文将对链式结构二叉树的几种功能进行实现与讲解
二叉树节点个数的判断
思路一:遍历二叉树
对于节点个数的判断,我们首先想到的最简单的方法就是任选一种遍历方式遍历二叉树(这里以前序遍历为例),定义变量size,每进行一次遍历就将size++,于是我们尝试写代码:
int TreeSize(BTNode* root)
{
int size = 0;
if (root == NULL)
return 0;
else
{
size++;
TreeSize(root->left);
TreeSize(root->right);
return size;
}
}
我们尝试运行代码,却发现最后打印出的结果不为6,而是等于1。我们尝试分析一下代码,发现当每次对函数进行递归时,size都会被赋值0,size++后就为1,我们不想要size被每次都赋值为0,所以在这里我们将size设为静态变量(即在size前的int前加static),但仍然会出现问题,因为局部的静态变量只会被初始化一次,所以这个函数只能使用一次。运行结果如下:
正确的实现方法:为了让size不会被每次都初始化为0,并且我们可以较方便地控制,我们应该将变量设为全局变量 (无论是否为静态变量),代码如下:
int size = 0;
int TreeSize(BTNode* root)
{
if (root == NULL)
return 0;
else
{
size++;
TreeSize(root->left);
TreeSize(root->right);
return size;
}
}
//代码测试
int main()
{
BTNode* root = CreatBinaryTree();
size = 0;
printf("TreeSize:%d\n", TreeSize(root));
size = 0;
printf("TreeSize:%d\n", TreeSize(root));
size = 0;
printf("TreeSize:%d\n", TreeSize(root));
return 0;
}
测试结果:
思路二:前置递归
我们不妨尝试一种新的思路:如果节点个数为0,则返回空,如果不为0,则在每个节点的位置进行:左子树+右子树+1的计算思路,以下图为例:
先在1这个节点计算:1的左子树是2,2的节点数不知道,继续往下寻找,2的左子树是3,继续找,3的左子树是0,加上右子树0再加1等于1,所以三这个节点的值算出来等于1;再往上,2的左子树3的值1加右子树0再加1等于2;再往上1的左子树2的值为2加右子树4的值再加一,右子树4的值又继续往下寻找......最后得出来的值即为节点数。实现代码如下:
int TreeSize(BTNode* root)
{
if (root == NULL)
return 0;
else
{
return TreeSize(root->left) + TreeSize(root->right) + 1;
}
//或者用三目操作符一步到位
//return root == NULL?0:
// TreeSize(root->left) + TreeSize(root->right) + 1;
}
思路可能较为复杂,但转换成代码就十分简洁明了。
二叉树叶节点个数的判断
在这里,我们首先尝试递归的思想:首先判空:节点为空返回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);
}
//代码测试
int main()
{
BTNode* root = CreatBinaryTree();
printf("TreeLeafSize:%d\n", TreeLeafSize(root));
return 0;
}
二叉树高度的判断
我们想要求二叉树的高度,可以通过递归对二叉树的每一层进行比较,而每一次比较都会进行加1,实现代码如下:
int TreeHeight(BTNode* root)
{
if (root == NULL)
return 0;
return TreeHeight(root->left) < TreeHeight(root->right) ? TreeHeight(root->right) + 1 :
TreeHeight(root->left) + 1;
}
但我们通过对递归的分析,会发现这样会出现大量内存的消耗,因为每次对节点进行计算后都没有存储计算所得值,这样就会导致越到后面计算多节点二叉树时前面都会再算一次,所以为了减少不必要的内存浪费,我们创造两个变量将左高度和右高度分别存储,代码如下:
int TreeHeight(BTNode* root)
{
if (root == NULL)
return 0;
int LeftHeight = TreeHeight(root->left);
int RightHeight = TreeHeight(root->right);
return LeftHeight < RightHeight ? RightHeight + 1 :
LeftHeight + 1;
}
//代码测试
int main()
{
BTNode* root = CreatBinaryTree();
printf("TreeHeight:%d\n", TreeHeight(root));
return 0;
}
测试结果如下:
单值二叉树
思路一:递归实现
首先为root判空:如果为空返回true,返回true的条件比较苛刻,所以我们倾向于返回false,因为只要有一个不相等就返回false,代码如下:
bool isUnivalTree(BTNode* root)
{
if (root == NULL)
return true;
if (root->left && root->left->data != root->data)
return false;
if (root->right && root->right->data != root->data)
return false;
return isUnivalTree(root->left)//根与左孩子比
&& isUnivalTree(root->right);//根与右孩子比
}
思路二:遍历实现
通过再创建一个子函数,将原函数的值传入里面来进行每个节点数值的判断,代码如下:
bool _isUnivalTree(struct TreeNode* root,int val)
{
if(root == NULL)
return true;
else if(val != root->val)
return false;
return _isUnivalTree(root->left,val)
&& _isUnivalTree(root->right,val);
}
bool isUnivalTree(struct TreeNode* root)
{
return _isUnivalTree(root,root->val);
}
总结
在链表结构二叉树中,递归的使用是必不可少的,在使用的过程中,要时常问问自己:这个递归结构可不可以这样用?具体的逻辑实现过程是怎样的?只有这样,才能学好链表结构二叉树。
最后,如果觉得我写得不错,请别忘了点赞,收藏,评论!!!