用java實現一顆平衡二叉樹ADT
阿新 • • 發佈:2018-12-04
平衡二叉樹是一顆能夠確保能在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;
}
}