算法與數據結構【Java實現】:二叉查找樹

        鏈表能夠很方便的存儲數據,但是,數據的組織只能是線性的,不能有層次的組織數據,且查找元素需要線性查找,複雜度O(n)。

        二叉查找樹是一種按照排序組織數據的有層次的方式

它的特點是:

(1)若左子樹不空,則左子樹上所有結點的值均小於它的根結點的值;

(2)若右子樹不空,則右子樹上所有結點的值均大於它的根結點的值;

即:對於任何一個子樹,左子樹所有結點值小於根結點,右子樹所有結點值小於根結點。

查找、插入刪除的最優複雜度爲log(n)

在極端情況下,如果按照排序好的順序給二叉查找樹數據,那麼樹會退化成一個鏈表,複雜的同鏈表一樣。

那麼:

在隨機情況下,二叉查找樹的查找效率有多高呢?

測試代碼:

BST tree = new BST();
		
		Random rand = new Random();
		double totalTime = 0;
		for (int i=0;i<=3000000; i++)
			tree.Insert(rand.nextInt(10000000));
		//tree.tranformIntoPerfectTree();
		for (int i=0;i<100;i++) {
			long time = System.currentTimeMillis();
			tree.Contains(new BSTNode(rand.nextInt(10000000)));
			totalTime += System.currentTimeMillis()-time;	
		}
		System.out.println("在1000萬數據中查找1000次 平均耗時: "+totalTime/100);

測試結果:

隨機生成300萬個數據(太多內存受不了),加入二叉查找樹,測試100次,平均時長爲:67.63ms

爲了提高查找效率,我們希望二叉樹儘可能像一個完全二叉樹

即整個樹只有最下面兩層不滿,其他層均滿。

爲此,人們提出了兩種算法

(1)DSW

當存入一定數據之後,按照一定規則將二叉查找樹拉伸成鏈表,然後重新組織數據,使數據接近完全二叉樹。以下代碼使用這種方法重建二叉搜索樹。因爲這種方法是所有數據一起重建一棵樹,所以又叫“全局重建”

(2)AVL

存入一個數據之後,該數據並非影響整棵樹的平衡,因爲數據總是插在最下方。所以可以只進行局部調整。

這種方法又叫“局部重建”(這個方法將在下一篇博文實現)

來看看:

平衡之後的二叉查找樹的效率

測試代碼及測試條件同上,加入了平衡函數tranformIntoPerfectTree()

改變不大,這是因爲我們隨機生成數據,如果數據有一定規律,那麼效率會提高很多。

 

對於二叉查找樹,有如下:

屬性:

root:樹的根,作爲樹的入口

size:數的大小,不必要,可以使用時遍歷求得

方法:

Insert:插入

remove:刪除,並返回被刪除的數據

isEmpty:判斷樹是否爲空

Contains:是否包含某數據

rotateRight/rotateLeft:將樹進行旋轉,這是DSW方法中使用的子方法

transformIntoBackbone:DSW方法的第一步,把樹轉化成鏈表

tranformIntoPerfectTree:使用DSW方法全局重構二叉樹

dfs:深度優先搜索,返回搜索路徑,二叉搜索樹的中序遍歷是數據的排序,使用遞歸,消耗資源

bfs:廣度優先遍歷,使用內存較大

 

下面是二叉查找樹的代碼:

package BST;

import java.util.ArrayList;
import java.util.Random;

public class BST {
	int size;
	BSTNode root;
	
	public BST() {
		root = null;
		size = 0;
	}
	public boolean isEmpty() {
		return root == null;
	}
	public void Insert(int value) {
		Insert(new BSTNode(value));
	}
	
	public boolean Contains(BSTNode node) {
		return Contains(node, root);
	}
	
