JAVA数据结构--AVL树的实现

AVL树的定义

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

节点的平衡因子是它的左子树的高度减去它的右子树的高度(有时相反)。带有平衡因子1、0或 -1的节点被认为是平衡的。带有平衡因子 -2或2的节点被认为是不平衡的,并需要重新平衡这个树。平衡因子可以直接存储在每个节点中,或从可能存储在节点中的子树高度计算出来。

  上图是摘自维基百科的AVL树实现的图例,比较清晰的解释了AVL调整平衡的过程。ABCD代表当前节点有子树。

  我以我个人理解以左右情况为例

  该例是左右情况,需要将其调整为左左或者右右才能继续调整。因为节点5是在右,所以3节点(虚线方框内)调整为左为最佳。左旋转即可使树变为左左形状。

AVL树节点定义

 1 private static class AvlNode<T>{
 2         public AvlNode(T theElement) {
 3             this(theElement, null, null);
 4         }
 5         public AvlNode(T theElement,AvlNode<T> lt,AvlNode<T> rt) {
 6             element=theElement;
 7             left=lt;
 8             right=rt;
 9             height=0;
10         }
11         T element;
12         AvlNode<T> left;
13         AvlNode<T> right;
14         int height;
15     }

与二叉查找树的定义类似,不过加入了节点的深度height定义。

AVL节点计算方法

1 private int height(AvlNode<T> t) {
2         return t==null?-1:t.height;
3 }

当banlance()或者旋转时height都会改变

节点旋转

 1 /*
 2      * 实现单旋转
 3      * */
 4     private AvlNode<T> rotateWithLeftChild(AvlNode<T> k2){//单左旋转
 5         AvlNode<T> k1=k2.left;
 6         k2.left=k1.right;
 7         k1.right=k2;
 8         k2.height=Math.max(height(k2.left), height(k2.right))+1;
 9         k1.height=Math.max(height(k1.left), k2.height)+1;
10         return k1;
11     }
12     private AvlNode<T> rotateWithRightChild(AvlNode<T> k1){//单右旋转
13         AvlNode<T> k2=k1.right;
14         k1.right=k2.left;
15         k2.left=k1;
16         k2.height=Math.max(height(k1.left), height(k1.right))+1;
17         k1.height=Math.max(height(k2.right), k1.height)+1;
18         return k2;
19     }
20     /*
21      * 实现双旋转
22      *
23      * */
24     private AvlNode<T> doubleWithLeftChild(AvlNode<T> k3){//先右旋转再左旋转
25         k3.left=rotateWithRightChild(k3.left);
26         return rotateWithLeftChild(k3);
27     }
28      private AvlNode<T> doubleWithRightChild( AvlNode<T> k1 ){//先左旋转再右旋转
29          k1.right = rotateWithLeftChild( k1.right );
30          return rotateWithRightChild( k1 );
31     }

balance()方法的实现

 1 private AvlNode<T> balance(AvlNode<T> t){
 2         if(t==null)
 3             return t;
 4         if(height(t.left)-height(t.right)>ALLOWED_IMBALANCE) {//左子树高度过高
 5             if(height(t.left.left)>=height(t.left.right))//判断进行单旋转还是双旋转
 6                 t=rotateWithLeftChild(t);
 7             else
 8                 t=doubleWithLeftChild(t);
 9         }
10         else if (height(t.right)-height(t.left)>ALLOWED_IMBALANCE) {//右子树高度过高
11             if(height(t.right.right)>=height(t.right.left))
12
13
14
15                 t=rotateWithRightChild(t);
16             else
17                 t=doubleWithRightChild(t);
18         }
19         t.height=Math.max(height(t.left), height(t.right))+1;
20         return t;
21     }

删除节点方法

 1 private AvlNode<T> remove(T x,AvlNode<T> t){
 2          if(t==null)
 3              return t;
 4          int compareResult=x.compareTo(t.element);
 5          if(compareResult<0)
 6              t.left=remove(x, t.left);//递归查找删除
 7          else if (compareResult>0) {
 8             t.right=remove(x, t.right);
 9         }
10          else if (t.left!=null&&t.right!=null) {//要删除的节点两个孩子节点的情况
11              t.element=findMin(t.right).element;//从右子树中找出最小的节点替换当前要删除的节点
12              t.right=remove(t.element, t.right);//删除右子树中需要拿出替换的节点
13         }
14          else {
15             t=(t.left!=null)?t.left:t.right;//单个子节点的情况
16         }
17          return balance(t);
18      }

