递归是一种很重要的思想,他可以帮助我们将大问题细分为许多个小问题,从而拆解问题,使得问题简单化,本篇博客主要利用的就是递归的思想,将整棵树的问题拆解为许多个根节点与左右子树的简单问题。
1. 二叉树遍历

总体核心思路:核心逻辑为递归调用,即分治思想,将问题不断拆解,从初始根节点与左右子树依次向下分解,直到叶子结点不可再分。
1.1 前序遍历
前序遍历主要是以 先根节点 再左子树 再右子树为逻辑遍历, 以例图为例
前序遍历后为:A B D NULL NULL NULL C NULL E NULL NULL
cs
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;
}
void PrevOrder(BTNode* root)
{
if (root == NULL)
{
printf("N ");
return;
}
printf("%d ", root->data);
PrevOrder(root->left);
PrevOrder(root->right);
}
1.2 中序遍历
核心逻辑:以左子树 根节点 右子树的顺序遍历
中序遍历后结果为:NULL D NULL B NULL A NULL C NULL E NULL
cs
void InOrder(BTNode* root)
{
if (root == NULL)
{
printf("N ");
return;
}
InOrder(root->left);
printf("%d ", root->data);
InOrder(root->right);
}
1.3 后序遍历
核心逻辑:以左子树 右子树 根节点 的顺序遍历
中序遍历后结果为:NULL NULL D NULL B NULL NULL NULL E C A
cs
void BehendOrder(BTNode* root)
{
if (root == NULL)
{
printf("N ");
return;
}
BehendOrder(root->left);
BehendOrder(root->right);
printf("%d ", root->data);
}
2. 树的计算
2.1 计算全部节点个数
计算全部节点就是遍历整棵树后计算所有节点即可,不递归的方法就是使用全局变量或者传一个指针参数,这二者均有局限,所以主要介绍递归。
非递归:
cs
int size = 0;
int TreeSize(BTNode* root)
{
if (root == NULL)
return 0;
else
++size;
TreeSize(root->left);
TreeSize(root->right);
return size;
}
void TreeSize(BTNode* root, int* psize)
{
if (root == NULL)
return 0;
else
++(*psize);
TreeSize(root->left, psize);
TreeSize(root->right, psize);
}
递归:依旧是将大问题分解为小问题,然后直到无法分解为止,将遍历整棵树看做遍历一个根节点与左子树和右子树,逐层拆解。
cs
int TreeSize(BTNode* root)
{
return root == NULL ? 0 :
TreeSize(root->left) + TreeSize(root->right) + 1;
}
2.2 计算叶子节点个数
首先空树没有叶子节点,直接返回返回0,是叶子结点返回1,不是叶子结点就递归返回他的左子树与右子树,逐层拆解到叶子节点。
cs
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);
}
2.3 计算树的高度
这里保存左右子树的高度,防止递归导致栈溢出。即分别求左子树与右子树的告诉,返回较大的值加一。
但是可以使用fmax来取出二者较大值,也是一种新思路。
cs
有效率问题
int TreeHeight(BTNode* root)
{
if (root == NULL)
return 0;
return TreeHeight(root->left) > TreeHeight(root->right) ?
TreeHeight(root->left) + 1 : TreeHeight(root->right) + 1;
}
int fmax(int x, int y)
{
return x > y ? x : y;
}
int TreeHeight(BTNode* root)
{
if (root == NULL)
return 0;
return fmax(TreeHeight(root->left), TreeHeight(root->right)) + 1;
}
cs
int TreeHeight(BTNode* root)
{
if (root == NULL)
return 0;
int leftHeight = TreeHeight(root->left);
int rightHeight = TreeHeight(root->right);
return leftHeight > rightHeight ?
leftHeight + 1 : rightHeight + 1;
}
2.4 计算第K层的节点数
递归:空树返回空,第零层即只有根节点返回1,其余的拆解为左子树与右子树的问题,依次递归。
cs
int KTreeSize(BTNode* root, int k)
{
if (root == NULL)
return 0;
if(k == 0)
return 1;
return KTreeSize(root->left, k - 1) + KTreeSize(root->right, k - 1);
}
3. Leetcode 练习
思路解析: 判断是否为单值二叉树就是判断所有节点的值是否相同。但是依次遍历判断有些麻烦,所以这里可以使用反证法,即只要找到不符合的节点就直接返回false,并结合递归的方法,将大问题分解为小问题。
具体解析:首先空树符合单值二叉树,直接返回true,其次判断左子树,先判断是否存在,之后判断其节点对应的值是否与根节点对应的值相同,右子树同理,最后返回递归的值。
cs
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);
}
