假设有一个二叉树,那么我们应该如何知道它的高度、层数等相关信息,下面我们利用二叉树递归的本质来依次求解。
求结点数目我们不能在函数里面创建临时计数变量,形参的改变不影响实参,递归的时候出来作用域就销毁了,因此我们需要传临时变量的地址。
void TreeSize(BTNode* root, int* size)
{
if (root == NULL)
return;
*size += 1;
TreeSize(root->left, size);
TreeSize(root->right, size);
}
递归结束条件是结点为空,这时返回0,否则返回左右子树的结点数之和+1,这里的是计数的是根结点。
int TreeSize1(BTNode* root)
{
if (root == NULL)
return 0;
return TreeSize1(root->left) + TreeSize1(root->right) + 1;
//加一加的是根结点
}
二叉树可由其左子树和右子树构成,左右子树高度便能求出二叉树的高度。当根结点为空时,返回0,根节点不为空时,返回左右子树的较大的高度+1,加一是指加上根的那一层。
int TreeHeight(BTNode* root)
{
if (root == NULL)
return 0;
int Left = TreeHeight(root->left);
int Right = TreeHeight(root->right);
int max = Left > Right ? Left : Right;
return max + 1;
}//求高度
第k层相对第一层需要往下递归k-1次,相对第二层需要递归k-2次,因此走到第k层需要递归k-1次,这时k==1。如果k>层数,提前走到空就返回 0。k为1时返回该结点1,否则返回左右子树之和。
int TreeKLevel(BTNode* root, int k)
{
//走不到第k层就空了
if (root == NULL)
return 0;
//当k=1时每次访问结点都返回1
if (k == 1) //相对位置关系,走到第k层说明要走k-1次,目标层是k==1
return 1;
else
return TreeKLevel(root->left, k - 1) + TreeKLevel(root->right, k - 1);
}
二叉树的层数遍历我们需要用到队列先进先出的性质,如果根结点不为空,那么根节点入队。再把它的左右不为空的孩子入队,这时我们需要让左右孩子已经入队的双亲出队,这样左右孩子其中一个又变成了根节点,可以让其孩子入队。注意队列存的是结点的指针,有结点地址便能访问结点,不需要存整个结点。
void LevelOrder(BTNode* root)
{
assert(root);
Queue q;
QueueInit(&q);
if (root != NULL)
QueuePush(&q, root);
while (!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);
printf("%d ", front->data);
QueuePop(&q);
if (front->left != NULL)
QueuePush(&q, front->left);
if (front->right != NULL)
QueuePush(&q, front->right);
}
printf("\n");
QueueDestroy(&q);
}
有了上面层序遍历的经验,只有根结点不为空,我们把左右孩子均入队。
我们可以发现如果是完全二叉树,出队时遇到NULL,那么我们跳出循环的话,队列中那么剩下的结点地址应该全是NULL。
如果不是完全二叉树,那么队出到NULL是,跳出循环,队列中肯定还有不为NULL的地址。
bool TreeComplete(BTNode* root)
{
Queue q;
QueueInit(&q);
//先让队列进一个数据才能循环起来
QueuePush(&q, root);
while (!QueueEmpty(&q))
{
BTNode* head = QueueFront(&q);
QueuePop(&q);
//删除根结点地址在入它的孩子
if (head != NULL)
{
QueuePush(&q, head->left);
QueuePush(&q, head->right);
}
else //队出空则跳出循环
{
break;
}
}
while (!QueueEmpty(&q))
{
if (QueueFront(&q))
{
//进到这说明地址不是NULL
QueueDestroy(&q);
return false;
}
QueuePop(&q);
}
QueueDestroy(&q);
return true;
}
若一棵树是当值二叉树,那么所有结点值相等,因为树的本质的是递归的,我们只需要比一组根和左右结点的值是否相等就行,再递归往下进行就行。
100. 相同的树
226. 翻转二叉树
翻转一颗树,我们可以从上往下翻转,以可以从上往下翻转,一样是根的左右的孩子翻转,再递归依次翻转。个人觉得还是从上往下翻转层次思路更加清晰一些。
有了上面相同的树题目经验,那个题是两颗树同时往一个方向走进行比较。而对称二叉树我们把一颗树看成两颗树,自己调用自己,一颗树往左则另外一颗树往其反方向走便能判断出其是不是对称的。
写了前面单值二叉树后,这个题思路差不多。先从根开始比较,不是再比左右子树。递归进行,这里只需要调用判断相同的树这个辅助函数就行,也就是递归嵌套了一层递归。
这些知识还在初阶的二叉树知识,基础巩固好了以后学复杂的二叉树知识也会轻松不少,期待下一篇博客见面。