算法学习 - 平衡二叉查找树实现(AVL树)

平衡二叉查找树

平衡二叉查找树是很早出现的平衡树,因为所有子树的高度差不超过1,所以操作平均为O(logN)。

平衡二叉查找树和BS树很像,插入和删除操作也基本一样,但是每个节点多了一个高度的信息,在每次插入之后都要更新树的每个节点的高度,发现不平衡之后就要进行旋转。

单旋转

单旋转是碰到左左或者右右的情况下所使用的方法。

例如:


  3
         2
                1

这种情况就需要旋转,因为3是根节点,它的左子树高度为0,右子树高度为2,相差超过1了,所以要进行旋转,而这是右右的情况,所以是单旋转。


       2
      /      1   3

这样子旋转过后就可以了~

双旋转

双旋转也很简单,但代码操作会稍微麻烦一点:


  2
         4
    /
   3

遇到这种情况就是双旋转,因为3是在2 4之间的。

旋转过后:


  3
 / 2   4

这样子就可以了。。其实很多时候情况比这个复杂,但是本质都是这样子操作的。

实现代码:

//
//  AVL.h
//  AVL
//
//  Created by Alps on 14-8-7.
//  Copyright (c) 2014年 chen. All rights reserved.
//

#ifndef AVL_AVL_h
#define AVL_AVL_h

#define ElementType int

struct TreeNode;
typedef TreeNode* AVL;
typedef TreeNode* Position;

Position Find(ElementType key, AVL A);
Position FindMax(AVL A);
Position FindMin(AVL A);

AVL Insert(ElementType key, AVL A);
AVL Delete(ElementType key, AVL A);

struct TreeNode{
    ElementType element;
    AVL left;
    AVL right;
    int height;
};

#endif

上面的代码是AVL.h文件。

//
//  main.cpp
//  AVL
//
//  Created by Alps on 14-8-7.
//  Copyright (c) 2014年 chen. All rights reserved.
//

#include <iostream>
#include "AVL.h"

int Height(AVL A){//求节点高度
    if (A == NULL) {
        return -1;
    }else{
        return A->height;
    }
}
int MAX(int a, int b){//返回两数中的大数
    return a>b?a:b;
}

AVL SingleRotateWithRight(AVL A){//右单旋转
    AVL tmp = A->right;
    A->right = tmp->left;
    tmp->left = A;
    A->height = MAX(Height(A->left), Height(A->right))+1;
    tmp->height = MAX(Height(tmp->left), Height(tmp->right))+1;
    return tmp;
}

AVL DoubleRotateWithRight(AVL A){//右双旋转
    AVL tmp = A->right;
    AVL tmp1 = tmp->left;
    tmp->left = tmp1->right;
    A->right = tmp1->left;
    tmp1->right = tmp;
    tmp1->left = A;
    tmp->height = MAX(Height(tmp->left), Height(tmp->right))+1;
    A->height = MAX(Height(A->left), Height(A->right))+1;
    tmp1->height = MAX(Height(tmp1->left), Height(tmp1->right))+1;
    return tmp1;
}

AVL SingleRotateWithLeft(AVL A){//左单旋转
    AVL tmp = A->left;
    A->left = tmp->right;
    tmp->right = A;
    A->height = MAX(Height(A->left), Height(A->right))+1;
    tmp->height = MAX(Height(tmp->left), Height(tmp->right))+1;
    return tmp;
}

AVL DoubleRotateWithLeft(AVL A){//左双旋转
    AVL tmp = A->left;
    AVL tmp1 = tmp->right;
    tmp->right = tmp1->left;
    A->left = tmp1->right;
    tmp1->left = tmp;
    tmp1->right = A;
    tmp->height = MAX(Height(tmp->left), Height(tmp->right))+1;
    A->height = MAX(Height(A->left), Height(A->right))+1;
    tmp1->height = MAX(Height(tmp1->left), Height(tmp1->right))+1;
    return tmp1;
}

AVL Insert(ElementType key, AVL A){//插入元素
    if (A == NULL) {
        A = (AVL)malloc(sizeof(struct TreeNode));
        A->element = key;
        A->height = 0;
        A->right = NULL;
        A->left = NULL;
//        return A;
    }else{
        if (key > A->element) {//如果大于当前节点,向右子树插入
            A->right = Insert(key, A->right);
            if (Height(A->right) - Height(A->left) == 2) {
                if (key > A->right->element) {//如果插入到节点的右子树的右方,右单旋转
                    A = SingleRotateWithRight(A);
                }else{
                    A = DoubleRotateWithRight(A);//插入到当前节点右子树的左方,右双旋转
                }
            }

        }else
            if (key < A->element) {
               A->left = Insert(key, A->left);
                if (Height(A->left) - Height(A->right) == 2) {
                    if (key < A->left->element) {//左单旋转
                        A = SingleRotateWithLeft(A);
                    }else{
                        A = DoubleRotateWithLeft(A);
                    }
                }
            }
    }

    A->height = MAX(Height(A->left), Height(A->right))+1;
    return A;
}

