1. 程式人生 > >Java實現二叉排序樹

Java實現二叉排序樹

定義:

二叉排序樹或者是一棵空樹,或者是具有下列性質的二叉樹: (1)若左子樹不空,則左子樹上所有結點的值均小於它的根結點的值; (2)若右子樹不空,則右子樹上所有結點的值均大於或等於它的根結點的值; (3)左、右子樹也分別為二叉排序樹; (4)沒有鍵值相等的節點。

說明:

可實現:構造樹,插入,查詢,刪除.

通過模式的選擇,可以插入值相等的點.但是不建議使用.

程式碼:

節點類Node:

package glut.bean;
public class Node {
	Node parent;
	Node leftChild;
	Node rightChild;
	int index;
	Number value;
	boolean isLeftChild;

	public Node() {
		// TODO Auto-generated constructor stub
	}

	public Node(Node parent, Node leftChild, Node rightChild, Number value) {
		this.parent = parent;
		this.leftChild = leftChild;
		this.rightChild = rightChild;
		this.value = value;
	}
}

排序樹類SortedTree:
package glut.bean;

import java.util.ArrayList;
import java.util.List;

public class SortedTree {
	private List<Number> arr;
	private Node root;
	private boolean allowTheSameNumber = false;

	/**
	 * 不能使用預設構造器
	 */
	private SortedTree() {
		// TODO Auto-generated constructor stub

	}

