AVL樹的Java實現(遞歸方法)

       AVL樹是一種自平衡的二叉查找樹。首先它是一種二叉查找樹,滿足任意一個節點(葉子節點除外)的值大於它左子樹上任意一個節點,且小於它右子樹上任意一個節點。因爲二叉查找樹的深度可能爲O(N),這樣的效率較低,因此衍生出了AVL樹,它具有自平衡的效果,能保持樹的深度爲O(logN)。AVL樹滿足:任意一個節點它的左子樹的高度和右子樹的高度差不超過1。(假設葉子節點的高度爲0,null節點的高度爲-1)

      基於上述的理論完成程序的編寫,既然要保存每個節點的高度,Node節點就需要一個int類型的height變量。自己完成的是採用遞歸的方法,以後有時間完成非遞歸方法的實現。上代碼:

public class TreeTest
{
	public static void main(String[] args)
	{
		AVLTree<Integer> st=new AVLTree<Integer>();
		st.insert(15);
		st.insert(7);
		st.insert(5);
		st.insert(37);
		st.insert(70);
		System.out.println("插入節點:"+st);
		st.remove(7);
		st.remove(15);
		System.out.println("刪除節點:"+st);
	}
	
}

//AVL樹:每個節點的左子樹和右子樹的高度差最多爲1
class AVLTree<T extends Comparable<T>>
{
	private Node<T> root=null;
	
	public AVLTree()
	{	
	}
	public void insert(T t)
	{
		root=insert(t,root);
	}
	public void remove(T t)
	{
		root=remove(t,root);	
	}
	public T findMax()
	{
		if(root==null)     //如果還沒有元素則返回空
			return null;
		return findMax(root).element;
	}
	public T findMin()
	{
		if(root==null)		//如果還沒有元素則返回空
			return null;
		return findMin(root).element;
	}
	//先序遍歷
	public void printFirst()
	{
		System.out.print("先序遍歷:");
		printFirst(root);
		System.out.print("\n");
	}
	private void printFirst(Node<T> node)
	{
		if(node!=null)
		{
			System.out.print(node.element+" ");
			printFirst(node.left);
			printFirst(node.right);
		}
	}
	//中序遍歷
	public void printTree()
	{
		System.out.print("中序遍歷:");
		printTree(root);
		System.out.print("\n");
	}
	private void printTree(Node<T> node)
	{
		if(node!=null)
		{
			printTree(node.left);
			System.out.print(node.element+" ");
			printTree(node.right);
		}
	}
	//插入分爲4總情況,分爲兩組,這兩組鏡像對稱。返回之前要進行node的高度賦值
	private Node<T> insert(T t,Node<T> node)
	{
		if(node==null)
			return new Node<T>(t,null,null);
		int i=t.compareTo(node.element);
		if(i>0)
		{
			node.right=insert(t,node.right);
			
			int cha=height(node.left)-height(node.right);
			if(cha>1 | cha<-1)
			{
				if(t.compareTo(node.right.element)>0)
					node=singleRightChild(node);
				else
					node=doubleRightChild(node);
			}
		}
		else
		{
			if(i<0)
			{
				node.left=insert(t,node.left);
				int cha=height(node.left)-height(node.right);
				if(cha>1 | cha<-1)
				{
					if(t.compareTo(node.left.element)<0)
						node=singleLeftChild(node);
					else
						node=doubleLeftChild(node);
				}
			}
		}
		node.height=Math.max(height(node.left),height(node.right))+1;
		return node;
	}
//刪除節點方法:遞歸刪除(三種情況),再判斷node節點左右子節點的高度差,|差|>1則進行旋轉平衡,高度賦值
	private Node<T> remove(T t,Node<T> node)
	{
		if(node==null) 	
			return null;
		int i=t.compareTo(node.element);
		if(i==0)
		{
			if(node.right!=null && node.left!=null)
			{
				node.element=findMin(node.right).element;
				node.right=remove(node.element,node.right);
			}
			else
				node=(node.right==null)?node.left:node.right;
		}
		else if(i>0)
			node.right=remove(t,node.right);
		else
			node.left=remove(t,node.left);
		if(node!=null)	   							//如果該節點不爲空,則進行平衡的判別處理和高度的賦值
		{
			if(height(node.right)-height(node.left)>1)   	//進行右旋轉
			{
				if(height(node.right.right)>=height(node.right.left))   //進行單旋轉
					node=singleRightChild(node);
				else										//進行雙旋轉
					node=doubleRightChild(node);
			}
			else if(height(node.left)-height(node.right)>1)	//進行左旋轉
			{
				if(height(node.left.left)>=height(node.left.right))   //進行單旋轉
					node=singleLeftChild(node);
				else										//進行雙旋轉
					node=doubleLeftChild(node);
			}
			node.height=Math.max(height(node.right),height(node.left))+1;
		}
		return node;
	}
	private Node<T> singleRightChild(Node<T> node)
	{
		Node<T> n=node.right;
		node.right=n.left;
		n.left=node;
		node.height=Math.max(height(node.left),height(node.right))+1;
		n.height=Math.max(height(n.right),height(n.left))+1;
		return n;
	}
	private Node<T> singleLeftChild(Node<T> node)
	{
		Node<T> n=node.left;
		node.left=n.right;
		n.right=node;
		node.height=Math.max(height(node.left),height(node.right))+1;
		n.height=Math.max(height(n.right),height(n.left))+1;
		return n;
	}
	//一次雙旋轉=兩次單旋轉
	private Node<T> doubleRightChild(Node<T> node)
	{
		node.right=singleLeftChild(node.right);
		return singleRightChild(node);
	}
	private Node<T> doubleLeftChild(Node<T> node)
	{
		node.left=singleRightChild(node.left);
		return singleLeftChild(node);
	}
	//返回節點的高度,空節點爲-1。新建節點的高度爲0
	private int height(Node<T> node)
	{
		return (node==null)?-1:node.height;
	}
	//返回元素最小的節點
	private Node<T> findMin(Node<T> node)
	{
		if(node==null)
			return null;
		if(node.left==null)
			return node;
		return findMin(node.left);
	}
	//返回元素最大的節點
	private Node<T> findMax(Node<T> node)
	{
		if(node==null)
			return null;
		if(node.right==null)
			return node;
		return findMax(node.right);
	}
	//節點類,包含元素和高度信息
	private static class Node<T>
	{
		private T element;
		private int height;
		private Node<T> left;
		private Node<T> right;
		public Node(T element,Node<T> left,Node<T> right)
		{
			this.element=element;
			this.left=left;
			this.right=right;
			height=0;
		}
	}	
	@Override
	public String toString()
	{
		StringBuilder sb=new StringBuilder();
		sb.append("[");
		sb.append(print(root));
		sb.append("]");
		return sb.toString();
	}
	//遞歸輸出,中序遍歷
	private String print(Node<T> node)
	{
		if(node!=null)
		{
			StringBuilder sb=new StringBuilder();
			sb.append(print(node.left));
			if(node.left!=null)
				sb.append(",");
			sb.append(node.element);
			if(node.right!=null)
				sb.append(",");
			sb.append(print(node.right));
			return sb.toString();
		}
		return "";
	}
}
輸出結果:

發佈了26 篇原創文章 · 獲贊 5 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章