	public boolean Remove(BSTNode node) {
		BSTNode[] fatherNode = new BSTNode[1];
		BSTNode toDelete = Search(node, fatherNode);		
		if (toDelete == null)
			return false;
		if (toDelete.left == null && toDelete.right == null)
			return false;
		
		if (toDelete.left == null && toDelete.right != null) {
			fatherNode[0].right = toDelete.right;
		}
		else if (toDelete.left != null && toDelete.right == null) {
			fatherNode[0].left = toDelete.left;
		}
		else if (toDelete.left != null && toDelete.right != null) {
			if(toDelete.right.right != null) {
				toDelete.right.right.left = toDelete.right.left;
				toDelete.right.left = toDelete.left;
			}
			else {
				if(toDelete.right.left != null)
					Insert(toDelete.right.left);
				toDelete.right.left = toDelete.left;
			}
			if(root != fatherNode[0])
				if (BSTNode.equals(fatherNode[0].right, toDelete))
					fatherNode[0].right = toDelete.right;
				else 
					fatherNode[0].left = toDelete.right;
			else {
				root = toDelete.right;
			}
		}
		size--;
		return true;
	}
	
	public void tranformIntoPerfectTree() {
		if (isEmpty() || size == 1) return ;
		transformIntoBackbone();	//轉化爲骨架結構(向右)
		//System.out.println("________________________________________");
		//printSelf();
		
		int n = this.size;
		int m = (int) Math.pow(2, Math.floor(Math.log10(n+1)/Math.log10(2))) - 1;
		int cnt = n-m;
		if(cnt>0) {
			rotateLeft(null, root);
			cnt--;
		}
		//System.out.println("m:"+m+" cnt: "+cnt);
		//printSelf();
		
		//System.exit(0);
		BSTNode grand = root;
		BSTNode now = root.right;
		if(cnt>0)
			while(true) {
				//System.out.println("___________In While_____________________________");
				//printSelf();
				rotateLeft(grand, now);
				//System.out.println("___________In While_____________________________");
				//printSelf();
				cnt--;
				if(cnt==0) break;
				grand = grand.right;
				now = grand.right;
			}
		
		while(m>1) {
			m=m/2;
			int tmp = m;
		
			if (tmp>=1) {
				rotateLeft(null, root);
				tmp--;
			}
			
			grand = root;
			now = root.right;
			//System.out.println("Pre Rotating: " + root.value + " " + root.right.value);
			while(tmp>0) {
				rotateLeft(grand, now);
				tmp--;
				if(tmp==0) break;
				grand = grand.right;
				now = grand.right;
			}
		}
		
	}
	
	public void transformIntoBackbone() {
		BSTNode grand = null;
		BSTNode now = root;
		while(now != null) {
			//System.out.println((grand==null?"null":grand.value) + " " + now.value);
			if (now.left != null) {
				rotateRight(grand, now);
				if(grand!=null)
					now = grand.right;
				else
					now = root;
				//System.out.println("exce 1");
				//System.out.println("___________In While_____________________________");
				//printSelf();
			}
			else {
				grand = now;
				now = now.right;
				//System.out.println("exce 2");
			}
		}
	}
	
	public void transformIntoBackboneLeft() {
		BSTNode grand = null;
		BSTNode now = root;
		while(now != null) {
			if (now.right != null) {
				rotateLeft(grand, now);
				if(grand!=null)
					now = grand.left;
				else
					now = root;
			}
			else {
				grand = now;
				now = now.left;
			}
			
		}
	}
	
	
	
	
	
	private void rotateRight(BSTNode grand, BSTNode node) {
		if (node.left == null) return ;
		BSTNode nodeLeft = node.left,
				nodeRight = node.right,
				child = node.left,
				childLeft = node.left.left,
				chileRight = node.left.right;
		node.left = chileRight;
		child.right = node;
		if(grand == null) {
			root = child;
		}
		else {
			grand.right = child;
		}
	}

	
	private void rotateLeft(BSTNode grand, BSTNode node) {
		if (node == null || node.right == null) return ;
		BSTNode nodeLeft = node.left,
				nodeRight = node.right,
				child = node.right,
				childLeft = node.right.left,
				chileRight = node.right.right;
		node.right = childLeft;
		child.left = node;
		if(grand == null) {
			root = child;
		}
		else {
			grand.right = child;
		}
	}
	
	private BSTNode Search(BSTNode node, BSTNode[] fatherNode) {
		if(isEmpty()) 
			return null;
		fatherNode[0] = root;
		BSTNode search = root;
		while(true) {
			if(search == null) return null;
			if (BSTNode.equals(search, node)) {return search;}
			fatherNode[0] = search;			
			if (node.value < search.value)
				search = search.left;
			else
				search = search.right;
		}
	}
	
