定义:

通常高度平衡树用符号HB(k)表示,其中k为左子树和右子树的高度差,k叫做平衡因子
在HB(k)中,如果k = 1,那么这样的二叉搜索树叫做AVL树,即一棵AVL树是带有平衡条件的二叉搜索树;左子树和右子树的高度差最多不能超过1。

1.AVL树的性质

一棵二叉树为AVL树,当且仅当满足如下条件:

  • 它是一棵二叉搜索树
  • 对任意结点X,其左子树的高度与其右子树的高度的差最多不超过1。

2.AVL树的作用

对于一般的二叉搜索树,其期望高度(即为一棵平衡树时)为log2n,其各操作的时间复杂度O(log2n)同时也由此而决定。但是,在某些极端的情况下(如在插入的序列是有序的时),二叉搜索树将退化成近似链或链,此时,其操作的时间复杂度将退化成线性的,即O(n)。我们可以通过随机化建立二叉搜索树来尽量的避免这种情况,但是在进行了多次的操作之后,由于在删除时,我们总是选择将待删除节点的后继代替它本身,这样就会造成总是右边的节点数目减少,以至于树向左偏沉。这同时也会造成树的平衡性受到破坏,提高它的操作的时间复杂度。

3. 旋转

如果在AVL树中进行插入或删除节点后,可能导致AVL树失去平衡。这种失去平衡的可以概括为4种姿态:LL(左左),LR(左右),RR(右右)和RL(右左)。下面给出它们的示意图:

【数据结构】AVL树

上图中的4棵树都是"失去平衡的AVL树",从左往右的情况依次是:LL、LR、RL、RR。除了上面的情况之外,还有其它的失去平衡的AVL树,如下图:

【数据结构】AVL树

上面的两张图都是为了便于理解,而列举的关于"失去平衡的AVL树"的例子。总的来说,AVL树失去平衡时的情况一定是LL、LR、RL、RR这4种之一,它们都有各自的定义:

(1)LL:LeftLeft,也称为"左左"。插入或删除一个节点后,根节点的左子树的左子树还有非空子节点,导致"根的左子树的高度"比"根的右子树的高度"大2,导致AVL树失去了平衡。
例如,在上面LL情况中,由于"根节点(8)的左子树(4)的左子树(2)还有非空子节点",而"根节点(8)的右子树(12)没有子节点";导致"根节点(8)的左子树(4)高度"比"根节点(8)的右子树(12)“高2。
(2)LR:LeftRight,也称为"左右”。插入或删除一个节点后,根节点的左子树的右子树还有非空子节点,导致"根的左子树的高度"比"根的右子树的高度"大2,导致AVL树失去了平衡。
例如,在上面LR情况中,由于"根节点(8)的左子树(4)的左子树(6)还有非空子节点",而"根节点(8)的右子树(12)没有子节点";导致"根节点(8)的左子树(4)高度"比"根节点(8)的右子树(12)“高2。
(3)RL:RightLeft,称为"右左”。插入或删除一个节点后,根节点的右子树的左子树还有非空子节点,导致"根的右子树的高度"比"根的左子树的高度"大2,导致AVL树失去了平衡。
例如,在上面RL情况中,由于"根节点(8)的右子树(12)的左子树(10)还有非空子节点",而"根节点(8)的左子树(4)没有子节点";导致"根节点(8)的右子树(12)高度"比"根节点(8)的左子树(4)“高2。
(4) RR:RightRight,称为"右右”。插入或删除一个节点后,根节点的右子树的右子树还有非空子节点,导致"根的右子树的高度"比"根的左子树的高度"大2,导致AVL树失去了平衡。
例如,在上面RR情况中,由于"根节点(8)的右子树(12)的右子树(14)还有非空子节点",而"根节点(8)的左子树(4)没有子节点";导致"根节点(8)的右子树(12)高度"比"根节点(8)的左子树(4)"高2。
如果在AVL树中进行插入或删除节点后,可能导致AVL树失去平衡。AVL失去平衡之后,可以通过旋转使其恢复平衡,下面分别介绍"LL(左左),LR(左右),RR(右右)和RL(右左)"这4种情况对应的旋转方法。

4.Java版本实现

package tree;

public class AVLTree<T> {
	class Node<T>{
		private Node<T>  left = null;
		private Node<T>  right = null;
		private T data;
		private int hight;
		
		public Node(T d) {
			data = d;
			hight = 1;
		}

		public Node<T> getLeft() {
			return left;
		}

		public void setLeft(Node<T>  left) {
			this.left = left;
		}

		public Node<T>  getRight() {
			return right;
		}

		public void setRight(Node<T>  right) {
			this.right = right;
		}

		public T getData() {
			return data;
		}

		public void setData(T data) {
			this.data = data;
		}

		public int getHight() {
			return hight;
		}

		public void setHight(int hight) {
			this.hight = hight;
		}
	}
	private Node<T> root;
	
	public AVLTree(T value) {
		root = new Node<T>(value);
	}
	
