算法与数据结构【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;
	}
	
}
发布了86 篇原创文章 · 获赞 56 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/WilliamCode/article/details/104302337