一、实现思想

  平衡二叉树比二叉查找树升级在哪里?

  平衡二叉树是在二叉查找树的属性『左小右大』的基础上做一个调整,确保每一个节点的左右子树高度差不大于1,这样在运用『左小右大』进行查找时,就可以一下子排除许多数。最直观的,平衡二叉树就不会有像二叉查找树那样一边倒的例子。

  如何确保每个节点的左右子树高度差不大于1?

  每插入一个节点后,我都对这棵树进行检查(这个检查正是本博客的重点),如果发现不平衡,立马做出调整。

 

二、实现图例

  举一个例子

 

 

  总结出四大情况

  RR调整

  LL调整

  RL调整

  LR调整

  

 

 

 

 

 

 

 

 三、实现代码

  插入的函数    (其中一部分代码,这是我觉得最精华的地方,利用了递归,一次递归搞定两样事情)

  1.   它是递归下去寻找插入的位置
  2.   插入完成之后,它会层层地跳出递归,顺便检查这条路径上地节点是否平衡,不平衡则立即调整
 1 //向树中插入元素                    //不需要在全局寻找最小不平衡点,用递归就能统一格式地寻找
 2 pTree insert(pTree root, int data)
 3 {
 4 
 5     //如果为NULL,就可以new一个节点,并且把指向返回给上一个指向
 6     if (root == NULL)
 7     {
 8         pTree p = new Tree();
 9         p->data = data;
10         p->left = NULL;
11         p->right = NULL;
12         root = p;
13     }
14     else
15     {
16         if (data < root->data)
17             root->left = insert(root->left, data); //先是执行了插入操作,再去判断是否需要调整
18         if (height(root->left) - height(root->right) == 2)
19         {
20             //判断需要进行哪一种调整,只需要判断插入的data,相对于最小不平衡点的下一个节点,的位置。太妙了,我没有想到这样比较
21             if (data < root->left->data)
22                 root = LLrotation(root);
23             else
24                 root = LRrotation(root);
25         }
26         if (data >= root->data)
27             root->right = insert(root->right, data);
28         if (height(root->right) - height(root->left) == 2)
29         {
30             if (data < root->right->data)
31                 root = RLrotation(root);
32             else
33                 root = RRrotation(root);
34         }
35     }
36 
37     return root;
38 }

 

  判断树高的函数    (这也是我觉得比较神奇的地方,也是利用了递归)

 1 //计算一个树的高度
 2 int height(pTree root)
 3 {
 4     int hl, hr, max;
 5     if (root)
 6     {
 7         //代码太妙了,有许多递归的用法
 8         hl = height(root->left);
 9         hr = height(root->right);
10         max = hl > hr ? hl : hr;
11         return max + 1;
12     }
13     else
14         return 1;
15 }

 

  全部代码

#include <stdio.h>

typedef struct TreeNode *pTree;
typedef struct TreeNode Tree;
struct TreeNode
{
    int data;
    pTree left;
    pTree right;
};

pTree buildTree(int a[], int len); //建立自平衡二叉树
pTree insert(pTree T, int v);      //向树中插入元素
int height(pTree T);               //计算一个树的高度
pTree LLrotation(pTree T);         //LL旋转,左单旋转
pTree LRrotation(pTree T);         //LR旋转,左右双旋
pTree RRrotation(pTree T);         //RR旋转,右单旋转
pTree RLrotation(pTree T);         //RL旋转,右左双旋
void middle_print(pTree T);        //中序遍历

//建立自平衡二叉树
pTree buildTree(int a[], int len)
{
    pTree root = NULL;
    for (int i = 0; i < len; i++)
    {
        root = insert(root, a[i]);
    }
    return root;
}

//向树中插入元素                    //不需要在全局寻找最小不平衡点,用递归就能统一格式地寻找
pTree insert(pTree root, int data)
{

    //如果为NULL,就可以new一个节点,并且把指向返回给上一个指向
    if (root == NULL)
    {
        pTree p = new Tree();
        p->data = data;
        p->left = NULL;
        p->right = NULL;
        root = p;
    }
    else
    {
        if (data < root->data)
            root->left = insert(root->left, data); //先是执行了插入操作,再去判断是否需要调整
        if (height(root->left) - height(root->right) == 2)
        {
            //判断需要进行哪一种调整,只需要判断插入的data,相对于最小不平衡点的下一个节点,的位置。太妙了,我没有想到这样比较
            if (data < root->left->data)
                root = LLrotation(root);
            else
                root = LRrotation(root);
        }
        if (data >= root->data)
            root->right = insert(root->right, data);
        if (height(root->right) - height(root->left) == 2)
        {
            if (data < root->right->data)
                root = RLrotation(root);
            else
                root = RRrotation(root);
        }
    }

    return root;
}

//计算一个树的高度
int height(pTree root)
{
    int hl, hr, max;
    if (root)
    {
        //代码太妙了,有许多递归的用法
        hl = height(root->left);
        hr = height(root->right);
        max = hl > hr ? hl : hr;
        return max + 1;
    }
    else
        return 1;
}

//LL旋转,左单旋转
pTree LLrotation(pTree T)
{
    pTree root = T->left;
    T->left = root->right;
    root->right = T;
    return root;
}
//LR旋转,左右双旋
pTree LRrotation(pTree T)
{
    pTree b = T->left;
    pTree c = b->right;
    b->right = c->left;
    c->left = b;
    T->left = c;
    T = LLrotation(T);
    return T;
}

//RR旋转,右单旋转
pTree RRrotation(pTree T)
{
    pTree root = T->right;
    T->right = root->left;
    root->left = T;
    return root;
}
//RL旋转,右左双旋
pTree RLrotation(pTree T)
{
    pTree b = T->right;
    pTree c = b->left;
    b->left = c->right;
    c->right = b;
    T->right = c;
    T = RRrotation(T);
    return T;
}
//中序遍历
void middle_print(pTree T)
{
    if (T->left != NULL)
        middle_print(T->left);
    printf("%d\n", T->data);
    if (T->right != NULL)
        middle_print(T->right);
}
int main(void)
{
    int len = 6;
    int a[] = {70, 61, 96, 88, 120, 90};
    pTree root = NULL;
    root = buildTree(a, len);
    // printf("%d\n", root->data);
    middle_print(root);

    return 0;
}
/*
输出
———— 
61
70
88
90
96
120
————
 */

  

 

四、总结

  这是我第一次感觉到递归如此厉害,我之前是用一个笨方法,从全局出发寻找那个最小不平衡点,真的是太麻烦,这里的一次递归便可以完成两件事情。

补充:

  这里没有讲删除节点,其实删除节点和二叉查找树删除是差不多的,只是在那个基础上多了一个调整。(这里算给自己挖一个坑吧,有机会在过来填)

2020-08-28

posted on 2020-08-28 00:05  Coderon  阅读(196)  评论(0编辑  收藏  举报