Position FindMax(AVL A){//找到当前树的最大值
    AVL tmp = A;
    if (A == NULL) {
        return NULL;
    }else{
        while (tmp->right != NULL) {
            tmp = tmp->right;
        }
    }
    return tmp;
}

Position FindMin(AVL A){//找到当前树的最小值
    AVL tmp = A;
    if (A == NULL) {
        return NULL;
    }else{
        while (tmp->left != NULL) {
            tmp = tmp->left;
        }
    }
    return tmp;
}

Position Find(ElementType key,AVL A){//查找节点,返回节点指针
    AVL tmp = A;
    if (A == NULL) {
        return NULL;
    }else{
        while (tmp != NULL && tmp->element != key) {
            if (key > tmp->element) {
                tmp = tmp->right;
            }else{
                tmp = tmp->left;
            }
        }
    }
    return tmp;
}

AVL Delete(ElementType key, AVL A){//删除节点

    if (A == NULL || Find(key, A) == NULL) {
        return NULL;
    }else{

        if (key == A->element) {//如果找到了要删除的节点
            AVL tmp;
            if (A->left && A->right) {//如果要删除的节点有左右子树
                tmp = FindMin(A->left);//用当前节点左子树的最小值替换
                A->element = tmp->element;
                A->left = Delete(A->element, A->left);//删掉左子树最小值节点
            }else{
                tmp = A;
                if (A->left) {
                    A = A->left;//<span style="font-family: Arial, Helvetica, sans-serif;">如果只存在左子树,直接返回它的左子树节点</span>

                }else{
                    if (A->right) {
                        A = A->right; //<span style="font-family: Arial, Helvetica, sans-serif;">如果只存在右子树,直接返回它的右子树节点</span>

                    }else{
                        A = NULL;//删除的是叶子节点,直接赋值为NULL
                    }
                }
                free(tmp);
                tmp = NULL;
                return A;//返回删除后的节点
            }
        }else{
            if (key > A->element) {//如果大于,去右子树
                A->right = Delete(key, A->right);
                if (Height(A->left) - Height(A->right) == 2) {
                    if (A->left->right != NULL && (Height(A->left->right) > Height(A->left->left))) {//如果当前节点不平衡,且节点左孩子存在右孩子,双旋转
                        A = DoubleRotateWithLeft(A);
                    }else{
                        A = SingleRotateWithLeft(A);//否则单旋转
                    }
                }
//                A->height = MAX(Height(A->left), Height(A->right));
            }else{
                if (key < A->element) {
                    A->left = Delete(key, A->left);
                    if (Height(A->right) - Height(A->left) == 2) {
                        if (A->right->left != NULL && (Height(A->right->left) > Height(A->right->right))) {//
                            A = DoubleRotateWithRight(A);
                        }else{
                            A = SingleRotateWithRight(A);
                        }
                    }
//                    A->height = MAX(Height(A->left), Height(A->right));
                }
            }
        }
    }
    A->height = MAX(Height(A->left), Height(A->right))+1;
    return A;
}

int main(int argc, const char * argv[])
{
    AVL A = NULL;
    A = Insert(3, A);
    printf("%d %d\n",A->element,A->height);
    A = Insert(2, A);
    printf("%d %d\n",A->left->element,A->height);
    A = Insert(1, A);
    printf("%d %d\n",A->left->element,A->left->height);
    A = Insert(4, A);
    A = Insert(5, A);
    printf("%d %d\n",A->right->element,A->right->height);
    A = Insert(6, A);
    printf("%d %d\n",A->element,A->height);
    A = Insert(7, A);
    A = Insert(16, A);
    A = Insert(15, A);
    printf("%d %d\n",A->right->element,A->right->height);
    A = Insert(14, A);
    printf("%d %d\n",A->right->element,A->right->height);
    A = Delete(16, A);
    printf("%d %d\n",A->right->element,A->right->height);
    A = Delete(6, A);
    A = Delete(5, A);
    printf("%d %d\n",A->right->element,A->right->height);
    return 0;
}

算法学习 - 平衡二叉查找树实现(AVL树),布布扣,bubuko.com

时间: 2024-08-04 12:58:51

算法学习 - 平衡二叉查找树实现(AVL树)的相关文章

