1. 程式人生 > >用java實現一顆平衡二叉樹ADT

用java實現一顆平衡二叉樹ADT

平衡二叉樹是一顆能夠確保能在O(lgn)漸進時間界進行查詢的樹。我編寫一個類來對平衡二叉樹進行操作,包括,新增元素,刪除元素,查詢元素等操作。我建議:對於資料結構,如果都能夠自己編寫一遍,不僅能夠摸清其中的奧妙,而且可以快速入手其他結構。

簡單實現程式碼如下:可以直接複製使用,或者轉為自己的jar檔案

package Com.Tree;

import java.util.Comparator;

/**
 * 注意:對於這個可變類,並未考慮執行緒安全的問題,也沒有定義成不可變的類。主要體現平衡二叉樹的實現方法。
 * 在這個類中,最關鍵的地方是平衡例程,即balance方法,而balance方法需要呼叫幾個輔助方法來幫助判斷和旋轉。
 * 其餘地方都與構建一顆二叉排序樹ADT一樣。
 * 搞幾個列子,balance()斷點一步步走一遍,摸清楚他的執行過程。
 * @author jane
 *
 * @param <T> 通用化處理,對於所有的可比較類(實現了comparable介面的類)都能進行排序。
 */
public class AVLSearchTree<T> {
	// declare the comparator
	private Comparator<? super T> cmp;

	private int myCompare(T lhs, T rhs) {
		if (cmp != null)
			return cmp.compare(lhs, rhs);
		else
			return ((Comparable) lhs).compareTo(rhs);

	}

