1. 程式人生 > >Java實現二叉排序樹的插入、查詢、刪除

Java實現二叉排序樹的插入、查詢、刪除

import java.util.Random;

/**
 * 二叉排序樹(又稱二叉查詢樹)
 * (1)可以是一顆空樹
 * (2)若左子樹不空,則左子樹上所有的結點的值均小於她的根節點的值
 * (3)若右子樹不空,則右子樹上所有的結點的值均大於她的根節點的值
 * (4)左、右子樹也分別為二叉排序樹
 * 
 * 
 * 效能分析:
 * 查詢效能:
 * 		含有n個結點的二叉排序樹的平均查詢長度和樹的形態有關,
 * 		(最壞情況)當先後插入的關鍵字有序時,構成的二叉排序樹蛻變為單枝樹。查詢效能為O(n)
 * 		(最好情況)二叉排序樹的形態和折半查詢的判定樹相同,其平均查詢長度和log2(n)成正比
 * 
 * 
 * 插入、刪除效能:
 * 		插入、刪除操作間複雜度都O(log(n))級的,
 * 		即經過O(log(n))時間搜尋到了需插入刪除節點位置和刪除節點的位置
 * 		經O(1)級的時間直接插入和刪除
 * 		與順序表相比,比序順序表插入刪除O(n)(查詢時間O(log(n))移動節點時間O(n))要快
 * 		與無序順序表插入時間O(1),刪除時間O(n)相比,因為是有序的,所查詢速度要快很多
 * 
 * 
 * 
 * 作者:小菜鳥
 * 建立時間:2014-08-17
 * 
 */

public class BinarySortTree {

	private Node root = null;

	
	/**查詢二叉排序樹中是否有key值*/
	public boolean searchBST(int key){
		Node current = root;
		while(current != null){
			if(key == current.getValue())
				return true;
			else if(key < current.getValue())
				current = current.getLeft();
			else
				current = current.getRight();
		}
		return false;
	}
	
	
	/**向二叉排序樹中插入結點*/
	public void insertBST(int key){
		Node p = root;
		/**記錄查詢結點的前一個結點*/
		Node prev = null;
		/**一直查詢下去,直到到達滿足條件的結點位置*/
		while(p != null){
			prev = p;
			if(key < p.getValue())
				p = p.getLeft();
			else if(key > p.getValue())
				p = p.getRight();
			else
				return;
		}
		/**prve是要安放結點的父節點,根據結點值得大小,放在相應的位置*/
		if(root == null)
			root = new Node(key);
		else if(key < prev.getValue())
			prev.setLeft(new Node(key));
		else prev.setRight(new Node(key));
	}
	
	
	
	/**
	 * 刪除二叉排序樹中的結點
	 * 分為三種情況:(刪除結點為*p ,其父結點為*f)
	 * (1)要刪除的*p結點是葉子結點,只需要修改它的雙親結點的指標為空
	 * (2)若*p只有左子樹或者只有右子樹,直接讓左子樹/右子樹代替*p
	 * (3)若*p既有左子樹,又有右子樹
	 * 		用p左子樹中最大的那個值(即最右端S)代替P,刪除s,重接其左子樹
	 * */
	public void deleteBST(int key){
		deleteBST(root, key);
	}
	private boolean deleteBST(Node node, int key) {
		if(node == null) return false;
		else{
			if(key == node.getValue()){
				return delete(node);
			}
			else if(key < node.getValue()){
				return deleteBST(node.getLeft(), key);
			}
			else{
				return deleteBST(node.getRight(), key);
			}
		}
	}

	private boolean delete(Node node) {
		Node temp = null;
		/**右子樹空,只需要重接它的左子樹
		 * 如果是葉子結點,在這裡也把葉子結點刪除了
		 * */
		if(node.getRight() == null){
			temp = node;
			node = node.getLeft();
		}
		/**左子樹空, 重接它的右子樹*/
		else if(node.getLeft() == null){
			temp = node;
			node = node.getRight();
		}
		/**左右子樹均不為空*/
		else{
			temp = node;
			Node s = node;
			/**轉向左子樹,然後向右走到“盡頭”*/
			s = s.getLeft();
			while(s.getRight() != null){
				temp = s;
				s = s.getRight();
			}
			node.setValue(s.getValue());
			if(temp != node){
				temp.setRight(s.getLeft());
			}
			else{
				temp.setLeft(s.getLeft());
			}
		}
		return true;
	}

	
	/**中序非遞迴遍歷二叉樹
	 * 獲得有序序列
	 * */
	public void nrInOrderTraverse(){
		Stack<Node> stack = new Stack<Node>();
		Node node = root;
		while(node != null || !stack.isEmpty()){
			while(node != null){
				stack.push(node);
				node = node.getLeft();
			}
			node = stack.pop();
			System.out.println(node.getValue());
			node = node.getRight();
		}
	}
	
	public static void main(String[] args){
		BinarySortTree bst = new BinarySortTree();
		/**構建的二叉樹沒有相同元素*/
		int[] num = {4,7,2,1,10,6,9,3,8,11,2, 0, -2};
		for(int i = 0; i < num.length; i++){
			bst.insertBST(num[i]);
		}
		bst.nrInOrderTraverse();
		System.out.println(bst.searchBST(10));
		bst.deleteBST(2);
		bst.nrInOrderTraverse();
	}
	
	
	/**二叉樹的結點定義*/
	public class Node{
		private int value;
		private Node left;
		private Node right;
		
		public Node(){
		}
		public Node(Node left, Node right, int value){
			this.left = left;
			this.right = right;
			this.value = value;
		}
		public Node(int value){
			this(null, null, value);
		}
		
		public Node getLeft(){
			return this.left;
		}
		public void setLeft(Node left){
			this.left = left;
		}
		public Node getRight(){
			return this.right;
		}
		public void setRight(Node right){
			this.right = right;
		}
		public int getValue(){
			return this.value;
		}
		public void setValue(int value){
			this.value = value;
		}
	}
	
}