樹論之二叉搜索樹

二叉搜索樹

二叉查找樹(Binary Search Tree),(又:二叉搜索樹,二叉排序樹)它或者是一棵空樹,或者是具有下列性質的二叉樹: 若它的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值; 若它的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值; 它的左、右子樹也分別爲二叉排序樹。

二叉搜索樹操作

  • 因爲二叉樹搜索樹的特點,我們插入一個元素必然需要從根節點開始查找整個樹,直到找到準確的位置
  • 二叉搜索樹查詢很快logn
  • 二叉搜索樹的刪除
  1. 如果要刪除的節點是葉子節點 直接刪除,父節點對應子樹設爲null
  2. 如果要刪除的節點只有一個子樹,父節點指向當前節點的子樹。
  3. 如果要刪除的節點有2個子樹,則先找到當前節點的後繼節點,把後繼節點的值賦值給當前節點。刪除後繼節點,因爲後繼節點肯定不會有2個子樹。

代碼再現

public class MyBinarySeachTree {

	private TreeNode root;
	
	static class TreeNode {
		private TreeNode left;//左節點
		private TreeNode right;//右節點
		private TreeNode parent;//父節點
		private int data;//數據值
		private boolean position = false;//表示左邊
		public TreeNode(int data) {
			this.data = data;
		}
	}
	
	public MyBinarySeachTree(int data) {
		root = new TreeNode(data); 
	}
	
	/**
	 * 正常插入法
	 * @param data
	 */
	public void insert(int data) {
		TreeNode node = new TreeNode(data);
		TreeNode pa = root.right;
		if( node.data >= root.data) {
			pa = root.right;
		}else{
			pa = root.left;
		}
		while( true ) {
			if( pa == null && node.data >= root.data  ) {
				root.right = node;
				node.parent = root;
				node.position = true;
				break;
			}else if(pa == null && node.data < root.data) {
				root.left = node;
				node.parent = root;
				break;
			}
			if( node.data >= pa.data){
				if( pa.right != null) {
					pa = pa.right;
					continue;
				}
				pa.right = node;
				node.parent = pa;
				node.position = true;
				break;
			}else if(node.data < pa.data ){
				if( pa.left != null) {
					pa = pa.left;
					continue;
				}
				pa.left = node;
				node.parent = pa;
				break;
			} 
		}
		
	}
	
	/**
	 * 遞歸插入法
	 * @param root
	 * @param data
	 */
	public void insert(TreeNode root , int data) {
		if( data > root.data) {
			if(root.right ==null) {
				TreeNode node = new TreeNode(data);
				root.right = node;
				node.parent = root;
				node.position = true;
				return;
			}
			insert(root.right, data);
		}else {
			if(root.left ==null) {
				TreeNode node = new TreeNode(data);
				root.left = node;
				node.parent = root;
				return;
			}
			insert(root.left, data);
		}
	}
	
	public TreeNode search(TreeNode root , int data) {
		if(root == null) {
			System.out.println("沒有找到");
			return null;
		}
		if( data > root.data) {
			return search(root.right, data);
		}else if(data < root.data ) {
			return search(root.left, data);
		}else{
			System.out.println("找到節點了");
			return root; 
		}
	}
	
	private TreeNode findNextNode(TreeNode node) {
		TreeNode parent = node;
		while(parent.left != null) {
			parent = parent.left;
		}
		return parent;
	}
	
	/**
	 *        9
	 *    7       11
	 *  5   8   10     16(X)
	 *2   6         12    24
	 *                 19    26
	 *                    20    28
	 * 
	 * 1.要刪除的結點是葉子結點 O(1)
     * 2.要刪除的結點只有一個子樹(左或者右)O(1)
     * 3.要刪除的結點有兩顆子樹:找後繼結點,而且後繼結點的左子樹一定爲空。
	 * 
	 * 
	 * @param data
	 */
	public void remove(int data) {
		TreeNode node = search(root, data);
		remove(node);
	}
	
	private void remove(TreeNode node) {
		if( node !=null ) {
			 //先判斷是否存在左右子樹
			if(node.left ==null || node.right == null) {
				if(node.left != null && node.position==false) node.parent.left = node.left;//要刪除節點的左子樹不爲空,並且當前節點是父節點的左子樹
				else if(node.left != null && node.position==true) node.parent.right = node.left;//要刪除節點的左子樹不爲空,並且當前節點是父節點的右子樹
				else if(node.right != null && node.position==false) node.parent.left = node.right;//要刪除節點的右子樹不爲空,並且當前節點是父節點的左子樹
				else if(node.right != null && node.position==true) node.parent.right = node.right;//要刪除節點的右子樹不爲空,並且當前節點是父節點的右子樹
				else if(node.position==false) node.parent.left = null; //當前節點是父節點的左子樹
				else node.parent.right = null; //當前節點是父節點的右子樹
				//移除當前節點
				node = null;
			}else{//查找當前節點的後繼節點
				TreeNode treeNode = findNextNode(node.right);
				node.data = treeNode.data;
				remove(treeNode);
			}
		}
	}
	
	public void print() {
		show(root);
		System.out.println("");
	}
	
	private void show(TreeNode node) {
		if(node == null) {
			return;
		}
		show(node.left);
		System.out.print(node.data+ " ");
		show(node.right);
	}
	
	public static void main(String[] args) {
		int data[] = {9,7,11,5,8,10,16,2,6,12,24,19,26,20,28};
		MyBinarySeachTree root = new MyBinarySeachTree(data[0]);	//第一個點作爲跟結點
		for(int i = 1 ; i < data.length ; i ++) {
			//root.insert(root, data[i]);
			root.insert(data[i]);
		}
		root.print();
		root.remove(16);
		System.out.println("刪除節點:"+16);
		root.print();
	}
	
}
發佈了42 篇原創文章 · 獲贊 6 · 訪問量 6402
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章