	// the class of Node
	private static 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;
		}
	}

	// 封裝一顆二叉平衡樹,對於所有的例項域都要私有化。
	private AVLNode<T> root;

	// 外部訪問介面。
	public AVLSearchTree() {
		root = null;
	}

	public AVLSearchTree(Comparator<? super T> c) // 從外部注入比較器,預設從小到大
	{
		root = null;
		cmp = c;
	}

	public void makeEmpty() {
		root = null;
	}

	public boolean isEmpty() {
		return root == null;
	}

	// 是否包含
	public boolean contains(T x) {
		return contains(x, root);
	}

	// 找最小
	public T findMin() {
		if (isEmpty())
			throw new NullPointerException();
		return findMin(root).element;
	}

	public T findMax() {
		if (isEmpty())
			throw new NullPointerException();
		return findMax(root).element;
	}

	// 插入
	public void insert(T x) {
		root = insert(x, root);
	}

	// 刪除
	public void remove(T x) {
		root = remove(x, root);
	}

	/**
	 * 三種遍歷二叉樹的方式,
	 * 
	 * @param type:引數0為先序遍歷,引數1為中序遍歷,2為後序遍歷。預設為先序遍歷
	 */
	public void printTree(int type) {
		switch (type) {
		case 0:
			printFirstRoot(root);
			System.out.println();
			break;
		case 1:
			printMidRoot(root);
			System.out.println();
			break;
		case 2:
			printLastRoot(root);
			System.out.println();
		default:
			printFirstRoot(root);
			System.out.println();
			break;
		}
	}

	/**
	 * 內部實現,封裝在類中,不對外部開放
	 * 
	 * @param t
	 */
	private void printFirstRoot(AVLNode<T> t) {
		if (t == null)
			return;
		System.out.print(t.element + " ");
		printFirstRoot(t.left);
		printFirstRoot(t.right);
	}

	private void printLastRoot(AVLNode<T> t) {
		if (t == null)
			return;
		printLastRoot(t.left);
		printLastRoot(t.right);
		System.out.print(t.element + " ");
	}

	private void printMidRoot(AVLNode<T> t) {
		if (t == null)
			return;
		printMidRoot(t.left);
		System.out.print(t.element + " ");
		printMidRoot(t.right);

	}

	// find the designate value
	private boolean contains(T x, AVLNode<T> t) {
		if (t == null)
			return false;
		int compareResult = myCompare(x, t.element);

		if (compareResult < 0)
			return contains(x, t.left);
		else if (compareResult > 0)
			return contains(x, t.right);
		else
			return true;
	}

	/**
	 * 計算樹的高度,如果節點為空則返回-1
	 * 
	 * @param t
	 * @return
	 */
	private int height(AVLNode<T> t) {
		return t == null ? -1 : t.height;
	}

	// find minimum value of Tree
	private AVLNode<T> findMin(AVLNode<T> t) {
		if (t == null)
			return null;
		else if (t.left == null)
			return t;
		return findMin(t.left);
	}

	// find maximum value of Tree
	private AVLNode<T> findMax(AVLNode<T> t) {
		if (t == null)
			return null;
		else if (t.right == null)
			return t;
		return findMin(t.right);
	}

	// 左旋
	private AVLNode<T> rotateWithLeftChild(AVLNode<T> k2) {
		AVLNode<T> k1 = k2.left;
		k2.left = k1.right;
		k1.right = k2;
		k2.height = Math.max(height(k2.left), height(k2.right)) + 1;
		k1.height = Math.max(height(k1.left), height(k1.right)) + 1;
		return k1;
	}

	// 右旋
	private AVLNode<T> rotateWithRightChild(AVLNode<T> k2) {
		AVLNode<T> k1 = k2.right;
		k2.right = k1.left;
		k1.left = k2;
		k2.height = Math.max(height(k2.left), height(k2.right)) + 1;
		k1.height = Math.max(height(k1.left), height(k1.right)) + 1;
		return k1;
	}

	/**
	 * 雙旋轉
	 * 
	 * @param k3
	 * @return
	 */
	private AVLNode<T> doubleWithLeftChild(AVLNode<T> k3) {
		// 先將K3的左子樹右旋
		k3.left = rotateWithRightChild(k3.left);
		// 再將K3左旋
		return rotateWithLeftChild(k3);
	}

	private AVLNode<T> doubleWithRightChild(AVLNode<T> k3) {
		k3.right = rotateWithLeftChild(k3.right);
		return rotateWithRightChild(k3);
	}

	// 通過旋轉平衡二叉樹
	private AVLNode<T> balance(AVLNode<T> t) {
		if (t == null)
			return t;

		// 如果左子樹比又子樹高2 則不平衡,從而發生左旋,或者先右旋再左旋。
		if (height(t.left) - height(t.right) == 2)
			if (height(t.left.left) >= height(t.left.right)) // 如果是一條直線
				t = rotateWithLeftChild(t);
			else // 如果是一條左凸右凹的曲線,則先右旋再左旋。
				t = doubleWithLeftChild(t);
		else if (height(t.right) - height(t.left) == 2) // 瀵逛簬鍙寵竟楂樺害澶т簬宸﹁竟楂樺害鐨勬儏鍐�
			if (height(t.right.right) >= height(t.right.left))
				t = rotateWithRightChild(t);
			else
				t = doubleWithRightChild(t);

		// 發生旋轉後重新定義根節點的高度,左子樹的最大高度,或者右子樹的最大高度+1
		t.height = Math.max(height(t.left), height(t.right)) + 1;
		return t;
	}

	/**
	 * 插入的實現,正常二叉樹排序樹的插入即可,在返回前呼叫平衡例程 balance()平衡下二叉樹。
	 * 
	 * @param x
	 * @param t
	 * @return
	 */
	private AVLNode<T> insert(T x, AVLNode<T> t) {
		if (t == null)
			return new AVLNode<>(x);

		int compareResult = myCompare(x, t.element);
		if (compareResult < 0) {
			t.left = insert(x, t.left);
		} else if (compareResult > 0) {
			t.right = insert(x, t.right);
		}

		// AVLTree must balance the height after every insert

		// 在左子樹,或者右子樹插入一個節點後,會改變其高度,所以呼叫平衡例程進行處理
		return balance(t);
	}

	/**
	 * 刪除一個匹配的元素,需要從右子樹找一個最小的值節點替換此節點,然後遞迴刪除右子樹的此節點。
	 * 
	 * @param x
	 * @param t
	 * @return
	 */
	private AVLNode<T> remove(T x, AVLNode<T> t) {
		if (t == null)
			return t;

		int compareResult = myCompare(x, t.element);

		if (compareResult < 0) {
			t.left = remove(x, t.left);
		} else if (compareResult > 0) {
			t.right = remove(x, t.right);
		} else if (t.left != null && t.right != null) // if delete this node and
														// it has two child
		{
			t.element = findMin(t.right).element; // find minimun value of right
													// child tree
			t.right = remove(t.element, t.right);
		} else
			t = (t.left != null) ? t.left : t.right;

		return balance(t); // AVLTree must balance after each remove;
	}
}

