单值二叉树
- 判断根结点与左右子结点值是否相等
- 使用分治判断左右子树是否为单值二叉树
- 检查到叶子节点后返回真
//单值二叉树
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);
}
检查两颗树是否相同
- 先判断结构是否相同,即该结点是否都不为空
- 再判断两当前结点值是否相等
//相同的树
bool isSameTree(struct TreeNode* p, struct TreeNode* q) {
//两树同时检查到空结点返回真
if (p == q && q == NULL)
{
return true;
}
//两棵树当前结点只有一个不为空
//结构不同,返回假
if (p == NULL || q == NULL)
{
return false;
}
//两棵树当前结点值不相等,返回假
if (q->val != p->val)
{
return false;
}
//对两棵树当前结点的左右子树进行分治
return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}
对称二叉树
- 直接使用判断相同树的实现
- 改为对左子树的左子树与右子树的右子树相比较
//对称二叉树
//直接使用相同树的实现
//改为对左子树的左子树与右子树的右子树相比较
bool isSameTree2(struct TreeNode* p, struct TreeNode* q) {
if (p == q && q == NULL)
{
return true;
}
if (p == NULL || q == NULL)
{
return false;
}
if (q->val != p->val)
{
return false;
}
return isSameTree2(p->left, q->right) && isSameTree2(p->right, q->left);
}
bool isSymmetric(struct TreeNode* root) {
return isSameTree2(root->left, root->right);
}
翻转二叉树
- 交换父节点的左右子结点,
- 再对子结点执行相同操作,以此递归
struct TreeNode* invertTree(struct TreeNode* root){
if (root == NULL)
{
return NULL;
}
struct TreeNode* tmp = root->left;
root->left = root->right;
root->right = tmp;
root->left = invertTree(root->left);
root->right = invertTree(root->right);
return root;
}
二叉树的前序遍历
- 先访问根结点再遍历左右子树
- 这里返回数组的下标 i 注意通过传地址实现值得累加
- 也可直接将 returnSize 作为下标,不用另外定义下标 i,用法相同
//前序遍历二叉树
int TreeSize(struct TreeNode* root)
{
return root == 0 ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}
void PreOrder(struct TreeNode* root, int* ret, int* pi)
{
if (root == NULL)
return;
ret[*pi] = root->val;
(*pi)++;
PreOrder(root->left, ret, pi);
PreOrder(root->right, ret, pi);
return;
}
int* preorderTraversal(struct TreeNode* root, int* returnSize) {
int size = TreeSize(root);
int* ret = (int*)malloc(size * sizeof(int));
int i = 0;
PreOrder(root, ret, &i);
*returnSize = size;
return ret;
}
另一颗树的子树
- 判断每个结点为根结点的子树是否与 subRoot 相同
- 不相等则继续往下判断以其左右子结点为根结点的子树是否与 subRoot 相同
bool isSameTree(struct TreeNode* p, struct TreeNode* q) {
//两树同时检查到空结点返回真
if (p == q && q == NULL)
{
return true;
}
//两棵树当前结点只有一个不为空
//结构不同,返回假
if (p == NULL || q == NULL)
{
return false;
}
//两棵树当前结点值不相等,返回假
if (q->val != p->val)
{
return false;
}
//对两棵树当前结点的左右子树进行分治
return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}
int TreeSize(struct TreeNode* root)
{
return root == 0 ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}
bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot){
if(TreeSize(root) < TreeSize(subRoot))
{
return false;
}
if(isSameTree(root, subRoot))
{
return true;
}
return isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot);
}
二叉树第k层的结点个数
- 二叉树第k层即子树的k-1层,以此分治
- 子树为空返回0
- 递归到k层,若有结点则计数该结点,返回1
//求二叉树第k层的结点个数
int TreeKLevel(BTNode* root, int k)
{
if (root == NULL)
{
return 0;
}
//递归到第k层且结点存在时,计数该结点,返回1
if (k == 1)
{
return 1;
}
//对子树的k-1层进行分治
return TreeKLevel(root->left, k - 1) + TreeKLevel(root->right, k - 1);
}
查找二叉树中值为x的结点
- 又需要判断返回值,同时也需要返回这个值时,最好提前记录返回值,避免多次调用
//查找二叉树中值为x的结点
BTNode* BinaryTreeFind(BTNode* root, char x)
{
if (root == NULL)
{
return NULL;
}
if (root->data == x)
{
return root;
}
//左子树找
BTNode* leftret = BinaryTreeFind(root->left, x);
if (leftret)
{
return leftret;
}
//右子树找
BTNode* rightret = BinaryTreeFind(root->right, x);
if (rightret)
{
return rightret;
}
return NULL;
}
层序遍历
- 依托队列实现
- 首先将根结点入队列
- 出队列,同时记录队头值,并将其左右子结点入队列
void LevelOrder(BTNode* root)
{
Queue q;
QueueInit(&q);
//根结点入队列
if (root)
QueuePush(&q, root);
while (!QueueEmpty(&q))
{
//出队列,同时记录队头值
BTNode* front = QueueFront(&q);
QueuePop(&q);
printf("%d ", front->data);
//将其左右子结点入队列
if (front->left)
QueuePush(&q, front->left);
if (front->right)
QueuePush(&q, front->right);
}
QueueDestroy(&q);
}
判断是否为完全二叉树
- 先进行层序遍历,遇到空结点就停止
- 如果队列中存在有效元素,则不为完全二叉树
bool TreeComplete(BTNode* root)
{
Queue q;
QueueInit(&q);
//先进行层序遍历,遇到空结点就停止
if (root)
QueuePush(&q, root);
while (!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);
QueuePop(&q);
if (front == NULL)
break;
QueuePush(&q, front->left);
QueuePush(&q, front->right);
}
//检查队列中是否还存在有效数据
while (!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);
QueuePop(&q);
if (front)
{
QueueDestroy(&q);
return false;
}
}
QueueDestroy(&q);
return true;
}
二叉树的构建及遍历
- 参考字符串为前序,自然也通过前序构建
- 遇到 ‘#’ 则只向后移动字符串指针,返回空
// 二叉树的构建及遍历
// 二叉树的构建及遍历
BTNode* FormTree(char* pc, int* pi)
{
//遇到'#'返回空指针,继续向后遍历字符串
if (pc[*pi] == '#')
{
(*pi)++;
return NULL;
}
//遇到非'#'则开始构建树,同样按照前序构建
BTNode* node = (BTNode*)malloc(sizeof(BTNode));
node->data = pc[*pi];
(*pi)++;
node->left = FormTree(pc, pi);
node->right = FormTree(pc, pi);
return node;
}
//中序打印
void InOrder1(BTNode* root)
{
if (root == NULL)
{
return;
}
InOrder1(root->left);
printf("%c ", root->data);
InOrder1(root->right);
}
int main() {
char ch[100] = { 0 };
while (scanf("%s", ch) != EOF)
{
int i = 0;
BTNode* tree = FormTree(ch, &i);
InOrder1(tree);
printf("\n");
}
return 0;
}