顽强的毅力可以征服世界上任何一座高峰。 ——狄更斯
在这篇文章中我简单的介绍了二叉树的定义和一些简单的性质,其中最最重要的,其实我觉得应该是那句话,因此,二叉树是由递归定义的,这句话大大的影响着后面我们解题时候的想法。也需要我们很好的认识和理解递归在解题时的运用。
对于二叉树来说,并不是所有的二叉树都是满二叉树或完全二叉树,也有些二叉树是特例独行的,那么我们该怎么去计算对于普通的二叉树的最大高度呢?将一个个节点的左右深度进行对比。那么又怎么求得左右深度呢?==那我们就先求根节点左右子树,以左右子树为根的深度,怎么求得左右子树的深度呢?那我们就求左右子树的左右节点的子树的深度。当到最后的时候,左右子树都是空,那么开始返回,返回1,进行比较。然后比较出最后的答案。
对于求最大深度的问题,我们可以将大问题化小,运用递归的思想来对上面的问题进行解答。
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
};
typedef struct TreeNode TreeNode;
int maxDepth(struct TreeNode* root)
{
if(!root)
return 0;
int max=maxDepth(root->left);
int min=maxDepth(root->right);
if(min>max)
{
int m=min;
min=max;
max=m;
}
return max+1;
}
注意:其中最重要的是在比较一个节点左右两边哪一个是大的之后,一定要return的时候返回max+1,要把自己在的那一层加上。
对于二叉树叶子节点的个数,最重要的找到一个节点,**它的左右子树都是空的节点。**那么我们怎么找呢?那必然也是要通过递归,才能找到的啊。
递归的写法,相对来说通常都是简单,并且明了的,对于一些题目来说,往往看懂了之后才会恍然大悟,所以看懂后的自我反省和理解是必不可少的。根据思考方式,我们可以写出这样的函数。
//叶子节点的个数
int TreeLeafSize(TreeNode* root)
{
//空 返回0
if(root==NULL)
return 0;
if(!root->left&&!root->right)
return 1;
return TreeLeafSize(root->left)+TreeLeafSize(root->right);
对于求值为x的节点,还是通过左右子树的递归,逐个寻找到目标的点,就比如说,当根节点不是的时候,就去找根的左节点,右节点。当左右节点都不是的时候,就去找左右节点的左右节点。通过这样一层一层的选择,让我们知道哪里是值为X的节点。
寻找的顺序还是先左后右,当到了最后的时候,首先判断的应该是左下角的节点,当左下角的节点判断完之后返回他的父节点,再对右节点判断。
TreeNode*TreeFind(TreeNode*root,BTDataType x)
{
if(root==NULL)
return NULL;
if(root->data==x)
return root;
TreeNode*ret1=TreeFind(root->left,x);
if(ret1)
return ret1;
TreeNode*ret2=TreeFind(root->right,x);
return ret2;
return NULL;
}
对于这段代码,需要注意的是对于其中的ret1和ret2的作用是必不可少的。有人会说那如果是在判断条件那直接是root->left(right)为什么不可以呢?其实最重要的原因是时间复杂程度上的不同如果只是在判断中直接使用,而不是先存储在判断的话,那么导致的结果就是,如果判断正确了,但是并不知道值是什么,因为没有储存,所以还得再来一次,找到相同的节点,然后再输出。这样的话会导致时间称为两倍。
对于求K层的节点个数,首先理解叶子节点的求值方法。这题相当是之前的那题目的衍生吧。只不过判断+1的方法不再是它的左右节点是否为空,而是在他那一层的K是否等于1的。
递归的方法是需要合理运用的,对于根节点的K层,相当于是对于根节点左右子树的K-1层。所以,答案是这样的。
int TreeLevelK(TreeNode*root,int k)
{
assert(k>0);
if(root==NULL)
return 0;
if(k==1)
return 1;
return TreeLevelK(root->left)+TreeLevelK(root->right);
}
两个树是否相同,也就是说每一个节点是否相同,每一个节点是否相同,得判断是否是空,是否有左右子树,有左右子树的情况下,能否左右子树的值是相同的。
bool isSameTree(struct TreeNode*p,struct TreeNode*q)
{ //两个同时为空
if(!p&&!q)
return true;
//有一个不为空
if(!p||!q)
return false;
if(p->val!=q->val)
return false;
return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
二叉树是否对称,关键在于对于二叉树来说,他的每一个从根出发的节点是否相同于另一个从根出发,并且相反方向的节点。
或者说对于这题来说,我突然还想到一个方法,那就是把这个二叉树先左右交换,也就是镜像二叉树,将镜像二叉树的根节点保存,然后对比,看看两棵二叉树是否相同,相同也能证明出二叉树是对称的。
相对于第二个方法,显然是会进行更多的步骤,得不尝试,所以,接下来的代码还是按照第一种来讲,但是对于第二种来说,第二种应该也是能够通过的。
主函数的内容我就不多写了,我就把函数内容写一下。(思想是,根据根节点,取到左右子树,然后左右子树作为子树的根节点,判断两棵子树是否相同)
bool _isSymmetric(struct TreeNode*root1,struct TreeNode*root2)
{
if(root1==NULL&&root2==NULL)
return true;
if(!root1||!root2)
return false;
if(root1->val!=root2->val)
return false;
return _isSymmetric(root1->left,root2->left)&&_isSymmetric(root1->right,root2->right);
到这里,对于基本的二叉树相关的问题已经解决的,差不多了,在寒假继续进行中,我将继续更新关于二叉树的更深的题目,以及未来的堆类的介绍和相关的问题。大家多多关注。我会逐步更新的。