	//RR型旋转
	Node<T> RRRoation(Node<T> k1) {
		Node<T> k2;
		k2 = k1.getRight();
		k1.setRight(k2.getLeft());
		k2.setLeft(k1);
		return k2;
	}
	
	//LL型旋转
	Node<T> LLRoation(Node<T> k2){
		Node<T> k1;
		k1 = k2.getLeft();
		k2.setLeft(k1.getRight());
		k1.setRight(k2);
		return k1;
	}
	
	//RL型旋转
	Node<T> RLRoation(Node<T> k3){
		k3.setRight(LLRoation(k3.getRight()));
		return RRRoation(k3);
	}
	
	//LR型旋转
	Node<T> LRRoation(Node<T> k4){
		k4.setLeft(RRRoation(k4.getLeft()));
		return LLRoation(k4);
	}
	
	//获取树的深度
	int getDepth(Node<T> root , int initDeep){
		if(root == null)
			return initDeep;
		int leftDeep = initDeep;
		int rightDeep = initDeep;
		if(root.getLeft() != null)
			leftDeep = getDepth(root.getLeft() , initDeep++);
		if(root.getRight() != null)
			rightDeep = getDepth(root.getRight(), initDeep++);
		
		return leftDeep > rightDeep ? leftDeep : rightDeep; 
	}
	
	//判断树是否失去平衡
	boolean unBanlace(Node<T> root) {
		if(root == null)
			return false;
		int leftHeight = getDepth(root.getLeft(), 1);
		int rightHeight = getDepth(root.getRight(), 1);
		return Math.abs(leftHeight - rightHeight) > 1;
	}
	
	
	//插入操作的入口
	public void insert(T value) {
		insert(root, value);
	}
	
	//插入操作的递归实现
	private Node<T> insert(Node<T> root , T value) {
		if(root == null) {
			root = new Node<T>(value);
			return root;
		}
			
		if((int)value < (int)root.getData()) {//插入左子树
			root.setLeft(insert(root.getLeft() , value));
			if(unBanlace(root)) {
				if((int)value < (int)root.getLeft().getData()) {
					//LL型旋转
					root = LLRoation(root);
				}else {
					//LR型旋转
					root = LRRoation(root);
				}
			}
		}else if((int)value > (int)root.getData()){//插入右子树
			root.setRight(insert(root.getRight() , value));
			if(unBanlace(root)) {
				if((int)value > (int)root.getRight().getData()) {
					//RR型旋转
					root = RRRoation(root);
				}else {
					//RL型旋转
					root = RLRoation(root);
				}
			}
		}else {
			throw new RuntimeException("duplicate value: " + value);
		}
		return root;
	}
	
	//删除结点的入口
	public Node<T> remove(T value){
		return remove(root , value);
	}
	
	//删除结点的递归实现
	private Node<T> remove(Node<T> root , T value){
		if(root == null)
			return null;
		if((int)value < (int)root.getData() ) {
			//欲删除结点在左子树
			root.setLeft(remove(root.getLeft() , value));
		}else if((int)value > (int)root.getData() ) {
			//欲删除结点在右子树
			root.setRight(remove(root.getRight() , value));
		}else if(root.getData() == value){
			//欲删除结点是根结点本身
			//左子树和右子树同时存在
			if(root.getLeft() != null && root.getRight() != null) {
				//左子树比右子树高
				if(getDepth(root.getLeft(), 1) > getDepth(root.getRight(), 1)) {
					Node<T> max = getMax(root.getLeft());
					root.setData(max.getData());
					root.setLeft(remove(root.getLeft(),max.getData()));
					
				}else {
					//左子树不高于右子树
					Node<T> min = getMin(root.getRight());
					root.setData(min.getData());
					root.setRight(remove(root.getRight(),min.getData()));
				}
			}else {
				//左子树和右子树不同时存在
				root = root.getLeft() == null ? root.getRight() : root.getLeft();
			}
		}else {
			System.out.println("no node matched value: " + value);
		}
		return root;
	}
	
	//获取最大结点
	Node<T> getMax(Node<T> root){
		if(root == null)
			return null;
		if(root.getRight() != null) {
			return getMax(root.getRight());
		}else {
			return root;
		}
	}
	
	//获取最小结点
	Node<T> getMin(Node<T> root){
		if(root == null)
			return null;
		if(root.getLeft() != null) {
			return getMin(root.getLeft());
		}else {
			return root;
		}
			
	}

	//先序遍历
	private  void inOrder(Node<T> root) {
		if(root != null) {
			
			inOrder(root.getLeft());
			System.out.print(root.getData() + "->");
			inOrder(root.getRight());
		}
		
	}
	public static void main(String[] args) {
		AVLTree<Integer> avlTree =  new AVLTree<>(3);
		int arr[]= {2,1,4,5,6,7,16,15,14,13,12,11,10,8,9};
		for (int a : arr) {
			avlTree.insert(a);	
		}
		
		avlTree.inOrder(avlTree.root);
		avlTree.remove(3);
		System.out.println();
		avlTree.inOrder(avlTree.root);
	}

}
	

相关文章: