3.平衡二叉树

  平衡二叉树,又称AVL树,它是一种特殊的二叉排序树。

  3.1 平衡二叉树的四种自旋

  这个左旋、右旋,在方向上和我观念里的是相反的。

查了之后才知道:

1、外侧插入:LL、RR,都是在最边边上。
2、内侧插入:LR、RL,往里面来了些。

  (1)LL旋转和RR旋转:

   

void RR_Rotate(AVLTree *root){
    AVLTreeNode* rchild = (*root)->Right;
    (*root)->Right = rchild->Left;
    rchild->Left = *root;
    *root = rchild;
}

void LL_Rotate(AVLTree *root) {
    AVLTreeNode* lchild = (*root)->Left;
    (*root)->Left = lchild->Right;
    lchild->Right = *root;
    *root = lchild;
}

  (2)LR,RL型旋转(插入的节点在CL上 还是CR上是没有影响的)

  LR型旋转图解

void LR_Rotate(AVLTree *root) {
    RR_Rotate(&(*root)->Left);
    return LL_Rotate(root);
}
void RL_Rotate(AVLTree *root) {
    LL_Rotate(&(*root)->Right);
    RR_Rotate(root);
}

小结:几个子树在水平位置上顺序是不会变的!根节点和根节点的子树在水平上的逻辑位置也是不会变的。


  3.2 平衡二叉树的插入

  插入算法就是出现不平衡状态时,判断需要使用哪种旋转方式来使得二叉树保持平衡:

AVLTree InsertAVLTree(AVLTree root, int x) {
    if (root == NULL) {
        root = new AVLTreeNode;
        root->Left = NULL;
        root->Right = NULL;
        root->data = x;
        return root;
    }
    if (x > root->data) {
            root->Right = InsertAVLTree(root->Right, x);
            //递归返回插入位置的父节点或者祖父……,如果失去了平衡
            ) {
                //如果插入的值大于,当前节点的左孩子节点,说明该节点是插在root的右子树上的
                if (x > root->Left->data) RR_Rotate(&root);
                else RL_Rotate(&root);
            }
    }

    else if (x < root->data) {
        root->Left = InsertAVLTree(root->Left, x);
        ) {
            if (x < root->Left->data) LL_Rotate(&root);
            else LR_Rotate(&root);
        }
    }
    else {
        cout << "the number is already included." << endl;
        return NULL;
    }
    return root;
}

 3.3 平衡二叉树的删除

   之前写过二叉排序树的节点的删除的话,这里会好写很多,就是多出来一个判断从哪个子树删除节点的问题。

void AVLTreeDel(AVLTree *root, int data)
{
    if (!*root) {
        cout << "delete failed" << endl;
        return;
    }
    AVLTreeNode *p = *root;
    if (data == p->data) {
        //左右子树都非空
        if (p->Left && p->Right) {
            //在高度更大的那个子树上进行删除操作
            //进左子树,右转到底,进右子树,左转到底,转弯碰壁,杀孩子。
            if (height(p->Left) > height(p->Right)) {
                AVLTreeNode *pre=NULL,*q = p->Left;
                if (!q->Right)
                    q->Right = p->Right;
                else {
                    while (q->Right) {
                        pre = q;
                        q = q->Right;
                    }
                    pre->Right = q->Left;
                    q->Left = p->Left;
                    q->Right = p->Right;
                }
                *root = q;
            }
            else {
                AVLTreeNode *pre = NULL, *q = p->Right;
                if (!q->Left)
                    q->Left = p->Left;
                else {
                    while (q->Left) {
                        pre = q;
                        q = q->Left;
                    }
                    pre->Left = q->Right;
                    q->Left = p->Left;
                    q->Right = p->Right;
                }
                *root=q;
            }
        }
        else
            (*root) = (*root)->Left ? (*root)->Left : (*root)->Right;
        delete p;
    }
    else if (data < p->data){//要删除的节点在左子树中
        //在左子树中进行递归删除
        AVLTreeDel(&(*root)->Left, data);
        //判断是否仍然满足平衡条件
        ){
            //如果当前节点右孩子的左子树更高
            if (height(p->Right->Left) > height(p->Right->Right))
                RL_Rotate(root);
            else
                RR_Rotate(root);
        }
    }
    else{
        AVLTreeDel(&(*root)->Right, data);
        ) {
            if (height((*root)->Left->Left) > height((*root)->Left->Right))
                LL_Rotate(root);
            else
                LR_Rotate(root);
        }
    }
}

https://www.2cto.com/kf/201702/556250.html

完整代码(2019.1.20):

#pragma once
#include "top.h"

typedef BTreeNode AVLTreeNode, *AVLTree;

void RR_Rotate(AVLTree *root){
    AVLTreeNode* Right = (*root)->Right;
    (*root)->Right = Right->Left;
    Right->Left = *root;
    *root = Right;
}