下面附帶以下二叉排序樹的ADT實現:

package Com.Tree;
import java.util.Comparator;


public class BinarySearchTree<T>{
	//declare the comparator
	private Comparator<? super T> cmp;
	private int myCompare(T lhs, T rhs)
	{
		if(cmp!=null)
			return cmp.compare(lhs, rhs);
		else
			return ((Comparable) lhs).compareTo(rhs);
			
	}
	//the class of Node
	private static 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;}		
	}
	
	//out interface
	private AVLNode<T> root;
	
    public BinarySearchTree(){root =null;}
	public BinarySearchTree(Comparator<? super T> c) //鍙互浼犻�掕嚜瀹氫箟鐨勬瘮杈冨櫒
	{root =null; cmp=c;}
	
	public void makeEmpty()
	{root =null;}
	
	public boolean isEmpty()
	{return root == null;}
	
	public boolean contains(T x)
	{return contains(x,root);}
	
	public T findMin()
	{if(isEmpty()) throw new NullPointerException(); return findMin(root).element;}
	
	public T findMax()
	{if(isEmpty()) throw new NullPointerException(); return findMax(root).element;}
	
	public void insert(T x)
	{root=insert(x,root);}
	
	public void remove(T x)
	{root=remove(x,root);}
	
	public void printTree(int type)
	{
		switch (type) {
		case 0:
			printFirstRoot(root);
			System.out.println();
			break;
		case 1:
			printMidRoot(root);
			System.out.println();
			break;
		case 2:
			printLastRoot(root);
			System.out.println();
		default:
			printFirstRoot(root);
			System.out.println();
			break;
		}
	}
	
   //inner methods

	private void printFirstRoot(AVLNode<T> t)
	{
		if(t==null)
			return;
		System.out.print(t.element+" ");
		printFirstRoot(t.left);
		printFirstRoot(t.right);
	}
	
	private void printLastRoot(AVLNode<T> t)
	{
		if(t==null)
			return;
		printLastRoot(t.left);
		printLastRoot(t.right);
		System.out.print(t.element+" ");
	}
	
	private void printMidRoot(AVLNode<T> t)
	{
		if(t==null)
			return;
		printMidRoot(t.left);
		System.out.print(t.element+" ");
		printMidRoot(t.right);
		
	}
	//find the designate value
	private boolean contains(T x, AVLNode<T> t)
	{
		if(t==null)
			return false;	
		int compareResult= myCompare(x, t.element);
		
		if(compareResult<0)
			return contains(x,t.left);
		else if(compareResult>0)
			return contains(x,t.right);
		else
			return true;
	}
	//find minimum value of Tree
    private AVLNode<T> findMin(AVLNode<T> t)
    {
    	if(t==null)
    		 return null;
    	else if(t.left==null)
    		return t;
    	return findMin(t.left);
    }
    
    //find maximum value of Tree
    private AVLNode<T> findMax(AVLNode<T> t)
    {
    	if(t==null)
    		 return null;
    	else if(t.right==null)
    		return t;
    	return findMin(t.right);
    }
    
    // insert a value into tree. update root reference on each return;
    private AVLNode<T> insert(T x, AVLNode<T> t)
    {
    	if(t==null)
    		return new AVLNode<>(x);
    	
    	int compareResult=myCompare(x, t.element);	
    	if(compareResult<0)
    	{
    		t.left=insert(x, t.left);
    	}
    	else if(compareResult>0)
    	{ t.right=insert(x, t.right);}
    	return t;
    }
    
    //remove a value in binarySearchTree and then balance it to AVLTree
    private AVLNode<T> remove(T x, AVLNode<T> t)
    {
    	if(t==null)
    		return t;
    	
    	int compareResult=myCompare(x, t.element);
    	
    	if(compareResult<0)
    	{
    		t.left=remove(x, t.left);
    	}
    	else if(compareResult>0)
    	{
    		t.right=remove(x, t.right);
    	}
    	else if(t.left!=null && t.right!=null) //if delete this node and it has two child
    	{
    		t.element=findMin(t.right).element; //find minimun value of right child tree
    		t.right=remove(t.element, t.right);
    	}
    	else
    		t=(t.left!=null)?t.left:t.right;
    	return t;
    }
}