平衡二叉树

平衡二叉树

与二叉搜索树不同之处是结点结构里多了平衡因子

balance factor : 绝对值(左子树的高度-右子树的高度)

定义

要么是二叉搜索树要么是空树

左右子树的高度差不超过一

左右子树都是平衡二叉树

高度的定义

叶结点高度为 1

树的高度等于左子树高度与右子树高度的最大值

操作

1. 插入

平衡二叉树插入结点后可能会导致失衡

此时就要调整离插入结点最近的失衡的树 , 失衡的四种情况有不同的应对方式

  • 左单旋 : 失衡的树的左子树的左子树比较高

    让 leftHeight-1, rightHeight+1

    左子树的右子树变成根结点的左子树

    根结点变成左子树的右子树

    左子树变为根

    然后更新新的根结点的平衡因子后返回

在这里插入图片描述

  • 右单旋 : 失衡的树的右子树的右子树比较高

    让 leftHeight+1, rightHeight-1

    然后和左单旋一样 , 只是操作对象反过来了

    image-20210223142108330

  • 左-右双旋 : 失衡的树左子树的右子树比较高 , 左子树的右子树先右单旋一次 , 左子树再左单旋一次

  • 右-左双旋 : 失衡的树右子树的左子树比较高 , 右子树的左子树先左单旋一次 , 右子树再右单旋一次

这里是我推出的为什么 , 双旋后成功平衡了树,可以不看

插入节点后 , LeftHeight - RightHeight = 2或-2

要么是左子树高了,要么是右子树高了

---- 例如左子树高了

​ 那就让右子树高度加一 , 根结点加入右子树,变为新右子树的根结点 , newRH=oldRRH+1=oldRH+1

​ 然后让左子树高度减一 , 这里又分两个情况

​ 1. 左子树的左子树高了 , 既 oldLLH=oldLH-1

​ 那就左子树成为根 , 左子树的左子树成为新左子树 , 既 newLH=oldLLH=oldLH-1, 左子树高度成功减一

​ 2. 左子树的右子树高了 , 既 oldRRH=oldRH-1

​ 那就 左子树的右子树的根结点 成为根 , 新左子树的根结点不变 , newLH=oldLLH<=oldLH-1,左子树高度成功减一

​ 原先 左子树的右子树的左子树 成为 新左子树的右子树

​ oldLRLH <= oldLH-2, 接上去后 newLH <= oldLH-1 , 即使接到了新左子树的右边,也不会影响

​ 原先 左子树的右子树的右子树 成为 新右子树的左子树

​ oldLRRH <= oldLH-2,接上去后 newRH <= oldLH-1 , 即使接到了新右子树的左边,也不会影响

代码实现

/* 
 * 平衡二叉树
 * 
 * 要么是二叉搜索树要么是空树
 * 与二叉搜索树不同之处是结点结构里多了平衡因子 balance factor : 绝对值(左子树的高度-右子树的高度)
 * 
 * 定义 : 
 *    左右子树的高度差不超过一
 *    左右子树都是平衡二叉树
 * 高度定义 :
 *    叶结点高度为 1
 *    树的高度等于左子树高度与右子树高度的最大值
 * 
 * 操作 : 
 *    插入 : 
 *      平衡二叉树插入结点后可能会导致失衡 , 此时就要调整离插入结点最近的失衡的树 , 失衡有四种情况
 *      - 左单旋 : 失衡的树的<u>左子树的左子树</u>比较高
 *          具体操作: 原左子树的左子树替换原左子树 , 原左子树成为左子树的右子树
 *      - 右单旋 : 失衡的树的<u>右子树的右子树</u>比较高
 *          具体操作: 原右子树的右子树替换原右子树 , 原右子树成为右子树的左子树
 *      - 左-右双旋 : 失衡的树左子树的右子树比较高 , 左子树的右子树先右单旋一次 , 左子树再左单旋一次
 *      - 右-左双旋 : 失衡的树右子树的左子树比较高 , 右子树的左子树先左单旋一次 , 右子树再右单旋一次
 * 
 *    删除 : 待做
 *    查找 : 与二叉搜索树相同
 * 
 * 
 * 
 */

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <queue>
using namespace std;

struct TreeNode;
typedef int ElementType;
typedef struct TreeNode *PointerBinaryTree;
typedef struct TreeNode
{
  ElementType val;
  int balanceFactor;
  struct TreeNode *left;
  struct TreeNode *right;
  TreeNode(ElementType val)
  {
    this->val = val;
    left = nullptr;
    right = nullptr;
    this->balanceFactor = 0;
  }
} * PointerTreeNode;
// 插入
PointerBinaryTree insertNode(PointerBinaryTree t, int val);

// 左单旋
PointerTreeNode singleLeftRotation(PointerTreeNode root);
// 右单旋
PointerTreeNode singleRightRotation(PointerTreeNode root);
// 左右双旋
PointerTreeNode LeftAndRightRotation(PointerTreeNode root);
// 右左双旋
PointerTreeNode RightAndLeftRotation(PointerTreeNode root);
// 得到树的高度
int getHeight(PointerTreeNode node);
// 层序遍历:队列
void BreadthFirstTraversal(PointerBinaryTree tree);