	private void Insert(BSTNode node) {
		//System.out.print("Value: " + node.value + " ");
		if (isEmpty()) {
			root = node;
			size = 1;
			return ;
		}
		BSTNode search = root;
		while(true) {
			//System.out.print("node value: "+ search.value + " ");
			if (node.value < search.value)
				if (search.left == null) {
					search.left = node;
					//System.out.println("add to left ");
					break;
				}
				else {
					search = search.left;
					//System.out.println("add to left ");
				}
			else 
				if (search.right == null) {
					search.right = node;
					//System.out.println("add to right ");
					break;
				}
				else {
					search = search.right;
					//System.out.println("add to right ");
				}
		}
		size++;
	}
	
	private boolean Contains(BSTNode targetNode, BSTNode nowNode) {
		if (isEmpty())
			return false;
		if (nowNode == null)
			return false;
		if (BSTNode.equals(targetNode, nowNode))
			return true;
		return Contains(targetNode, nowNode.left) || Contains(targetNode, nowNode.right);
	}
	
	public void dfs(int[] result, int[] cnt, BSTNode node) {
		if (isEmpty())
			return ;
		//System.out.println("To Node:" + node.value);
		if (node.left != null) {
			//System.out.print("L"+node.value+" ");
			dfs(result, cnt, node.left);
		}
		result[cnt[0]++] = node.value;
		
		if (node.right != null) {
			//System.out.print("R"+node.value+" ");
			dfs(result, cnt, node.right);
		}
		return ;
	}
	public void bfs(int[] result, int[] cnt) {
		if (isEmpty())
			return ;
		ArrayList<BSTNode> list = new ArrayList();
		list.add(root);
		while(!list.isEmpty()) {
			BSTNode now = list.remove(0);
			if (now.left != null)
				list.add(now.left);	
			if (now.right != null)
				list.add(now.right);
			result[cnt[0]++] = now.value;
		}
	}
	
	public void printSelf() {
		int[] result = new int[this.size];
		int[] cnt = new int[1];
		this.dfs(result, cnt, this.root);
		System.out.println("\nDFS: ");
		for(int i=0; i<result.length; i++)
			System.out.print(result[i] + " ");
		System.out.println(" Size: "+ this.size);
		
		cnt[0] = 0;
		result = new int[this.size];
		this.bfs(result, cnt);
		System.out.println("BFS: ");
		for(int i=0; i<result.length; i++)
			System.out.print(result[i] + " ");
		System.out.println();
	}
	
	static public void main(String[] argv) {
		BST tree = new BST();
		
		Random rand = new Random();
		double totalTime = 0;
		for (int i=0;i<=3000000; i++)
			tree.Insert(rand.nextInt(10000000));
		tree.tranformIntoPerfectTree();
		for (int i=0;i<100;i++) {
			long time = System.currentTimeMillis();
			tree.Contains(new BSTNode(rand.nextInt(10000000)));
			totalTime += System.currentTimeMillis()-time;	
		}
		System.out.println("在1000萬數據中查找1000次 平均耗時: "+totalTime/100);
		//tree.Insert(10);tree.Insert(5);tree.Insert(11);tree.Insert(6);tree.Insert(3);
		
		//tree.printSelf();
		
		//tree.Remove(new BSTNode(14));
		//tree.Remove(new BSTNode(10));
		//tree.printSelf();
		//tree.rotateRight(null, tree.root);
		
		//tree.transformIntoBackbone();
		//tree.printSelf();
		//tree.transformIntoBackboneLeft();
		//tree.printSelf();
		
		//tree.tranformIntoPerfectTree();
		//tree.printSelf();
	}
}


class BSTNode{
	public int value;
	public BSTNode left;
	public BSTNode right;
	
	static boolean equals(BSTNode a, BSTNode b) {
		if(a==b && b==null) return true;
		if(a==null || b==null) return false;
		return a.value == b.value;
	}
	
	public BSTNode(int value) {
		this.value = value;
	}
	public BSTNode(int value, BSTNode left, BSTNode right) {
		this.value = value;
		this.left = left;
		this.right = right;
	}
	
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章