AVL平衡二叉树是什么?如何用C++代码实现

12 篇文章 0 订阅

一、概念

平衡二叉树(AVL树)

        特点:左子树和右子树都是平衡二叉树,且左右子树的深度差绝对值不超过1。       

        平衡因子BF:定义为该节点的左子树深度减去它的右子树深度。则平衡二叉树上的所有结点的平衡因子只可能是-1,0,1.只要二叉树上有一个结点的平衡因子的绝对值大于1,那么该二叉树就是不平衡的。

举例:

下图1不是BST树,59>58

下图2不是,58不满足左右子树高度差为1的条件

 

下图3不是

 

二、实现

        有以下一堆数字,实现依次创建为平衡二叉树:3 2 1 4 5 6 7 8 10 9,从而理解左旋和右旋。

        插入“1”后发现“3”不平衡(3的左子树-右子树个数=2>1),需要将“3”右旋,如下:

        也就是说,插入A节点之后,B不平衡,就要旋转B节点。那么旋转的方向,取决于那哪边平衡因子小,上例中,左节点平衡因子大于右节点的,就往右旋转。

        什么叫向右旋?就是将不平衡的B旋转到节点的右边

         然后插入“4”,“5”,插入完“5”后,会发现“3”和“2”不平衡,他们的平衡因子为2,因此对“3”左旋:

此时“2”和“3”都平衡了,然后继续插入“6”,发现“2”不平衡了,需要对“2”进行右旋:

 1.先让“2”的右子树变为“3”

2.让“2”的整体变为“4”的左子树

 然后插入“7”,发现“5”不平衡,对“5”左旋:

 

插入"10"和“9”

此时“7”不平衡,右左旋,先把“10“放在“9”的右子树,然后把“7”放在“9”的左子树,把根“9”和前面的树根“6“连在一起。

C++代码实现


class Node{
  Node():m_left(NULL),m_right(NULL),m_bf(0){}
  Node(int v):m_value(v),m_left(NULL),m_right(NULL),m_bf(0){}
  int m_value;//值
  Node* m_left;//左孩子
  Node* m_right;//右孩子
  int m_bf;//平衡因子
};

class AVLTree
{
public:
  AVLTree():m_root(NULL){}
  void InsertAVLTreeValue(int v)
  {
    InsertAVLTreeValue(root,v);
  }
  void InsertAVLTreeValue(Node*& root,int v);
  void InOrder()
  {
    InOrder(root);
  }
  void InOrder(Node* root);
  void RotateR(Node* root);
  void RotateL(Node* root);
  void RotateRL(Node* root);
  void RotateLR(Node* root);
private:
  Node* m_root;//指向根节点的指针
};
void AVLTree::RotateL(Node* root)
{
  Node* child=root;
  root=child->m_right;
  child->m_right=root->left;
  root->left=root;
  root->m_bf=child->m_bf=0;
}
void AVLTree::RotateR(Node* root)
{
  Node* child=root;
  root=child->m_right;
  child->m_left=root->right;
  root->right=root;
  root->m_bf=child->m_bf=0;
}
void AVLTree::RotateLR(Node* root)
{
  Node* childR=root;
  Node* childL=childR->m_right;
  root=childL->m_right;
  childL->m_right=root->m_left;
  root->m_left=childL;
  
  if(root->m_bf<=0)
    childL->m_bf=0;
  else
    child->m_bf=-1;

  childR->m_left=root->m_right;
  root->m_right=childR;
  if(root->m_bf==-1)
    childR->m_bf=1;
  else
    childR->m_bf=0;
  root->m_bf=0;
}
void AVLTree::RotateRL(Node* root)
{
  Node* childL=root;
  Node* childR=childL->m_left;
  root=childR->m_left;

  childR->m_left=root->m_right;
  root->m_right=childR;
  
  if(root->m_bf>=0)
    childL->m_bf=0;
  else
   child->m_bf=1;

  childR->m_right=root->m_left;
  root->m_left=childL;
  if(root->m_bf==1)
    childL->m_bf=-1;
  else
    childL->m_bf=0;
  root->m_bf=0;
}

void AVLTree::InOrder(Node* root)
{
  if(root!=NULL)
  {
    InOrder(root->m_left);
    cout<<root->m_value<<" ";
    InOrder(root->m_right);
  }
}
void AVLTree::InsertAVLTreeValue(Node*& root,int v)
{
  Node* p=root;
  Node* parent=NULL;
  stack<Node*> ss;//用栈存放待插入新结点路径上的结点,以便后续计算平衡因子bf
  //1.标记parent和p并存放路径的节点到栈内
  while(p!=NULL)
  {
    if(p->m_value==v)//如果待插入结点和树内已存在结点相同就不插入了
      return;
    parent=p;
    aa.push(parent);
    if(v<parent->value)
      p=p->m_left;
    else
      p=p->m_right;
  }
  p=new Node(v);//2.创建新节点存放值
  if(parent==NULL)//树为空当前节点为根节点
  {
    root=p;
    return ;
  }
  //3.把新结点和前面已经创建完的树链接到一起
  if(v<parent->m_value)
    parent->m_left=p;
  else
    parent->m_right=p;

  //4.通过旋转使其满足AVL树条件
  while(!ss.empty())
  {
    parent=ss.top();//栈顶元素赋值给parent
    ss.pop();//出栈
    if(parent->m_left==p)
      parent->m_bf--;//左--
    else
      parent->m_bf++;//右++

    if(parent->m_bf==0)//★平衡就不用再看了
      break;

    if(parent->m_bf==1||parent->m_bf==-1)
    {//此时需要看下上一层结点,循环执行,如果栈不空就从栈内继续取数据
      p=parent;
    }

    else//bf==2,需要旋转
    {
      /*旋转分为两大类
       *1.单旋转:当parent和p的平衡因子是同号
       *2.双旋转:异号
      */
      int flag=parent->m_bf>0?1:-1;
      if(p->m_bf==flag)//同号
      {
        if(flag==-1)
          RotateR(parent);//右旋
        else
          PotateL(parent);//左旋
      }
      else{//异号
        if(flag==1)
          RotateRL(parent);//右左旋
        else
          RotateLR(parent);//左右旋
      }
    }
    //5.旋转完之后和原来的树链接到一起
    if(ss.empty())
    {
      m_root=parent;
    }
    else{
      Node* q=ss.top();
      ss.pop();
      if(q->m_value > parent->m_value)
        q-<m_left=parent;
      else
        q->m_right=parent;
    }
  }
}
void main()
{
  int num[]={3,2,1,6,5,4,7,10,9,8};
  int n=sizeof(num)/sizeof(num[0]);
  AVLTree t;
  for(int i=0;i<n;i++)
  {
    t.InsertAVLTreeValue(num[i]);
  }
  t.InOrder();
  cout<<endl;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值