void LL_Rotate(AVLTree *root) {
    AVLTreeNode* Left = (*root)->Left;
    (*root)->Left = Left->Right;
    Left->Right = *root;
    *root = Left;
}
void LR_Rotate(AVLTree *root) {
    RR_Rotate(&(*root)->Left);
    return LL_Rotate(root);
}
void RL_Rotate(AVLTree *root) {
    LL_Rotate(&(*root)->Right);
    RR_Rotate(root);
}
AVLTree AVLTreeInsert(AVLTree root, int x) {
    if (root == NULL) {
        root = new AVLTreeNode;
        root->Left = NULL;
        root->Right = NULL;
        root->data = x;
        return root;
    }
    if (x > root->data) {
            root->Right = AVLTreeInsert(root->Right, x);
            //递归返回插入位置的父节点或者祖父……,如果失去了平衡
            ) {
            //如果插入的值大于,当前节点的右孩子节点,说明该节点是插在root的右子树上的
                //if (x > root->Left->data) RR_Rotate(&root);不能保证该节点一定有左子树
                if (x > root->Right->data)RR_Rotate(&root);
                else RL_Rotate(&root);
            }
    }
    else if (x < root->data) {
        root->Left = AVLTreeInsert(root->Left, x);
        ) {
            if (x < root->Left->data) LL_Rotate(&root);
            else LR_Rotate(&root);
        }
    }
    else {
        cout << "the number is already included." << endl;
        return NULL;
    }
    return root;
}

AVLTree AVLTreeCreat(int *a, int length) {
    AVLTree T = NULL;
    ; i < length; i++) {
        T = AVLTreeInsert(T, a[i]);
    }
    return T;
}
AVLTreeNode* AVLFind(AVLTree T, int x) {
    AVLTreeNode *p = T;
    while (p) {
        if (x == p->data) break;
        p = x > p->data ? p->Right : p->Left;
    }
    return p;
}

AVLTree AVLMax(AVLTree p)
{
    if (!p) return NULL;
    if (p->Right == NULL)
        return p;
    return AVLMax(p->Right);
}

AVLTree AVLMin(AVLTree p)
{
    if (!p)
        return NULL;
    if (p->Left == NULL)
        return p;
    return AVLMin(p->Left);
}

void AVLTreeDel(AVLTree *root, int data)
{
    if (!*root) {
        cout << "delete failed" << endl;
        return;
    }
    AVLTreeNode *p = *root;
    if (data == p->data) {
        //左右子树都非空
        if (p->Left && p->Right) {
            //在高度更大的那个子树上进行删除操作
            //进左子树,右转到底,进右子树,左转到底,转弯碰壁,杀孩子。
            if (height(p->Left) > height(p->Right)) {
                AVLTreeNode *pre=NULL,*q = p->Left;
                if (!q->Right)
                    q->Right = p->Right;
                else {
                    while (q->Right) {
                        pre = q;
                        q = q->Right;
                    }
                    pre->Right = q->Left;
                    q->Left = p->Left;
                    q->Right = p->Right;
                }
                *root = q;
            }
            else {
                AVLTreeNode *pre = NULL, *q = p->Right;
                if (!q->Left)
                    q->Left = p->Left;
                else {
                    while (q->Left) {
                        pre = q;
                        q = q->Left;
                    }
                    pre->Left = q->Right;
                    q->Left = p->Left;
                    q->Right = p->Right;
                }
                *root=q;
            }
        }
        else
            (*root) = (*root)->Left ? (*root)->Left : (*root)->Right;
        delete p;
    }
    else if (data < p->data){//要删除的节点在左子树中
        //在左子树中进行递归删除
        AVLTreeDel(&(*root)->Left, data);
        //判断是否仍然满足平衡条件
        ){
            //如果当前节点右孩子的左子树更高
            if (height(p->Right->Left) > height(p->Right->Right))
                RL_Rotate(root);
            else
                RR_Rotate(root);
        }
    }
    else{
        AVLTreeDel(&(*root)->Right, data);
        ) {
            if (height((*root)->Left->Left) > height((*root)->Left->Right))
                LL_Rotate(root);
            else
                LR_Rotate(root);
        }
    }
}

void checkCreat() {
    ;
    );

    ; i < length; i++) {
        cout << a[i] << ",";
    }

    cout << endl;
    AVLTree T = AVLTreeCreat(a, length);
    int t = rand() % length;
    AVLTreeDel(&T, a[t]);
    ; i++) {
        a[i] = a[i + ];
    }

    Preorder(T);
    cout << endl;
    Inorder(T);
    cout << endl;
    Postorder(T);
    cout << endl;
    free(a);
}