	/**
	 * 必須給定一個List,且list不能為空
	 * 
	 * @param arr
	 */
	public SortedTree(List<Number> arr) {
		this.arr = arr;
		if (!arr.isEmpty()) {
			root = new Node();
			root.parent = null;
			root.leftChild = null;
			root.rightChild = null;

			createSortedTree();
		} else {
			try {
				throw new Exception("Array is empty");
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	/**
	 * 必須給定一個List,且list不能為空
	 * 
	 * @param arr
	 * @param allowTheSameNumber
	 *            是否允許重複數字(建議false).true:allow ;false: not allow
	 */
	public SortedTree(List<Number> arr, boolean allowTheSameNumber) {
		this.arr = arr;
		this.allowTheSameNumber = allowTheSameNumber;
		if (!arr.isEmpty()) {
			root = new Node();
			root.parent = null;
			root.leftChild = null;
			root.rightChild = null;

			createSortedTree();
		} else {
			try {
				throw new Exception("Array is empty");
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	/**
	 * 以下引數都是通過createSortedTree方法的for迴圈獲取
	 * 
	 * @param value
	 * @param curNode
	 * @param index
	 */
	private void build(Number value, Node curNode, int index) {
		// 向左轉
		if (value.doubleValue() < curNode.value.doubleValue()) {
			// 如果沒有左節點,就建立
			if (curNode.leftChild == null) {
				curNode.leftChild = createNewNode(value, curNode, index, true);
				return;
			}
			// 有就繼續遍歷
			build(value, curNode.leftChild, index);
			// 向右轉
		} else if (value.doubleValue() > curNode.value.doubleValue()) {
			// 如果沒有右節點,就建立
			if (curNode.rightChild == null) {
				curNode.rightChild = createNewNode(value, curNode, index, false);
				return;
			}
			// 有就繼續遍歷
			build(value, curNode.rightChild, index);
			// 相同的值
		} else {
			if (!allowTheSameNumber) {
				try {
					throw new Exception("has the same number");
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				// 如果允許相同的值,則將它放在右子樹
			} else {
				// 如果沒有右節點,就建立
				if (curNode.rightChild == null) {
					curNode.rightChild = createNewNode(value, curNode, index,
							false);
					return;
				}
				// 有就繼續遍歷
				build(value, curNode.rightChild, index);
			}
		}
	}

	/**
	 * 
	 * @param value
	 * @param curNode
	 *            當前節點
	 * @param index
	 *            下標
	 * @param isLeftChild
	 *            是否為左節點
	 * @return 新建立的節點
	 */
	private Node createNewNode(Number value, Node curNode, int index,
			boolean isLeftChild) {
		Node newNode = new Node();
		newNode.value = value;
		// 將當前節點作為新建節點的雙親節點
		newNode.parent = curNode;
		newNode.index = index;
		newNode.isLeftChild = isLeftChild;
		return newNode;
	}

	private void createSortedTree() {
		// 預設將arr中第一個元素放到根
		root.value = arr.get(0);
		root.index = 0;
		for (int i = 1; i < arr.size(); i++) {
			build(arr.get(i), root, i);
		}
	}

	/**
	 * 
	 * @param value
	 *            給定的值
	 * @return 給定的值在arr中的下標
	 */
	public int indexOf(Number value) {
		Node targetNode = find(value, root);
		return targetNode == null ? -1 : targetNode.index;
	}

	/**
	 * 
	 * @param value
	 *            給定的值
	 * @return 給定的值的節點
	 */
	public Node get(Number value) {
		return find(value, root);
	}

	/**
	 * 
	 * @param value查詢的值
	 * @param curNode
	 *            第一個查詢的節點(預設為根節點)
	 * @return如果存在指定值的節點,返回.否則返回null
	 */
	private Node find(Number value, Node curNode) {
		if (curNode != null) {
			if (value.doubleValue() < curNode.value.doubleValue()) {
				return find(value, curNode.leftChild);
			} else if (value.doubleValue() > curNode.value.doubleValue()) {
				return find(value, curNode.rightChild);
			} else {
				return curNode;
			}
		} else {
			return null;
		}
	}

	/**
	 * 
	 * 
	 * @return 排序後的陣列(重複的數字只顯示一次)
	 */
	public List<Number> getSortedArray() {
		// newArr用於存放升序排列後的陣列
		List<Number> newArr = new ArrayList<Number>();
		midTraversal(root, newArr);
		return newArr;
	}

	// 中序遍歷二叉排序樹會得到升序的陣列
	private void midTraversal(Node curNode, List<Number> newArr) {
		// TODO Auto-generated method stub
		// 如果沒有左子樹,意味著遍歷到頭了
		if (curNode.leftChild == null) {
			// 直接把該店的值新增到數組裡
			newArr.add(curNode.value);
			// 如果有左子樹,繼續遍歷
		} else {
			midTraversal(curNode.leftChild, newArr);
			// 並且在遍歷完後將該節點的值新增到數組裡
			newArr.add(curNode.value);
		}
		// 最後遍歷右子樹
		if (curNode.rightChild != null) {
			midTraversal(curNode.rightChild, newArr);
		}
	}

	/**
	 * 
	 * @param value
	 *            要新增的值
	 */
	public void insert(Number value) {
		// 先將值新增到list裡
		arr.add(value);
		// 進行插入操作
		build(value, root, arr.size() - 1);
	}

	/**
	 * 刪除給定的值的第一次出現的節點
	 * 
	 * @param value
	 *            要刪除的值
	 */
	public void delete(Number value) {
		// 先看看有沒有這個節點
		Node targetNode = find(value, root);
		// 如果沒有這個節點,丟擲找不到的異常
		if (targetNode == null) {
			try {
				throw new Exception("specified value not found");
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		// 如果有這個節點
		// 當該節點擁有2個子節點
		if (targetNode.leftChild != null && targetNode.rightChild != null) {
			// 可以從目標節點的左子樹中找到最大的值,來替換目標節點(也可以通過右子數)
			// maxNodeOfLeft: the max value node of the left tree of the target
			Node maxNodeOfLeft = findLeftMaxNode(targetNode);
			// 將左子樹中最大的節點的值和下標放到目標節點中
			targetNode.value = maxNodeOfLeft.value;
			targetNode.index = maxNodeOfLeft.index;
			// leftChildOfMaxNode:the left child of the max node
			Node leftChildOfMaxNode = maxNodeOfLeft.leftChild;
			Node parent = maxNodeOfLeft.parent;

			if (leftChildOfMaxNode != null) {
				// 進行節點連線操作
				leftChildOfMaxNode.parent = parent;
				connected(maxNodeOfLeft, leftChildOfMaxNode, parent);
			} else {
				// 進行節點連線操作
				connected(maxNodeOfLeft, null, parent);
			}
			maxNodeOfLeft = null;
			// 如果無子節點
		} else if (targetNode.leftChild == null
				&& targetNode.rightChild == null) {
			// 進行節點連線操作
			Node parent = targetNode.parent;
			connected(targetNode, null, parent);
			targetNode = null;
			// 如果只有一個子節點
		} else {
			Node targetNodeLeftChild = targetNode.leftChild;
			Node parent = targetNode.parent;
			// 如果目標節點沒有左子樹
			if (targetNodeLeftChild == null) {
				// 那它肯定有右子樹
				Node targetNodeRightChild = targetNode.rightChild;
				// 進行節點連線操作
				targetNodeRightChild.parent = parent;
				connected(targetNode, targetNodeRightChild, parent);
			} else {
				// 進行節點連線操作
				targetNodeLeftChild.parent = parent;
				connected(targetNode, targetNodeLeftChild, parent);
			}
		}
	}

	/**
	 * 
	 * @param childNode
	 *            子節點
	 * @param childOfChildNode
	 *            子節點的子節點
	 * @param parentNode
	 *            子節點的雙親節點
	 */
	private void connected(Node childNode, Node childOfChildNode,
			Node parentNode) {
		if (childNode.isLeftChild) {
			parentNode.leftChild = childOfChildNode;
		} else {
			parentNode.rightChild = childOfChildNode;
		}
	}

	/**
	 * 
	 * @param targetNode
	 *            目標節點
	 * @return 返回值是指定節點的左子樹中值最大的節點
	 */
	private Node findLeftMaxNode(Node targetNode) {
		Node maxNodeOfLeft = targetNode.leftChild;
		// 一直右下,直到葉子
		while (maxNodeOfLeft.rightChild != null) {
			maxNodeOfLeft = maxNodeOfLeft.rightChild;
		}
		return maxNodeOfLeft;
	}

	public List<Number> getArr() {
		return arr;
	}

	public void setArr(List<Number> arr) {
		this.arr = arr;
	}

}

測試程式碼:
package glut.test;

import glut.bean.SortedTree;

import java.util.ArrayList;
import java.util.List;

public class MyTest {
	public static void main(String[] args) {

		List<Number> arr = new ArrayList<Number>();

		init(arr);

		SortedTree st = new SortedTree(arr, true);

		st.get(8);

		st.insert(10);

		st.delete(9);
		
		List<Number> array = st.getSortedArray();
		for (Number number : array) {
			System.out.print(number + ",");
		}

	}

	private static void init(List<Number> arr) {
		arr.add(7);
		arr.add(2);
		arr.add(1);
		arr.add(0);
		arr.add(5);
		arr.add(4);
		arr.add(3);
		arr.add(6);
		arr.add(9);
		arr.add(8);
	}

}