平衡二叉树(Balance Binary Tree) --AVL树

上一节介绍的二叉查找树的查找效率取决于二叉排序树的形态,而构造一棵形态均匀的二叉查找树与节点插入的次序有关,而插入的顺序往往是不可预测的。

(1)若将最大值或最小值首先插入,整个二叉查找树将没有左子树或右子树。

(2)在最坏情况下,插入的次序已经是有序的,此时二叉查找树将成为一棵斜树,此时就成了一个线性边,查找的效率骤然下降,时间复杂度边为O(n)

(3)所以二叉查找树的效率介于 O(logN)和O(n)之间。

基于上面的情况,这就需要我们找到一种动态平衡的方法,对于任意的插入序列都能构造一棵形态均匀、平衡的二叉查找树,这就是我们下面介绍的平衡二叉树

平衡二叉树性质: 

(1)根节点的左子树和右子树的深度最多相差1。   (2)根节点的左子树和右子树叶都是一棵平衡二叉树。

平衡因子: 每个结点的平衡因子是该结点的左子树与右子树的深度之差。

构造平衡二叉树的思想: 在构造二叉查找树的过程中,每当插入一个结点,首先检查插入后是否破坏了树的平衡性,若破坏对树进行调整,使插入后成为平衡二叉树。                                             《平衡二叉树(Balance Binary Tree) --AVL树》

下面,介绍一下平衡二叉树插入时就对树进行调整的4种情况:

(1)LL型

BL  、 BR  分别表示结点B 的左右子树,  AR  为结点A的右子树,且深度都是h。 将节点X 插到B 的左子树上,导致节点A 的平衡因子有1变为了2,A失去平衡。                                                    《平衡二叉树(Balance Binary Tree) --AVL树》

新插入的节点是插在结点A的左孩子的左子树上,属于LL型。根据扁担原理,将支撑结点由A 改为B,并进行顺时针旋转,旋转后,A和BR 发生冲突,采用旋转优先原则,将A结点作为B结点的右孩子,B结点的右孩子脱落下来成为A结点的左孩子。

(2)RR型

BL  、 BR  分别表示结点B 的左右子树, AR  为结点A的右子树,且深度都是h。 将节点X 插到B 的右子树上,导致节点A 的平衡因子有-1变为了-2,A失去平衡。                                          《平衡二叉树(Balance Binary Tree) --AVL树》 

新插入的节点是插在结点A的右孩子的右子树上,属于LL型。根据扁担原理,将支持节点右A 改为B,并进行逆时针旋转,旋转后,A和BL 发生冲突,采用旋转优先原则,将A结点作为B结点的左孩子,B结点的左孩子脱落下来成为A结点的右孩子。

(3)LR型

节点X插在根结点的左孩子的右子树上,使结点A的平衡因子有1变为了2,A结点失去平衡,这里属于LR型,需要旋转2次。

第一次旋转: 根结点不动,先调整结点A的左子树。将支撑节点由B调整为C,进行逆时针,此时B和C的左子树发生冲突,旋转优先,将B作为C的左孩子,C的左孩子脱落下来成为B的右孩子,此时C成为了A的左孩子。

                               《平衡二叉树(Balance Binary Tree) --AVL树》

第二次旋转: 调整不平衡因子。将支撑结点由A调整为C,相应的进行顺时针旋转。此时,A和C的右孩子冲突,将A作为C的右孩子,C的右孩子脱落下来成为A的左孩子。

(4)RL型

和LR型类似,也需要两次调整。节点X插在根结点的右孩子的左子树上,使结点A的平衡因子有-1变为了-2,A结点失去平衡,这里属于RL型,需要旋转2次

第一次旋转: 根结点不动,先调整结点A的右子树。将支撑节点由B调整为C,进行顺时针,

此时B和C的右子树发生冲突,旋转优先,将B作为C的右孩子,C的右孩子。

《平衡二叉树(Balance Binary Tree) --AVL树》

第二次旋转: 调整不平衡因子。将支撑结点由A调整为C,相应的进行逆时针旋转。

此时,A和C的左孩子冲突,将A作为C的左孩子,C的左孩子脱落下来成为A的右孩子。

通过上面的分析,我们已经明白了构建平衡二叉树的及基本过程及思路,这也是平衡二叉树的精华所在,无论插入的序列是怎么样,我们都能通过调整构建一棵平衡二叉树,保证二叉树中的每个节点的平衡因子都不会大于1,保证了树的深度达到最浅,从而比较的次数就会更少,时间复杂度就会降低,在平衡二叉树中查找的时间复杂度为O(logN)。比二叉查找树性能更加好。

                                  《平衡二叉树(Balance Binary Tree) --AVL树》

一个平衡二叉树的简单实现:

package org.TT.BalanceTree;

/**
 *  平衡二叉树简单实现  
 */
public class AvlTree<T extends Comparable<? super T>> {

	private AvlNode<T> root;// AVL树根

	/**
	 * 初始化为空树
	 */
	public AvlTree() {
		root = null;
	}

	/**
	 * 在AVL树中插入数据
	 */
	public void insert(T x) {
		root = insert(x, root);
	}

	/**
	 * 在AVL树中找最小的数据
	 */
	public T findMin() {
		if (isEmpty())
			System.out.println("树空");
		return findMin(root).element;
	}

	/**
	 * 在AVL树中找最大的数据
	 */
	public T findMax() {
		if (isEmpty())
			System.out.println("树空");
		return findMax(root).element;
	}

