Java實現二叉排序樹
阿新 • • 發佈:2019-01-03
定義:
二叉排序樹或者是一棵空樹,或者是具有下列性質的二叉樹: (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); } }