数据结构——平衡二叉树(AVLTree)的更多相关文章

  1. 什么是泛型?,Set集合,TreeSet集合自然排序和比较器排序,数据结构-二叉树,数据结构-平衡二叉树

    ==知识点== 1.泛型 2.Set集合 3.TreeSet 4.数据结构-二叉树 5.数据结构-平衡二叉树 ==用到的单词== 1.element[ˈelɪmənt] 要素 元素(软) 2.key[ ...

  2. 数据结构-平衡二叉树 旋转过程平衡因子分析 c和java代码实现对比

    平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且 ...

  3. java——平衡二叉树 AVLTree、AVLMap、AVLSet

    平衡二叉树:对于任意一个节点,左子树和右子树的高度差不能超过1 package Date_pacage; import java.util.ArrayList; public class AVLTre ...

  4. 平衡二叉树(AVLTREE,双链表实现)

    首先说下好久没更新了,最近打游戏和工作都有点多,o(^▽^)o. 写这个AVL发现自己的代码风格好差,尤其是变量命名这块,后来意识到了,想去改,但是太多了,改了几个就不想改了,做这个是记录下自己的成长 ...

  5. Java数据结构——平衡二叉树的平衡因子(转自牛客网)

    若向平衡二叉树中插入一个新结点后破坏了平衡二叉树的平衡性.首先要找出插入新结点后失去平衡的最小子树根结点的指针.然后再调整这个子树中有关结点之间的链接关系,使之成为新的平衡子树.当失去平衡的最小子树被 ...

  6. 大话数据结构—平衡二叉树(AVL树)

    平衡二叉树(Self-Balancing Binary Search Tree/Height-Balanced Binary Search Tree),是一种二叉排序树,当中每个节点的左子树和右子树的 ...

  7. 数据结构-平衡二叉树Java实现

    1,Node.java package com.cnblogs.mufasa.BalanceBinaryTree; public class Node { Node parent; Node left ...

  8. JavaScript数据结构——树的实现

    在计算机科学中,树是一种十分重要的数据结构.树被描述为一种分层数据抽象模型,常用来描述数据间的层级关系和组织结构.树也是一种非顺序的数据结构.下图展示了树的定义: 在介绍如何用JavaScript实现 ...

  9. 20162325 金立清 S2 W8 C17

    20162325 2017-2018-2 <程序设计与数据结构>第8周学习总结 教材学习内容概要 二叉查找树是一棵二叉树,对于其中的每个结点,左子树上的元素小于父结点的值,而右子树上的元素 ...

随机推荐

  1. Rest架构下的增删改查

    首先还是要连接一下什么是Rest, REST是英文representational state transfer(表象性状态转变)或者表述性状态转移;Rest是web服务的一种架构风格;使用HTTP, ...

  2. [javaSE] 网络编程(TCP-并发上传图片)

    客户端: 1.服务端点 2.读取客户端已有的图片数据 3.通过socket输出流将数据发给服务端 4.读取服务端反馈信息 5.关闭 获取Socket对象,new出来,构造参数:String的服务端ip ...

  3. Spring系列之——使用模板快速搭建springboot项目

    1 在官网https://start.spring.io/生成spring boot的模板 2 IDEA导入模板,设置如下勾选项,其他选项卡为默认值 3 idea呈现 4 新增controller类 ...

  4. docker login 报错 Error response from daemon: Get https://registry-1.docker.io/v2/: unauthorized: incorrect username or password

    按照网上说的说法,造成这个现象有很多原因,大家可以多尝试一下,下面贴出解决我问题的方法: docker账户分为两个部分,一个是email,一个是dockerID,使用docker login登陆时要使 ...

  5. Oracle数据库采用数据泵方式导入导出数据

    特别说明:Oralce的数据泵导入导出技术只能用在数据库服务器上,在只有客户端的机器上是无法使用数据泵技术的. 1.创建备份文件目录  mkdir d:\dmp 2.在Oralce中注册该目录,将目录 ...

  6. js中作用域链和作用域

    作用域 在JavaScript中,我们可以将作用域定义为一套规则,这套规则用来管理引擎如何在当前作用域以及嵌套的子作用域中根据标识符名称(变量名或者函数名)进行变量查找. 经过研究<高级程序设计 ...

  7. 001profile条件化创建bean

    01.类级别条件创建 @Configuration @Profile("dev") public class Aclass{}---->影响整个类,包括类的注解.开发环境,类 ...

  8. 使用PuTTy在CentOS下安装web.py与简单的文件传输

    两周前,出于帮朋友忙的目的,尝试了一下微信公众号的菜单自定义与自动回复功能的实现,成了. 两周后,需要将代码转移至朋友新购的服务器上,发现基本操作全忘记了,麻瓜!所以记一笔,希望也能对大家也有帮助. ...

  9. Grunt入门学习之(1) -- 环境安装

    Grunt入门学习(1) - 环境安装 这周根据项目需要,在项目的基础上分模块开发了一个小的项目板块,但是在规范组织每个模块的代码和其依赖性时比较麻烦,需要一个项目板块的构建工具.各个模块都包括其对应 ...

  10. Python爬虫教程-06-爬虫实现百度翻译(requests)

    使用python爬虫实现百度翻译(requests) python爬虫 上一篇介绍了怎么使用浏览器的[开发者工具]获取请求的[地址.状态.参数]以及使用python爬虫实现百度翻译功能[urllib] ...