// 插入
PointerBinaryTree insertNode(PointerBinaryTree t, int val)
{

  // 树为空树
  if (t == nullptr)
  {
    t = (PointerBinaryTree)malloc(sizeof(struct TreeNode));
    t->val = val;
    t->balanceFactor = getHeight(t->left) - getHeight(t->right);
    // printf("t = null , insert t \n");
  }
  // 树不为空
  // 先按二叉搜索树插入结点,再调整为平衡二叉树
  // 这里用递归来操作 , 二叉搜索树的插入那里我用的是迭代
  else if (val > t->val)
  {
    // printf("insert t right\n");
    t->right = insertNode(t->right, val);

    // 结点插入后弹栈返回
    // 判断树是否需要平衡旋转
    if (getHeight(t->left) - getHeight(t->right) == -2)
    {
      if (val > t->right->val)
      {
        // 右子树的右子树较高 , 右单旋
        t = singleRightRotation(t);
      }
      else
      {
        // 右子树的左子树较高 , 右左单旋
        t = RightAndLeftRotation(t);
      }
    }
  }
  else if (val < t->val)
  {
    // printf("insert t left\n");
    t->left = insertNode(t->left, val);
    // 结点插入后弹栈返回
    // 判断树是否需要平衡旋转
    if (getHeight(t->left) - getHeight(t->right) == 2)
    {
      if (val < t->left->val)
      {
        // 左子树的左子树较高 , 左单旋
        t = singleLeftRotation(t);
      }
      else
      {
        // 左子树的右子树较高 , 左右单旋
        t = LeftAndRightRotation(t);
      }
    }
  }
  else
  {
    // 发现相同的值 , 什么都不做
  }
  // 不太清楚为什么要更新平衡因子, 插入操作中也没有用过 , 也许是给删除操作用的
  // 老师没讲删除操作 , 先不写了 , 今天脑细胞消耗太大了
  t->balanceFactor = getHeight(t->left) - getHeight(t->right);
  return t;
}

// 左单旋
PointerTreeNode singleLeftRotation(PointerTreeNode root)
{
  PointerTreeNode newRoot = root->left;
  root->left = newRoot->right;
  newRoot->right = root;
  newRoot->balanceFactor = getHeight(newRoot->left) - getHeight(newRoot->right);
  return newRoot;
}
// 右单旋
PointerTreeNode singleRightRotation(PointerTreeNode root)
{
  PointerTreeNode newRoot = root->right;
  root->right = newRoot->left;
  newRoot->left = root;
  newRoot->balanceFactor = getHeight(newRoot->left) - getHeight(newRoot->right);
  return newRoot;
}

// 左右双旋
PointerTreeNode LeftAndRightRotation(PointerTreeNode root)
{
  // 树的左子树进行右单旋
  root->left = singleRightRotation(root->left);
  // 树进行左单旋
  root = singleLeftRotation(root);
  return root;
}

// 右左双旋
PointerTreeNode RightAndLeftRotation(PointerTreeNode root)
{
  // 树的右子树进行左单旋
  root->right = singleLeftRotation(root->right);
  // 树进行右单旋
  root = singleRightRotation(root);
  return root;
}
// 得到树的高度
int getHeight(PointerTreeNode node)
{
  if (node == nullptr)
    return 0;
  int leftHeight = getHeight(node->left);
  int rightHeight = getHeight(node->right);
  if (leftHeight > rightHeight)
  {
    return leftHeight + 1;
  }
  else
  {
    return rightHeight + 1;
  }
}
// 层序遍历:队列
void BreadthFirstTraversal(PointerBinaryTree tree)
{
  queue<PointerTreeNode> q;
  q.push(tree);
  PointerTreeNode node;
  cout << "---- 层序遍历";
  while (q.empty() != true)
  {
    printf("\n");
    for (int i = q.size(); i > 0; i--)
    {
      node = q.front();
      q.pop();
      cout << node->val << " ";
      if (node->left != nullptr)
        q.push(node->left);
      if (node->right != nullptr)
        q.push(node->right);
    }
  }
  printf("\n--------\n");
}
  /*
  input example :
  10   1 5 3 8 6   2 12 75 43 62 
  */
  /* output : 
  input size and data (example: 3 12 13 16)
  input : 10   1 5 3 8 6   2 12 75 43 62 
  insertNode over
  ---- 层序遍历
  3 
  1 12 
  2 6 62 
  5 8 43 75 
  -------- 
  */
int main()
{
  PointerBinaryTree tree = nullptr;
  int size = 0;
  printf("input size and data (example: 3 12 13 16)\ninput : ");
  scanf("%d", &size);
  int *input = (int*)malloc(size*sizeof(int));
  for (int i = 0; i < size; i++)
  {
    scanf("%d", input + i);
    tree = insertNode(tree, input[i]);
  }
  printf("insertNode over\n");
  BreadthFirstTraversal(tree);
  return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值