	/**
	 * 搜索,查找记录,找到返回 true 否则返回false
	 */
	public boolean find(T x) {
		return find(x, root);
	}
	
	/**
	 * 清空AVL 树
	 */
	public void clear() {
		root = null;
	}

	/**
	 * 判断是否为空
	 */
	public boolean isEmpty() {
		return root == null;
	}

	/**
	 * 排序输出AVL树, 采用中序输出
	 */
	public void printTree() {
		if (isEmpty())
			System.out.println("Empty tree");
		else
			printTree(root);
	}

	/**
	 * 以根节点开始,将新节点插入到合适的位置
	 */
	private AvlNode<T> insert(T x, AvlNode<T> root) {
		if (root == null)
			return new AvlNode<T>(x, null, null);

		int compareResult = x.compareTo(root.element);

		if (compareResult < 0) {
			root.left = insert(x, root.left);// 将x插入左子树中
			if (height(root.left) - height(root.right) == 2)// 打破平衡
				if (x.compareTo(root.left.element) < 0)// LL型(左左型)
					root = rotateWithLeftChild(root);
				else
					root = doubleWithLeftChild(root);	// LR型(左右型)
		} else if (compareResult > 0) {
			root.right = insert(x, root.right);// 将x插入右子树中
			if (height(root.right) - height(root.left) == 2)// 打破平衡
				if (x.compareTo(root.right.element) > 0)// RR型(右右型)
					root = rotateWithRightChild(root);
				else
					// RL型
					root = doubleWithRightChild(root);
		} else
			; // 重复数据,什么也不做
		root.height = Math.max(height(root.left), height(root.right)) + 1;// 更新高度
		return root;
	}

	/**
	 * 找最小值
	 */
	private AvlNode<T> findMin(AvlNode<T> n) {
		if (n == null)
			return n;
		while (n.left != null)
			n = n.left;
		return n;
	}

	/**
	 * 找最大值
	 */
	private AvlNode<T> findMax(AvlNode<T> n) {
		if (n == null)
			return n;
		while (n.right != null)
			n = n.right;
		return n;
	}

	/**
	 * 搜索(查找),以某个节点作为根开始查找
	 */
	@SuppressWarnings("unchecked")
	private boolean find(T x, AvlNode<?> root) {
		while (root != null) {
			int compareResult = x.compareTo((T) root.element);

			if (compareResult < 0)
				root = root.left;
			else if (compareResult > 0)
				root = root.right;
			else
				return true; //找到
		}
		return false; //未找到
	}

	/**
	 * 中序遍历AVL树
	 */
	private void printTree(AvlNode<T> n) {
		if (n != null) {
			printTree(n.left);
			System.out.print(n.element + "  ");
			printTree(n.right);
		}
	}

	/**
	 * 求AVL树的高度
	 */
	private int height(AvlNode<T> n) {
		return n == null ? -1 : n.height;
	}

	/**
	 * 带左子树旋转,适用于LL型
	 */
	private AvlNode<T> rotateWithLeftChild(AvlNode<T> n) {
		AvlNode<T> k = n.left;
		n.left = k.right;
		k.right = n;
		n.height = Math.max(height(n.left), height(n.right)) + 1;
		k.height = Math.max(height(k.left), n.height) + 1;
		return k;
	}

	/**
	 * 带右子树旋转,适用于RR型
	 */
	private AvlNode<T> rotateWithRightChild(AvlNode<T> n) {
		AvlNode<T> k = n.right;
		n.right = k.left;
		k.left = n;
		n.height = Math.max(height(n.left), height(n.right)) + 1;
		k.height = Math.max(height(k.right), n.height) + 1;
		return k;
	}

	/**
	 * 双旋转,适用于LR型
	 */
	private AvlNode<T> doubleWithLeftChild(AvlNode<T> n) {
		n.left = rotateWithRightChild(n.left);
		return rotateWithLeftChild(n);
	}

	/**
	 * 双旋转,适用于RL型
	 */
	private AvlNode<T> doubleWithRightChild(AvlNode<T> n) {
		n.right = rotateWithLeftChild(n.right);
		return rotateWithRightChild(n);
	}

	public static void main(String[] args) {
		AvlTree<Integer> t = new AvlTree<Integer>();

		int[] value = { 6, 1, 20, 7, 10, 8, 9, 3, 14, 5, 18};
		for (int v : value) {
			t.insert(v);
		}
		System.out.println("中序遍历: ");
		t.printTree();
		
		System.out.println();
		System.out.println("树的高度: " + t.height(t.root));
		
		System.out.println("最小值: " + t.findMin());
		System.out.println("最大值: " + t.findMax());
		System.out.println("查找“10”: " + t.find(10));
	}

}

结果:

《平衡二叉树(Balance Binary Tree) --AVL树》

AVL节点类: 

package org.TT.BalanceTree;

public class AvlNode<T> {

	T element; // 节点中的数据
	AvlNode<T> left; // 左孩子
	AvlNode<T> right; // 右孩子
	int height; // 节点的高度

	AvlNode(T theElement) {
		this(theElement, null, null);
	}

	AvlNode(T theElement, AvlNode<T> lt, AvlNode<T> rt) {
		element = theElement;
		left = lt;
		right = rt;
		height = 0;
	}

}

    原文作者:平衡二叉树
    原文地址: https://blog.csdn.net/tanjiquan/article/details/50685185
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