完整代码如下(不含遍历),github地址

  1 package Tree;
  2 public class AvlTree <T extends Comparable<? super T>>{
  3     private static class AvlNode<T>{
  4         public AvlNode(T theElement) {
  5             this(theElement, null, null);
  6         }
  7         public AvlNode(T theElement,AvlNode<T> lt,AvlNode<T> rt) {
  8             element=theElement;
  9             left=lt;
 10             right=rt;
 11             height=0;
 12         }
 13         T element;
 14         AvlNode<T> left;
 15         AvlNode<T> right;
 16         int height;
 17     }
 18     private AvlNode<T> root;//定义根节点
 19     public AvlTree() {
 20         root=null;
 21     }
 22     public int height() {
 23         return height(root);
 24     }
 25     public void insert(T x) {
 26         insert(x, root);
 27     }
 28     public void remove(T x) {
 29         root=remove(x,root);
 30     }
 31     private int height(AvlNode<T> t) {
 32         return t==null?-1:t.height;
 33     }
 34     private AvlNode<T> insert(T x,AvlNode<T> t){
 35         if(t==null)
 36             return new AvlNode<T>(x, null, null);
 37         int compareResult=x.compareTo(t.element);
 38         if(compareResult<0) {
 39             t.left=insert(x, t.left);
 40         }
 41         else if(compareResult>0){
 42             t.right=insert(x, t.right);
 43         }
 44         else {
 45
 46         }
 47         return balance(t);
 48
 49     }
 50     private AvlNode<T> balance(AvlNode<T> t){
 51         if(t==null)
 52             return t;
 53         if(height(t.left)-height(t.right)>ALLOWED_IMBALANCE) {//左子树高度过高
 54             if(height(t.left.left)>=height(t.left.right))//判断进行单旋转还是双旋转
 55                 t=rotateWithLeftChild(t);
 56             else
 57                 t=doubleWithLeftChild(t);
 58         }
 59         else if (height(t.right)-height(t.left)>ALLOWED_IMBALANCE) {//右子树高度过高
 60             if(height(t.right.right)>=height(t.right.left))
 61
 62
 63
 64                 t=rotateWithRightChild(t);
 65             else
 66                 t=doubleWithRightChild(t);
 67         }
 68         t.height=Math.max(height(t.left), height(t.right))+1;
 69         return t;
 70     }
 71     /*
 72      * 实现单旋转
 73      * */
 74     private AvlNode<T> rotateWithLeftChild(AvlNode<T> k2){//单左旋转
 75         AvlNode<T> k1=k2.left;
 76         k2.left=k1.right;
 77         k1.right=k2;
 78         k2.height=Math.max(height(k2.left), height(k2.right))+1;
 79         k1.height=Math.max(height(k1.left), k2.height)+1;
 80         return k1;
 81     }
 82     private AvlNode<T> rotateWithRightChild(AvlNode<T> k1){//单右旋转
 83         AvlNode<T> k2=k1.right;
 84         k1.right=k2.left;
 85         k2.left=k1;
 86         k2.height=Math.max(height(k1.left), height(k1.right))+1;
 87         k1.height=Math.max(height(k2.right), k1.height)+1;
 88         return k2;
 89     }
 90     /*
 91      * 实现双旋转
 92      *
 93      * */
 94     private AvlNode<T> doubleWithLeftChild(AvlNode<T> k3){//先右旋转再左旋转
 95         k3.left=rotateWithRightChild(k3.left);
 96         return rotateWithLeftChild(k3);
 97     }
 98      private AvlNode<T> doubleWithRightChild( AvlNode<T> k1 ){//先左旋转再右旋转
 99          k1.right = rotateWithLeftChild( k1.right );
100          return rotateWithRightChild( k1 );
101     }
102      private AvlNode<T> remove(T x,AvlNode<T> t){
103          if(t==null)
104              return t;
105          int compareResult=x.compareTo(t.element);
106          if(compareResult<0)
107              t.left=remove(x, t.left);//递归查找删除
108          else if (compareResult>0) {
109             t.right=remove(x, t.right);
110         }
111          else if (t.left!=null&&t.right!=null) {//要删除的节点两个孩子节点的情况
112              t.element=findMin(t.right).element;//从右子树中找出最小的节点替换当前要删除的节点
113              t.right=remove(t.element, t.right);//删除右子树中需要拿出替换的节点
114         }
115          else {
116             t=(t.left!=null)?t.left:t.right;//单个子节点的情况
117         }
118          return balance(t);
119      }
120      private AvlNode<T> findMin(AvlNode<T> t){
121             //非递归写法
122             if(t!=null)
123                 while(t.left!=null)
124                     t=t.left;
125             return t;
126             //递归写法
127             /*if(t==null)
128                 return null;
129             else if (t.left==null) {
130                 return t;
131             }
132             return findMin(t.left);*/
133         }
134     private static final int ALLOWED_IMBALANCE=1;
135
136 }

时间: 2024-10-12 04:50:02

JAVA数据结构--AVL树的实现的相关文章

数据结构--AVL树的insert()的Java实现

一个AVL树是其每个节点的左子树和右子树的高度差最多差1的二叉查找树:AVL树是一种最古老的平衡查找树 上代码: package com.itany.avlshu; public class AVLTree<T extends Comparable<?super T>> { private static class AvlNode<T> { private int height; private T element; private AvlNode<T> l

Java数据结构之树和二叉树

从这里开始将要进行Java数据结构的相关讲解,Are you ready?Let's go~~ Java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来的几章,我们将会分别讲解这几种数据结构,主要也是通过Java代码的方式来讲解相应的数据结构. 今天要讲解的是:Java线性结构 Java数据结构之树形结构 之前我们前几章学习的都是Java数据结构的线性结构,都是一对一的,从现在开始我们将要学习Java的树形结构. 树对于我们来普通Java程序员而言,

Java创建AVL树

AVL树是带有平衡条件的二叉查找树,其查找和删除的时间复杂度为logn,是对二叉查找树的改进,我们将节点的左子树和右子树深度之差称为平衡因子(BF),其中的每一个节点的平衡因子的绝对值不大于1. 距离插入节点最近的,并且平衡因子绝对值大于1的节点为根的子树,称为最小不平衡子树. 要实现AVL树,就必须保证在插入的时候消除不平衡的子树,即通过某种方式,使每次插入一个节点,都是平衡的BST树,下面我们讨论一下插入的时候四种情况: 1:对左孩子的左子树进行一次插入: 2:对左孩子的右子树进行一次插入:

数据结构--AVL树

AVL树是高度平衡的二叉搜索树,较搜索树而言降低了树的高度:时间复杂度减少了使其搜索起来更方便: 1.性质: (1)左子树和右子树高度之差绝对值不超过1: (2)树中每个左子树和右子树都必须为AVL树: (3)每一个节点都有一个平衡因子(-1,0,1:右子树-左子树) (4)遍历一个二叉搜索树可以得到一个递增的有序序列 2.结构: 平衡二叉树是对二叉搜索树(又称为二叉排序树)的一种改进.二叉搜索树有一个缺点就是,树的结构是无法预料的.任意性非常大.它仅仅与节点的值和插入的顺序有关系.往往得到的是

数据结构--Avl树的创建,插入的递归版本和非递归版本,删除等操作

AVL树本质上还是一棵二叉搜索树,它的特点是: 1.本身首先是一棵二叉搜索树. 2.带有平衡条件:每个结点的左右子树的高度之差的绝对值最多为1(空树的高度为-1). 也就是说,AVL树,本质上是带了平衡功能的二叉查找树(二叉排序树,二叉搜索树). 对Avl树进行相关的操作最重要的是要保持Avl树的平衡条件.即对Avl树进行相关的操作后,要进行相应的旋转操作来恢复Avl树的平衡条件. 对Avl树的插入和删除都可以用递归实现,文中也给出了插入的非递归版本,关键在于要用到栈. 代码如下: #inclu

简单数据结构———AVL树

C - 万恶的二叉树 Crawling in process... Crawling failed Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 2193 Description An AVL tree is a kind of balanced binary search tree. Named after their invento

数据结构&amp;&amp;AVL树原理、插入操作详解及实现

1.基本概念 AVL树的复杂程度真是比二叉搜索树高了整整一个数量级--它的原理并不难弄懂,但要把它用代码实现出来还真的有点费脑筋.下面我们来看看: 2.AVL树是什么? AVL树本质上还是一棵二叉搜索树(因此读者可以看到我后面的代码是继承自二叉搜索树的),它的特点是: 1. 本身首先是一棵二叉搜索树. 2. 带有平衡条件:每个结点的左右子树的高度之差的绝对值(平衡因子)最多为1. 例如: 5              5 / \            / \ 2   6          2  

[数据结构] AVL树和AVL旋转、哈夫曼树和哈夫曼编码

1. AVL树 AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树.查找.插入和删除在平均和最坏情况下都是O(log n).增加和删除可能需要通过一次或多次树旋转来重新平衡这个树. 节点的平衡因子是它的左子树的高度减去它的右子树的高度(有时相反).带有平衡因子1.0或 -1的节点被认为是平衡的.带有平衡因子 -2或2的节点被认为是不平衡的,并需要重新平衡这个树.平衡因子可以直接存储在每个节点中,或从可能存储在节点中的子树高度计算出来. 1.2AVL旋转 AVL树的基本操作一

再回首数据结构—AVL树(二)

前面主要介绍了AVL的基本概念与结构,下面开始详细介绍AVL的实现细节: AVL树实现的关键点 AVL树与二叉搜索树结构类似,但又有些细微的区别,从上面AVL树的介绍我们知道它需要维护其左右节点平衡,实现AVL树关键在于标注节点高度.计算平衡因子.维护左右子树平衡这三点,下面分别介绍: 标注节点高度 从上面AVL树的定义中我们知道AVL树其左右节点高度差不能超过一,所以我们需要标注出每个节点高度: 1.节点高度为最大的子节点高度加1,其中叶子节点高度为1: 2.1与4叶子节点高度为1,节点3高度