二叉排序樹(Binary Sort Tree),又稱二叉查找樹(Binary Search Tree),亦稱二叉搜索樹。是數據結構中的一類。在通常狀況下,查詢效率比鏈表結構要高。node
數組
當左子樹不爲空時,左子樹上的全部節點值都小於左子樹的根節點值數據結構
當右子樹不爲空時,右子樹上的全部節點值都小於右子樹的根節點值ide
若是二叉樹中有相同值節點時,能夠放在它的左子節點或右子節點(若是不是開發須要,儘可能不要有相同值的節點)this
(1) 判斷根節點是否爲空,若是爲空則將插入節點設置爲根節點spa
(2.1) 判斷插入節點值是否小於當前節點值,若是小於則往左節點走3d
(2.2) 當往左節點走時判斷左節點是否爲空,如爲空則將左節點設置爲插入節點,不爲空則跳到步驟(2)指針
(3.1) 判斷插入節點值是否大於當前節點值,若是大於則往右節點走code
(3.2) 當往右節點走時判斷右節點是否爲空,如爲空則將右節點設置爲插入節點,不爲空則跳到步驟(2)blog
下圖是將 [6, 2, 7, 1, 4, 8] 數組按順序插入二叉排序樹的過程圖示:
BSTNode root;//二叉排序樹的根節點 public void add(BSTNode node){ //若是根節點爲空則,則將傳入節點設置爲根節點 if (root == null){ root = node; }else { add(node, root); } } /** * 在二叉排序樹中添加節點 * @param node 添加的節點 * @param pointer 輔助指針節點,初始指向根節點 */ public void add(BSTNode node, BSTNode pointer){ if (node == null){ return; } if (pointer.value > node.value){//指針節點值大於添加節點值時 //若是指針節點的左節點恰好爲空,則將添加節點插入到該左節點 if (pointer.left == null){ pointer.left = node; }else { //若是不是則繼續往左節點走 add(node, pointer.left); } }else {//指針節點值小於添加節點值時 //若是指針節點的右節點恰好爲空,則將添加節點插入到該右節點 if (pointer.right == null){ pointer.right = node; }else { //若是不是則繼續往右節點走 add(node, pointer.right); } } }
(1) 判斷當前節點是不是查找節點,若是是則直接返回當前節點
(2) 判斷當前節點值是否大於查找節點值,若是大於則往左節點查找,跳到步驟(1)
(3) 判斷當前節點值是否小於查找節點值,若是小於則往右節點查找,跳到步驟(1)
下圖是從二叉排序樹中查找值爲4的節點的圖示:
//根據value值查找節點 public BSTNode searchNode(int value){ if (root == null){ return null; } return searchNode(value, root); } /** * 根據value值查找節點 * @param value 查找的節點 * @param node 查找的樹 * @return */ public BSTNode searchNode(int value, BSTNode node){ //若是當前節點的值等於value時,則返回該節點 if (node.value == value) { return node; } else if (node.value > value){//當前節點的值大於value時 //若是該節點的左節點爲空,則表示二叉排序樹內沒有該值的節點,返回空 if (node.left == null) return null; //左節點不爲空,繼續往左子樹查找 return searchNode(value, node.left); }else {//當前節點的值小於value時 //若是該節點的右節點爲空,則表示二叉排序樹內沒有該值的節點,返回空 if (node.right == null) return null; //右節點不爲空,繼續往右子樹查找 return searchNode(value, node.right); } }
刪除節點可能有的3中狀態:
刪除節點是葉子節點
刪除節點只有左子樹爲空或右子樹爲空
刪除節點左子樹和右子樹都爲空
(1) 判斷刪除節點值是否小於當前節點值,如小於則往左節點走
(2) 判斷刪除節點值是否大於當前節點值,如大於則往右節點走
(3) 當刪除節點值等於當前節點值時,即當前節點時要刪除的節點,判斷當前節點是什麼狀態
(3.1) 當前節點是葉子節點時,則直接刪除當前節點
(3.2) 當前節點左子樹爲空時,則將右節點頂上,代替當前節點位置
(3.3) 當前節點右子樹爲空時,則將左節點頂上,代替當前節點位置
(3.4) 當前節點左子樹和右子樹都不爲空時,則將左子樹的最大值節點取出後刪除,再用最大值節點頂替當前節點位置
/** * 根據value值刪除節點 * 刪除節點可能有的3種狀態: * 1.該節點是葉子節點 * 2.該節點只有左子樹或只有右子樹 * 3.該節點左子樹和右子樹都有 * @param value 要刪除節點的value值 */ public BSTNode delete(int value, BSTNode node){ if (value < node.value){//當查找節點值小於當前節點值 //向左子樹遞歸遍歷,並將刪除後的新的左子樹鏈接到左節點位置代替原先左子樹 node.left = delete(value, node.left); //返回刪除後新的樹 return node; }else if(value > node.value){//當查找節點值大於當前節點值 //向右子樹遞歸遍歷,並將刪除後的新的右子樹鏈接到右節點位置代替原先右子樹 node.right = delete(value, node.right); //返回刪除後新的樹 return node; }else {//當查找節點值等於當前節點值時,即當前節點就是要刪除的節點 //刪除節點時葉子節點的狀態 if (node.left == null && node.right == null){ //直接將該節點設爲空 return null; } //刪除節點左子樹爲空,右子樹不爲空的狀態 else if (node.left == null && node.right != null){ //保存刪除節點的右子樹 BSTNode rightSubTree = node.right; //將刪除節點的右子樹設爲空,使得該節點可以儘早被垃圾回收 node.right = null; //返回刪除節點的右子樹,鏈接到刪除節點的父節點 return rightSubTree; } //刪除節點右子樹爲空,左子樹不爲空的狀態 else if (node.right == null && node.left != null){ BSTNode leftSubTree = node.left; node.left = null; return leftSubTree; } //刪除節點的左子樹和右子樹都不爲空的狀態 //這裏咱們使用的是左子樹的最大值節點代替的方法 else { //獲取左子樹的最大值節點並從左子樹中刪除它 BSTNode max = max(node.left); //將該最大值節點的左子樹和右子樹設置爲該節點的左子樹和右子樹 max.left = delMax(node.left); max.right = node.right; //將刪除節點的左子樹和右子樹設爲空,使得該節點可以儘早被垃圾回收 node.left = null; node.right = null; //執行完刪除操做後,返回以最大值節點爲根節點的新的樹,鏈接的刪除節點的父節點 return max; } } } /** * 查找傳入節點樹下value值最大的節點並刪除該節點 * @param node * @return */ public BSTNode delMax(BSTNode node){ if (node.right != null){ node.right = delMax(node.right); return node; }else { BSTNode leftSubTree = node.left; node.left = null; return leftSubTree; } } /** * 查找傳入節點樹下value值最大的節點並放回該節點 * 在二叉排序樹中最大值的節點就是最右葉子節點 * @param node * @return */ public BSTNode max(BSTNode node){ BSTNode max = node; while (max.right != null){ max = max.right; } return max; }
public class BinarySortTreeDemo { public static void main(String[] args) { int array[] = {13,7,8,3,29,6,1}; BinarySortTree binarySortTree = new BinarySortTree(); for (int i=0; i<array.length; i++){ binarySortTree.add(new BSTNode(array[i])); } binarySortTree.midOrder(); System.out.println("刪除後二叉順序樹的節點:"); binarySortTree.delete(13); binarySortTree.delete(7); binarySortTree.delete(1); binarySortTree.delete(29); binarySortTree.delete(6); binarySortTree.midOrder(); } } //二叉排序樹 class BinarySortTree{ BSTNode root; public void setRoot(BSTNode root){ this.root = root; } //添加節點 public void add(BSTNode node){ //若是根節點爲空則,則將傳入節點設置爲根節點 if (root == null){ root = node; }else { add(node, root); } } /** * 在二叉排序樹中添加節點 * @param node 添加的節點 * @param pointer 指針節點,初始指向根節點 */ public void add(BSTNode node, BSTNode pointer){ if (node == null){ return; } if (pointer.value > node.value){//指針節點值大於添加節點值時 //若是指針節點的左節點恰好爲空,則將添加節點插入到該左節點 if (pointer.left == null){ pointer.left = node; }else { //若是不是則繼續往左節點走 add(node, pointer.left); } }else {//指針節點值小於添加節點值時 //若是指針節點的右節點恰好爲空,則將添加節點插入到該右節點 if (pointer.right == null){ pointer.right = node; }else { //若是不是則繼續往右節點走 add(node, pointer.right); } } } //根據value值查找節點 public BSTNode searchNode(int value){ if (root == null){ return null; } return searchNode(value, root); } /** * 根據value值查找節點 * @param value 查找的節點 * @param node 查找的樹 * @return */ public BSTNode searchNode(int value, BSTNode node){ //若是當前節點的值等於value時,則返回該節點 if (node.value == value) { return node; } else if (node.value > value){//當前節點的值大於value時 //若是該節點的左節點爲空,則表示二叉排序樹內沒有該值的節點,返回空 if (node.left == null) return null; //左節點不爲空,繼續往左子樹查找 return searchNode(value, node.left); }else {//當前節點的值小於value時 //若是該節點的右節點爲空,則表示二叉排序樹內沒有該值的節點,返回空 if (node.right == null) return null; //右節點不爲空,繼續往右子樹查找 return searchNode(value, node.right); } } public void delete(int value){ //判斷刪除節點在二叉排序樹中是否存在 BSTNode node = searchNode(value); if (node == null){ throw new RuntimeException("二叉排序樹內無對應節點"); } //將刪除後新的二叉排序樹更換掉原先二叉排序樹 root = delete(value, root); } /** * 根據value值刪除節點 * 刪除節點可能有的3種狀態: * 1.該節點是葉子節點 * 2.該節點只有左子樹或只有右子樹 * 3.該節點左子樹和右子樹都有 * @param value 要刪除節點的value值 */ public BSTNode delete(int value, BSTNode node){ if (value < node.value){//當查找節點值小於當前節點值 //向左子樹遞歸遍歷,並將刪除後的新的左子樹鏈接到左節點位置代替原先左子樹 node.left = delete(value, node.left); //返回刪除後新的樹 return node; }else if(value > node.value){//當查找節點值大於當前節點值 //向右子樹遞歸遍歷,並將刪除後的新的右子樹鏈接到右節點位置代替原先右子樹 node.right = delete(value, node.right); //返回刪除後新的樹 return node; }else {//當查找節點值等於當前節點值時,即當前節點就是要刪除的節點 //刪除節點時葉子節點的狀態 if (node.left == null && node.right == null){ //直接將該節點設爲空 return null; } //刪除節點左子樹爲空,右子樹不爲空的狀態 else if (node.left == null && node.right != null){ //保存刪除節點的右子樹 BSTNode rightSubTree = node.right; //將刪除節點的右子樹設爲空,使得該節點可以儘早被垃圾回收 node.right = null; //返回刪除節點的右子樹,鏈接到刪除節點的父節點 return rightSubTree; } //刪除節點右子樹爲空,左子樹不爲空的狀態 else if (node.right == null && node.left != null){ BSTNode leftSubTree = node.left; node.left = null; return leftSubTree; } //刪除節點的左子樹和右子樹都不爲空的狀態 //這裏咱們使用的是左子樹的最大值節點代替的方法 else { //獲取左子樹的最大值節點並從左子樹中刪除它 BSTNode max = max(node.left); //將該最大值節點的左子樹和右子樹設置爲該節點的左子樹和右子樹 max.left = delMax(node.left); max.right = node.right; //將刪除節點的左子樹和右子樹設爲空,使得該節點可以儘早被垃圾回收 node.left = null; node.right = null; //執行完刪除操做後,返回以最大值節點爲根節點的新的樹,鏈接的刪除節點的父節點 return max; } } } /** * 查找傳入節點樹下value值最大的節點並刪除該節點 * @param node * @return */ public BSTNode delMax(BSTNode node){ if (node.right != null){ node.right = delMax(node.right); return node; }else { BSTNode leftSubTree = node.left; node.left = null; return leftSubTree; } } /** * 查找傳入節點樹下value值最大的節點並放回該節點 * 在二叉排序樹中最大值的節點就是最右葉子節點 * @param node * @return */ public BSTNode max(BSTNode node){ BSTNode max = node; while (max.right != null){ max = max.right; } return max; } public void midOrder(){ if (root != null){ midOrder(root); }else { System.out.println("二叉順序樹爲空,沒法遍歷"); } } //中序遍歷 public void midOrder(BSTNode node){ if (node.left != null){ midOrder(node.left); } System.out.println(this); if (node.right != null){ midOrder(node.right); } } } //二叉排序樹節點 class BSTNode{ int value; BSTNode left; BSTNode right; public BSTNode(int value){ this.value = value; } @Override public String toString() { return "BSTNode{" + "value=" + value + '}'; } }