算法二叉搜索树之AVL树

最近学习了二叉搜索树中的AVL树,特在此写一篇博客小结. 1.引言 对于二叉搜索树而言,其插入查找删除等性能直接和树的高度有关,因此我们发明了平衡二叉搜索树.在计算机科学中,AVL树是最先发明的自平衡二叉搜索树.在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树.对于N个节点的AVL树,由于树高被限制为lgN,因此其插入查找删除操作耗时为O(lgN). 2.旋转 在讲解关键步骤插入与删除以前,首先我们先定义一些辅助用的操作:旋转.旋转分为左旋和右旋,其示意图如下: 相信上

数据结构-自平衡二叉查找树(AVL)详解

介绍: 在计算机科学中,AVL树是最先发明的自平衡二叉查找树. 在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树. 查找.插入和删除在平均和最坏情况下都是O(log n).增加和删除可能需要通过一次或多次树旋转来重新平衡这个树.AVL树得名于它的发明者 G.M. Adelson-Velsky 和 E.M. Landis,他们在 1962 年的论文 "An algorithm for the organization of information" 中发表了它.

ACM学习历程—51NOD 1412 AVL树的种类(递推)

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1770 这是这次BSG白山极客挑战赛的B题.设p(i, j)表示节点个数为i,高度为j的AVL树的个数. 那么,对于1 <= k <= i-1 p[i][j] += p[k][j-1]*p[i-1-k][j-1]%MOD; p[i][j] += p[k][j-2]*p[i-1-k][j-1]%MOD; p[i][j] += p[k][j-1]*p[i-1-k][j-2]

二叉查找树之AVL树

AVL树插入数据的四种结构: 第一种: 第二种: 第三种: 第四种: 原文地址:https://www.cnblogs.com/blentle/p/8289203.html

二叉查找树【AVL树】

数据结构课:二叉树上机实验.为了保证树的平衡性,使用AVL平衡树. #include <stdio.h> #include <string.h> #include <stdlib.h> struct AvlNode; typedef struct AvlNode *Position; typedef struct AvlNode *AvlTree; AvlTree MakeEmpty(AvlTree T); Position Find(int x, AvlTree T)

【算法学习笔记】57. 前缀树 字典序优化技巧 STL学习 SJTU OJ 1366 前缀匹配

Description 给出一个总字符个数大小不超过1,000,000的字典(这个字典的单词顺序不为字典序)和不超过1000个长度不超过1000的前缀,输出字典中匹配该前缀,字典序为K_i的单词在字典中的位置. 所有单词都为小写字母. Input Format 第一行: 两个整数N,M,分别表示字典中的单词个数和需要查询的前缀数. 接下来N行:每行一个字符串,表示字典中的单词. 接下来M行,每行一个K_i, P_i, P_i表示查询的前缀,K_i表示满足这个前缀在字典序中的位置. Output

AVL树-自平衡二叉查找树(Java实现)

在计算机科学中,AVL树是最先发明的自平衡二叉查找树.AVL树得名于它的发明者 G.M. Adelson-Velsky 和 E.M. Landis,他们在 1962 年的论文 "An algorithm for the organization of information" 中发表了它. 一.AVL树的旋转规律 AVL树的基本操作一般涉及运做同在不平衡的二叉查找树所运做的同样的算法.但是要进行预先或随后做一次或多次所谓的"AVL旋转". 假设由于在二叉排序树上插入

AVL树(平衡二叉查找树)

首先要说AVL树,我们就必须先说二叉查找树,先介绍二叉查找树的一些特性,然后我们再来说平衡树的一些特性,结合这些特性,然后来介绍AVL树. 一.二叉查找树 1.二叉树查找树的相关特征定义 二叉树查找树,又叫二叉搜索树,是一种有顺序有规律的树结构.它可以有以下几个特征来定义它: (1)首先它是一个二叉树,具备二叉树的所有特性,他可以有左右子节点(左右孩子),可以进行插入,删除,遍历等操作: (2)如果根节点有左子树,则左子树上的所有节点的值均小于根节点上的值,如果根节点有右子树,则有字数上的所有节

自平衡二叉(查找树/搜索树/排序树) binary search tree

在计算机科学中,AVL树是最先发明的自平衡二叉查找树.AVL树得名于它的发明者 G.M. Adelson-Velsky 和 E.M. Landis,他们在 1962 年的论文 "An algorithm for the organization of information" 中发表了它. 一.AVL树的旋转规律 AVL树的基本操作一般涉及运做同在不平衡的二叉查找树所运做的同样的算法.但是要进行预先或随后做一次或多次所谓的"AVL旋转". 假设由于在二叉排序树上插入