爲了更加深刻了解二叉搜索樹,博主本身用Java寫了個二叉搜索樹,有興趣的同窗能夠一塊兒探討探討。node
首先,二叉搜索樹是啥?它有什麼用呢?算法
二叉搜索樹, 也稱二叉排序樹,它的每一個節點的數據結構爲1個父節點指針,1個左孩子指針,1個有孩子指針,還有就是本身的數據部分了,由於只有左右兩孩子,因此才叫二叉樹,在此基礎上,該二叉樹還知足另一個條件:每一個結點的左孩子都不大於該結點&&每一個結點的右孩子都大於該結點。這樣,咱們隊這棵樹進行中序遍歷,就能把key從小到大排序了……數據結構
那麼問題來了,我都有線性表有鏈表了,我還要它幹啥?兩個字!效率!ide
相比線性表,你要搜索一個key,就要執行一次線性時間,算法複雜度爲O(n);而用二叉搜索樹,算法效率是O(lgn)!這是很誘人的數字。下面我用Java實現如下二叉搜索樹,你天然就明白爲何算法複雜度是O(lgn)了。post
其次,寫一個數據結構,天然而然也要實現對這個數據結構的增、刪、查、改了。測試
下面是個人思路:ui
1 public class Test { 2 public static void main(String[] args) { 3 int[] datas={12,4,5,7,4,8,3,2,6,9}; 4 BinTree tree=new BinTree(datas); 5 tree.preOrderTraverse();//先序遍歷 6 tree.midOrderTraverse();//中序遍歷 7 tree.postOrderTraverse();//後序遍歷 8 tree.insert(15); //插入結點 9 tree.search(7); //查詢結點 10 tree.search(100); //查詢一個不存在的結點 11 tree.getMax(); //獲取最大值 12 tree.getMin(); //獲取最小值 13 tree.getPre(7); //前驅結點 14 tree.getPre(2); //最前的前驅結點 15 tree.getPost(7); //後繼結點 16 tree.getPost(15); //最後的後繼結點 17 tree.delete(5); //刪除結點 18 tree.delete(0); //刪除一個不存在的結點 19 } 20 }
1 public class BinTree { 2 Node root=null; 3 private class Node{ 4 Node parent=null; 5 Node leftChild=null; 6 Node rightChild=null; 7 int key; 8 public Node(int data) { 9 this.key=data; 10 } 11 } 12 public BinTree(int[] datas) { 13 buildTree(datas); 14 } 15 private void buildTree(int[] datas) { 16 for (int i = 0; i < datas.length; i++) { 17 Node node=new Node(datas[i]); 18 insertNode(node); 19 } 20 } 21 private void insertNode(Node node) { //插入結點 22 Node next=this.root; 23 Node cur=null; //用來保存當前結點 24 while(next!=null){ //當到達葉子結點時,確認位置! 25 cur=next; 26 if(node.key>=cur.key){ 27 next=next.rightChild; 28 }else{ 29 next=next.leftChild; 30 } 31 } 32 node.parent=cur; //插入該結點! 33 if(cur==null){ 34 this.root=node; //該樹爲空樹,因此這個是根節點 35 }else if(node.key>=cur.key){ 36 cur.rightChild=node; 37 }else{ 38 cur.leftChild=node; 39 } 40 } 41 /* 42 * 插入一個數 43 */ 44 public void insert(int data){ 45 Node node=new Node(data); 46 System.out.println("插入結點:"+data); 47 insertNode(node); 48 this.midOrderTraverse(); 49 } 50 51 /* 52 * 先序遍歷 53 */ 54 public void preOrderTraverse(){ 55 System.out.println("先序遍歷:"); 56 preOrderTraverse(root); 57 System.out.println(); 58 } 59 private void preOrderTraverse(Node node){ //先序遍歷 60 if(node!=null){ 61 System.out.print("-"+node.key+"-"); 62 preOrderTraverse(node.leftChild); 63 preOrderTraverse(node.rightChild); 64 } 65 } 66 /* 67 * 中序遍歷 68 */ 69 public void midOrderTraverse(){ 70 System.out.println("中序遍歷:"); 71 midOrderTraverse(root); 72 System.out.println(); 73 } 74 private void midOrderTraverse(Node node){ //中序遍歷 75 if(node!=null){ 76 midOrderTraverse(node.leftChild); 77 System.out.print("-"+node.key+"-"); 78 midOrderTraverse(node.rightChild); 79 } 80 81 } 82 83 /* 84 * 後序遍歷 85 */ 86 public void postOrderTraverse(){ 87 System.out.println("後序遍歷:"); 88 postOrderTraverse(root); 89 System.out.println(); 90 } 91 private void postOrderTraverse(Node node){ //後序遍歷 92 if(node!=null){ 93 System.out.print("-"+node.key+"-"); 94 postOrderTraverse(node.leftChild); 95 postOrderTraverse(node.rightChild); 96 } 97 } 98 99 /* 100 * 搜索結點 101 */ 102 public void search(int data){ 103 System.out.println("您要查找的是:"+data); 104 Node node; 105 if((node=searchNode(new Node(data)))==null){ 106 System.out.println("樹中沒有該結點!"); 107 }else{ 108 System.out.println("查找"+node.key+"成功!"); 109 } 110 } 111 112 private Node searchNode(Node node){ //private供內部調用,搜索結點 113 if(node==null){ 114 System.out.println("輸入爲空,查找失敗!"); 115 }else{ 116 if(root==null){ 117 System.out.println("該樹爲空樹!"); 118 }else{ //開始查找 119 boolean isFound=false; 120 Node x=root; 121 Node y=null; 122 while(!isFound&&x!=null){ //當查到或者到了葉子節點還沒查到時,終結! 123 y=x; 124 if(node.key==x.key){ 125 isFound=true; 126 }else{ //經過比較大小往下面查找 127 if(node.key>x.key){ 128 x=x.rightChild; 129 }else{ 130 x=x.leftChild; 131 } 132 } 133 } 134 if(isFound){ //沒找到的話,在最後返回null 135 return y; 136 } 137 } 138 } 139 return null; 140 } 141 142 /* 143 * 獲取最大值 144 */ 145 public void getMax(){ 146 Node node; 147 if((node=getMaxNode(root))==null){ 148 System.out.println("該樹爲空!"); 149 }else{ 150 System.out.println("最大的結點是:"+node.key); 151 } 152 153 } 154 155 private Node getMaxNode(Node node){ //獲取最大值 156 if(node!=null){ 157 Node x=node; 158 Node y=null; 159 while(x!=null){ //一直往右遍歷直到底就是最大值了! 160 y=x; 161 x=x.rightChild; 162 } 163 return y; 164 } 165 return null; 166 } 167 168 /* 169 * 獲取最小值 170 */ 171 public void getMin(){ 172 Node node; 173 if((node=getMinNode(root))==null){ 174 System.out.println("該樹爲空!"); 175 }else{ 176 System.out.println("最小的結點是:"+node.key); 177 } 178 } 179 private Node getMinNode(Node node){ //獲取最小值 180 if(node!=null){ 181 Node x=node; 182 Node y=null; 183 while(x!=null){ //一直往左遍歷直到底就是最小值了! 184 y=x; 185 x=x.leftChild; 186 } 187 return y; 188 } 189 return null; 190 } 191 192 /* 193 * 獲取前驅結點 194 */ 195 public void getPre(int data){ 196 Node node=null; 197 System.out.println(data+"的前驅結點:"); 198 if((node=getPreNode(searchNode(new Node(data))))==null){ 199 System.out.println("該結點不存在或無前驅結點!"); 200 }else{ 201 System.out.println(data+"的前驅結點爲:"+node.key); 202 } 203 } 204 205 private Node getPreNode(Node node){ //獲取前驅結點 206 if(node==null){ 207 return null; 208 } 209 if(node.leftChild!=null){ //當有左孩子時,前驅結點就是左子樹的最大值 210 return getMaxNode(node.leftChild); 211 }else{//當不存在左孩子時,前驅結點就是——它的祖先,並且,它在這個祖先的右子樹中。這句話本身畫圖就能理解了 212 Node x=node; 213 Node y=node.parent; 214 while(y!=null&&x==y.leftChild){ 215 x=y; 216 y=y.parent; 217 } 218 return y; 219 } 220 } 221 222 /* 223 * 獲取後繼結點 224 */ 225 public void getPost(int data){ 226 Node node=null; 227 System.out.println(data+"的後繼結點:"); 228 if((node=getPostNode(searchNode(new Node(data))))==null){ 229 System.out.println("該結點不存在或無後繼結點!"); 230 }else{ 231 System.out.println(data+"的後繼結點爲:"+node.key); 232 } 233 } 234 235 private Node getPostNode(Node node){ //獲取後繼結點 236 if(node==null){ 237 return null; 238 } 239 if(node.rightChild!=null){ //當有右孩子時,前驅結點就是右子樹的最小值 240 return getMinNode(node.rightChild); 241 }else{//當不存在右孩子時,後繼結點就是——它的祖先,並且,它在這個祖先的左子樹中。這句話本身畫圖就能理解了 242 Node x=node; 243 Node y=node.parent; 244 while(y!=null&&x==y.rightChild){ 245 x=y; 246 y=y.parent; 247 } 248 return y; 249 } 250 } 251 252 253 /* 254 * 刪除結點 255 */ 256 public void delete(int data){ 257 Node node; 258 if((node=searchNode(new Node(data)))==null){//注意!這裏不能new結點!你必須從樹中找該結點!new就是初始化了 259 System.out.println("二叉樹中不存在此結點!"); 260 return; 261 } 262 deleteNode(node); 263 System.out.println("刪除結點"+data+"後:"); 264 this.midOrderTraverse(); 265 } 266 267 268 private void deleteNode(Node node){ 269 if(node==null){ 270 System.out.println("刪除結點不能爲空!"); 271 return; 272 } 273 replacedNode(node); 274 } 275 276 private void replacedNode(Node node) { //替換結點 277 if(node.leftChild!=null 278 &&node.rightChild!=null){ //當有左右孩子時,用後繼結點替換 279 replacedNodeOfPost(node); 280 } 281 else 282 { 283 if(node.leftChild!=null){ //當只有左孩子時,直接用左子樹替換 284 node=node.leftChild; 285 }else if(node.rightChild!=null){ //只有右孩子時,直接有子樹替換 286 node=node.rightChild; 287 }else{ //當沒有左右孩子時,就直接釋放了這個結點 288 freeNode(node); 289 } 290 } 291 } 292 293 294 private void freeNode(Node node) { //釋放該結點,斷掉其與父結點的連接 295 if(node==node.parent.leftChild){ 296 node.parent.leftChild=null; 297 }else{ 298 node.parent.rightChild=null; 299 } 300 } 301 302 private void replacedNodeOfPost(Node node) { 303 Node y=this.getPostNode(node); //找後繼結點 304 node.key=y.key; 305 replacedNode(y); //替換了key以後,再一次遞歸把如今這個結點給替換了! 306 } 307 308 }