從零開始學資料結構和演算法(六)二叉排序樹
-
概念
或者是一顆空樹,或者是一顆具有如下性質的樹:
- 若左子樹不為空,那麼左子樹上面的所有節點的關鍵字值都比根節點的關鍵字值小
- 若右子樹不為空,那麼右子樹上面的所有節點的關鍵字值都比根節點的關鍵字值大
- 左右子樹都為二叉樹
- 沒有重複值(這一點在實際中可以忽略)
主要操作
- 新增節點

-
查詢節點
-
刪除節點
-
節點是葉子
-
只有左孩子
-
只有右孩子
-
左右孩子都有
-
-
遍歷
用二叉樹的中序
樹,森林,二叉樹的轉換
樹轉換為二叉樹
-
概念
-
圖解
森林轉換為二叉樹
-
概念
-
圖解
二叉樹轉換為樹
-
概念
-
圖解
二叉樹轉換為森林
-
概念
-
圖解
程式碼示例
public class SearchBinaryTree { //根節點 public TreeNode root; /** * 新增節點 */ public TreeNode put(int data){ if(root==null){ TreeNode node=new TreeNode(data); root=node; return node; } TreeNode parent=null; TreeNode node=root; //找到要放入的位置 while(node!=null){ parent=node; if(data<node.data){ node=node.leftChild; }else if(data>node.data){ node=node.rightChild; }else{//是重複值 就不理會了 return node; } } //生成一個節點放入 TreeNode newNode=new TreeNode(data); if(data<parent.data) { parent.leftChild = newNode; }else{ parent.rightChild=newNode; } newNode.parent=parent; return newNode; } /** * 中序遍歷 */ public void midOrderTraverse(TreeNode root){ if(root==null){ return; } //LDR midOrderTraverse(root.leftChild); System.out.print(root.data+" "); midOrderTraverse(root.rightChild); } /** * 查詢一個節點 */ public TreeNode searchNode(int data){ if(root==null){ return null; } TreeNode node=root; while(node!=null){ if(node.data==data){ return node; }else if(data>node.data){ node=node.rightChild; }else if(data<node.data){ node=node.leftChild; } } return null; } /** * 刪除節點 * 要刪除的節點在樹上是一定存在的才刪除 */ public void delNode(TreeNode node){ if(node==null){ throw new NoSuchElementException(); }else{ //先得到父親,方便後面的操作 TreeNode parent=node.parent; //1.葉子 if(node.leftChild==null && node.rightChild==null){ //特別的情況:1.樹上只有一個節點或是空樹 if(parent==null){ root=null; }else if(parent.rightChild==node){ parent.rightChild=null; }else if(parent.leftChild==node){ parent.leftChild=null; } node.parent=null; }else if(node.leftChild!=null && node.rightChild==null){ //2.只有左孩子 if(parent==null){//如果要刪除的是根 node.parent=null; node.leftChild.parent=null; root=node.leftChild; }else{ if(parent.leftChild==node){//要刪除的節點是父親的左邊 node.leftChild.parent=parent; parent.leftChild=node.leftChild; }else{//要刪除的節點是父親的右邊 node.leftChild.parent=parent; parent.rightChild=node.leftChild; } node.parent=null; } }else if(node.leftChild==null && node.rightChild!=null){ //3.只有右孩子 if(parent==null){//如果要刪除的是根 node.parent=null; node.rightChild.parent=null; root=node.rightChild; }else{ if(parent.leftChild==node){//要刪除的節點是父親的左邊 node.rightChild.parent=parent; parent.leftChild=node.rightChild; }else{//要刪除的節點是父親的右邊 node.rightChild.parent=parent; parent.rightChild=node.rightChild; } node.parent=null; } }else{//4。有左右兩個孩子 if(node.rightChild.leftChild==null){//1.如果被刪除節點的右子樹的左子樹為空,就直接補上右子樹 node.rightChild.leftChild=node.leftChild; if(parent==null){ root=node.rightChild; }else{ if(parent.leftChild==node){ parent.leftChild=node.rightChild; // }else{ parent.rightChild=node.rightChild; // } } node.parent=null; }else{//2.否則就要補上右子樹的左子樹上最小的一個 TreeNode leftNode=getMinLeftTreeNode(node.rightChild); //1 leftNode.leftChild=node.leftChild; //2 TreeNode leftNodeP=leftNode.parent; leftNodeP.leftChild=leftNode.rightChild; //3 leftNode.rightChild=node.rightChild; //4 if(parent==null){ root=leftNode; }else{ if(parent.leftChild==node){ parent.leftChild=leftNode; // }else{ parent.rightChild=leftNode; // } } } } } } private TreeNode getMinLeftTreeNode(TreeNode node) { TreeNode curRoot=null; if(node==null){ return null; }else{ curRoot=node; while(curRoot.leftChild!=null){ curRoot=curRoot.leftChild; } } return curRoot; } public static class TreeNode{ intdata; TreeNode leftChild; TreeNode rightChild; TreeNode parent; public TreeNode(int data){ this.data=data; this.leftChild=null; this.rightChild=null; this.parent=null; } } } 複製程式碼
public class ExampleUnitTest { @Test public void addition_isCorrect() throws Exception { SearchBinaryTree tree=new SearchBinaryTree(); //5273416 int[] array=new int[]{5,2,7,3,4,1,6}; for (int i : array) { tree.put(i); } tree.midOrderTraverse(tree.root); for(int i=0;i<array.length-1;i++){ SearchBinaryTree.TreeNode node=tree.searchNode(array[i]); tree.delNode(node); } System.out.println("----"); tree.midOrderTraverse(tree.root); //System.out.println(node.data); 複製程式碼