二分法猜数字的游戏应该每个人都知道,通过对猜测数字“大了”、“小了”的情况判断,来猜出最终的数字。序列范围为 的集合,复杂度为 ,即最多需要 次可以猜到最终数字。
二分法的查找过程是,在一个有序的序列中,每次都会选择有效范围中间位置的元素作判断,即每次判断后,都可以排除近一半的元素,直到查找到目标元素或返回不存在,所以 个有序元素构成的序列,查找的时间复杂度为 。既然线性结构能够做到查询复杂度为 级别,那二叉搜索树产生又有何必要呢?毕竟二叉搜索树的查询复杂度只是介于 ~ 之间,并不存在查询优势。
二叉搜索树是一种节点值之间具有一定数量级次序的二叉树,对于树中每个节点:
示例:
观察二叉搜索树结构可知,查询每个节点需要的比较次数为节点深度加一。如深度为 0,节点值为 “6” 的根节点,只需要一次比较即可;深度为 1,节点值为 “3” 的节点,只需要两次比较。即二叉树节点个数确定的情况下,整颗树的高度越低,节点的查询复杂度越低。
【1】 完全二叉树,所有节点尽量填满树的每一层,上一层填满后还有剩余节点的话,则由左向右尽量填满下一层。如上图BST所示,即为一颗完全二叉树;
【2】每一层只有一个节点的二叉树。如下图SP_BST所示:
第【1】种情况下的查找次数分析:由上一章 二叉树 可知,完美二叉树中树的深度与节点个数的关系为:。设深度为 的完全二叉树节点总数为 ,因为完全二叉树中深度为 的叶子节点层不一定填满,所以有 ,即:,因为 为查找次数,所以完全二叉树中查找次数为:。
第【2】种情况下,树中每层只有一个节点,该状态的树结构更倾向于一种线性结构,节点的查询类似于数组的遍历,查询复杂度为 。
所以二叉搜索树的查询复杂度为 ~。
二叉搜索树的构造过程,也就是将节点不断插入到树中适当位置的过程。该操作过程,与查询节点元素的操作基本相同,不同之处在于:
由此可知,单个节点的构造复杂度和查询复杂度相同,为 ~。
二叉搜索树的节点删除包括两个过程,查找和删除。查询的过程和查询复杂度已知,这里说明一下删除节点的过程。
第一种情况如下图 s_1 所示,待删除节点值为 “6”,该节点无子树,删除后并不影响二叉搜索树的结构特性,可以直接删除。即二叉搜索树中待删除节点度为零时,该节点为叶子节点,可以直接删除;
s_1 s_1'第二种情况如下图 s_2 所示,待删除节点值为 “7”,该节点有一个左子树,删除节点后,为了维持二叉搜索树结构特性,需要将左子树“上移”到删除的节点位置上。即二叉搜索树中待删除的节点度为一时,可以将待删除节点的左子树或右子树“上移”到删除节点位置上,以此来满足二叉搜索树的结构特性。
s_2 s_2'第三种情况如下图 s_3 所示,待删除节点值为 “9”,该节点既有左子树,也有右子树,删除节点后,为了维持二叉搜索树的结构特性,需要从其左子树中选出一个最大值的节点,“上移”到删除的节点位置上。即二叉搜索树中待删除节点的度为二时,可以将待删除节点的左子树中的最大值节点“移动”到删除节点位置上,以此来满足二叉搜索树的结构特性。
s_3 s_3'其实在真实的实现代码中,该情况下的实际节点删除操作是:
1.查找出左子树中的最大值节点
2.替换待删除节点 的值为 的值
3.删除 节点
因为 作为左子树的最大值节点,所以节点的度一定是 0 或 1,所以删除节点的情况就转移为以上两种情况。
之前提到二叉搜索树中节点的删除操作,包括查询和删除两个过程,这里称删除节点后,维持二叉搜索树结构特性的操作为“稳定结构”操作,观察以上三种情况可知:
由以上查询复杂度、构造复杂度和删除复杂度的分析可知,三种操作的时间复杂度皆为 ~。下面分析线性结构的三种操作复杂度,以二分法为例:
由此可知,二叉搜索树相对于线性结构,在构造复杂度和删除复杂度方面占优;在查询复杂度方面,二叉搜索树可能存在类似于斜树,每层上只有一个节点的情况,该情况下查询复杂度不占优势。
1.完整实现
1 package DataStructure.Tree; 2 3 import DataStructure.Tree.printer.BinaryTreeInfo; 4 import DataStructure.main1.AbstractList; 5 6 import java.util.Comparator; 7 import java.util.LinkedList; 8 import java.util.Queue; 9 10 public class BinarySearchTree <E > implements BinaryTreeInfo { 11 private int size; 12 private Node<E> root; 13 private Comparator<E> comparator; 14 public BinarySearchTree(Comparator<E> comparator){ 15 this.comparator=comparator; 16 } 17 public BinarySearchTree(){ 18 this(null); 19 } 20 public int size(){ 21 return size; 22 } 23 public boolean isEmpty(){ 24 return size==0; 25 } 26 27 public void clear() { 28 root=null; 29 size=0; 30 } 31 public static abstract class Visitor<E> { 32 boolean stop; 33 /** 34 * @return 如果返回true,就代表停止遍历 35 */ 36 public abstract boolean visit(E element); 37 } 38 public void add(E element) { 39 elementnotnullcheck(element); 40 //添加第一个节点 41 if(root==null){ 42 root =new Node<>(element,null); 43 size++; 44 return; 45 } 46 //添加的不是第一个节点,找到父节点 47 Node<E> node =root; 48 Node<E> parent =root;//每次需要保存上一次的父节点 49 int cmp=0; 50 while (node!=null) { 51 cmp = compare(element, node.element); 52 parent=node; 53 if (cmp > 0) { 54 node = node.right; 55 } else if (cmp < 0) { 56 node = node.left; 57 } else { 58 node.element=element;//覆盖相等的,意义是 59 return; 60 } 61 } 62 //看看插入到节点的哪个方向 63 Node<E> newnode=new Node<>(element,parent); 64 if(cmp>0){ 65 parent.right=newnode; 66 } 67 else if(cmp<0) { 68 parent.left=newnode; 69 } 70 size++; 71 72 } 73 74 75 76 77 public boolean contains(E element) { 78 return node(element)!=null; 79 } 80 81 //element不能为null 82 private void elementnotnullcheck(E element){ 83 if(element==null){ 84 throw new IllegalArgumentException("element must not be null"); 85 } 86 } 87 //前序遍历 88 public void preorder(Visitor<E> visitor) { 89 if (visitor == null) return; 90 preorder(root, visitor); 91 } 92 93 private void preorder(Node<E> node, Visitor<E> visitor) { 94 if (node == null || visitor.stop) return; 95 96 visitor.stop = visitor.visit(node.element); 97 preorder(node.left, visitor); 98 preorder(node.right, visitor); 99 } 100 101 public void inorder(Visitor<E> visitor) { 102 if (visitor == null) return; 103 inorder(root, visitor); 104 } 105 106 private void inorder(Node<E> node, Visitor<E> visitor) { 107 if (node == null || visitor.stop) return; 108 109 inorder(node.left, visitor); 110 if (visitor.stop) return; 111 visitor.stop = visitor.visit(node.element); 112 inorder(node.right, visitor); 113 } 114 115 public void postorder(Visitor<E> visitor) { 116 if (visitor == null) return; 117 postorder(root, visitor); 118 } 119 120 private void postorder(Node<E> node, Visitor<E> visitor) { 121 if (node == null || visitor.stop) return; 122 123 postorder(node.left, visitor); 124 postorder(node.right, visitor); 125 if (visitor.stop) return; 126 visitor.stop = visitor.visit(node.element); 127 } 128 129 /** 130 * 层序遍历,首先,根节点入队,然后循环以下步骤 ,直到队列为空1.将队头节点A出队,进行访问2.将A的左节点入队,3.将A的右节点入队 131 * @param visitor 132 */ 133 public void levelOrder(Visitor<E> visitor) { 134 if (root == null || visitor == null) return; 135 136 Queue<Node<E>> queue = new LinkedList<>(); 137 queue.offer(root); 138 139 while (!queue.isEmpty()) { 140 Node<E> node = queue.poll(); 141 if (visitor.visit(node.element)) return; 142 143 if (node.left != null) { 144 queue.offer(node.left); 145 } 146 147 if (node.right != null) { 148 queue.offer(node.right); 149 } 150 } 151 } 152 /** 153 * 前驱节点: 中序遍历时的前一个节点 154 * 求前驱节点 155 */ 156 protected Node<E> predecessor(Node<E> node) { 157 if (node == null) return null; 158 159 // 前驱节点在左子树中(left.right.right.right....) 160 Node<E> p = node.left; 161 if (p != null) { 162 // 左子树不为空,则找到它的最右节点 163 while (p.right != null) { 164 p = p.right; 165 } 166 return p; 167 } 168 169 // 能来到这里说明左子树为空, 则从父节点、祖父节点中寻找前驱节点 170 // 当父节点不为空, 且某节点为父节点的左子节点 171 // 则顺着父节点找, 直到找到【某结点为父节点或祖父节点的右子树中】时 172 while (node.parent != null && node.parent.left == node) { 173 node = node.parent; 174 } 175 176 // 来到这里有以下两种情况: 177 // node.parent == null 无前驱, 说明是根结点 178 // node.parent...right == node 找到【某结点为父节点或祖父节点的右子树中】 179 // 那么父节点就是某节点的前驱节点 180 return node.parent; 181 } 182 /** 183 * 后继节点: 中序遍历时的后一个节点 184 * 求后继节点 185 */ 186 protected Node<E> successor(Node<E> node) { 187 if (node == null) return null; 188 // 后继节点与前驱节点正好相反 189 190 // 后继节点在右子树中(node.right.left.left...) 191 if (node.right != null) { 192 Node<E> p = node.right; 193 while (p.left != null) { 194 p = p.left; 195 } 196 return p; 197 } 198 199 // 来到这里说明没有右节点, 则从父节点、祖父节点中寻找后继节点 200 // 当父节点不为空, 且某节点为父节点的右子节点 201 // 则顺着父节点找, 直到找到【某结点在父节点或祖父节点的左子树中】时 202 while (node.parent != null && node.parent.right == node) { 203 node = node.parent; 204 } 205 206 // 来到这里有以下两种情况: 207 // node.parent == null 无前驱,说明是根结点 208 // node.parent.left == node 找到【某结点在父节点或祖父节点的左子树中】 209 // 那么父节点就是某节点的后继节点 210 return node.parent; 211 } 212 /** 213 * 根据传入的值删除元素 214 */ 215 public void remove(E element) { 216 remove(node(element)); 217 } 218 // 根据节点删除元素 219 private void remove(Node<E> node) { 220 if (node == null) return; 221 222 size--; 223 224 if (node.hasTwochildren()) { // 度为2的节点 225 // 找到后继节点 226 Node<E> s = successor(node); 227 // 用后继节点的值覆盖度为2的节点的值 228 node.element = s.element; 229 // 删除后继节点 230 node = s; 231 } 232 233 // 删除node节点(node的度必然是1或者0) 234 Node<E> replacement = node.left != null ? node.left : node.right; 235 236 if (replacement != null) { // node是度为1的节点 237 // 更改parent 238 replacement.parent = node.parent; 239 // 更改parent的left、right的指向 240 if (node.parent == null) { // node是度为1的节点并且是根节点 241 root = replacement; 242 } else if (node == node.parent.left) { 243 node.parent.left = replacement; 244 } else { // node == node.parent.right 245 node.parent.right = replacement; 246 } 247 } else if (node.parent == null) { // node是叶子节点并且是根节点 248 root = null; 249 } else { // node是叶子节点,但不是根节点 250 if (node == node.parent.left) { 251 node.parent.left = null; 252 } else { // node == node.parent.right 253 node.parent.right = null; 254 } 255 } 256 } 257 258 // 根据元素值获取节点元素 259 private Node<E> node(E element){ 260 elementnotnullcheck(element); 261 262 Node<E> node = root; 263 while(node != null){ 264 int cmp = compare(element, node.element); 265 if(cmp < 0){ 266 node = node.left;//从左边找 267 }else if (cmp > 0){ 268 node = node.right; 269 }else{ // cmp == 0 270 return node; 271 } 272 } 273 return null; 274 } 275 276 /** 277 * 递归来计算高度 278 * @return 279 */ 280 public int height2(){ 281 return height(root); 282 } 283 284 private int height(Node<E> node){ 285 if(node==null) return 0; 286 return 1+Math.max(height( node.left) ,height(node.right) ); 287 } 288 /** 289 * 层序遍历来计算高度 290 */ 291 public int height() { 292 if (root == null) return 0; 293 294 // 树的高度 295 int height = 0; 296 // 存储着每一层的元素数量 297 int levelSize = 1; 298 Queue<Node<E>> queue = new LinkedList<>(); 299 queue.offer(root); 300 301 while (!queue.isEmpty()) { 302 Node<E> node = queue.poll(); 303 levelSize--; 304 305 if (node.left != null) { 306 queue.offer(node.left); 307 } 308 309 if (node.right != null) { 310 queue.offer(node.right); 311 } 312 313 if (levelSize == 0) { // 意味着即将要访问下一层 314 levelSize = queue.size(); 315 height++; 316 } 317 } 318 319 return height; 320 } 321 /** 322 * 是否是完全二叉树 323 */ 324 public boolean isComplete() { 325 if (root == null) return false; 326 327 Queue<Node<E>> queue = new LinkedList<>(); 328 queue.offer(root); 329 330 // leaf代表是否要求后面都是叶子节点 331 // 比如遍历到一个节点 left == null && right == null 332 // 或者是 left != null && right == null 333 // 则要求这个节点后面的节点都是叶子节点 334 boolean leaf = false; 335 while (!queue.isEmpty()) { 336 Node<E> node = queue.poll(); 337 // 要求是叶子结点,但是当前节点不是叶子结点 338 if (leaf && !node.isleaf()) { 339 return false; 340 } 341 if (node.left != null) { 342 queue.offer(node.left); 343 } else if (node.right != null) { 344 // node.left == null && node.right != null 345 return false; 346 } 347 if (node.right != null) { 348 queue.offer(node.right); 349 } else { 350 // node.left == null && node.right == null 351 // node.left != null && node.right == null 352 leaf = true; // 要求后面都是叶子节点 353 } 354 } 355 return true; 356 } 357 //这些都为优化前 358 // public boolean isComplete(){ 359 // if (root == null ) return false; 360 // Queue<Node<E>> queue = new LinkedList<>(); 361 // queue.offer(root); 362 ////树不为空,开始遍历,入队。 1.左右不为空 ,入队2.左空,右不空,false 3.左不空,右空,或者左右都是空,那么右边都是叶子节点 363 // boolean leaf=false; 364 // while (!queue.isEmpty()) { 365 // Node<E> node = queue.poll(); 366 // if(leaf&&!node.isleaf() ){return false;} 367 // if (node.hasTwochildren() ){ 368 // queue.offer(node.left); 369 // queue.offer(node.right); 370 // } 371 // else if (node.left == null&&node.right!=null) { 372 // return false; 373 // } 374 // else {//后面的遍历节点都是叶子 375 // leaf=true; 376 // if(node.left!=null) 377 // queue.offer(node.left); 378 // } 379 // } 380 // return true; 381 // } 382 // 383 // /** 384 // * 前序遍历 385 // */ 386 // public void preorderTraversal(){ 387 // preorderTraversal(root); 388 // } 389 // private void preorderTraversal(Node<E> node){ 390 // if(node==null) return; 391 // System.out.println(node.element); 392 // preorderTraversal(node.left); 393 // preorderTraversal(node.right); 394 // 395 // } 396 // /** 397 // * 中序遍历 398 // */ 399 // public void inorderTraversal(){ 400 //inorderTraversal(root); 401 // } 402 // 403 // 404 // private void inorderTraversal(Node<E> node){ 405 // if(node==null) return; 406 // preorderTraversal(node.left); 407 // System.out.println(node.element); 408 // preorderTraversal(node.right); 409 // 410 // } 411 ///** 412 // * 后续遍历 413 // */ 414 // public void postorderTraversal(){ 415 // postorderTraversal(root); 416 //} 417 // 418 // 419 // private void postorderTraversal(Node<E> node){ 420 // if(node==null) return; 421 // postorderTraversal(node.left); 422 // postorderTraversal(node.right); 423 // System.out.println(node.element); 424 // 425 // } 426 // 427 // /** 428 // * 层序遍历 429 // */ 430 // public void levelOrderTraversal() { 431 // if (root == null) return; 432 // 433 // Queue<Node<E>> queue = new LinkedList<>(); 434 // queue.offer(root); 435 // 436 // while (!queue.isEmpty()) { 437 // Node<E> node = queue.poll(); 438 // System.out.println(node.element); 439 // 440 // if (node.left != null) { 441 // queue.offer(node.left); 442 // } 443 // 444 // if (node.right != null) { 445 // queue.offer(node.right); 446 // } 447 // } 448 // } 449 450 /** 451 * 452 * @param e1 453 * @param e2 454 * @return ==0 相等 大于0 e1大 455 */ 456 private int compare(E e1,E e2){ 457 if(comparator!=null){ 458 return comparator.compare(e1,e2); 459 460 } 461 return ((Comparable<E>)e1).compareTo(e2); 462 } 463 464 465 466 @Override 467 public Object root() { 468 return root; 469 } 470 471 @Override 472 public Object left(Object node) { 473 return ((Node<E>)node).left; 474 } 475 476 @Override 477 public Object right(Object node) { 478 return ((Node<E>)node).right; 479 } 480 481 @Override 482 public Object string(Object node) { 483 return ((Node<E>)node).element; 484 } 485 //定位节点 486 private static class Node<E>{ 487 E element; 488 Node<E> left;//左子节点 489 Node<E> right; 490 Node<E> parent;//父节点 491 public Node (E element,Node<E> parent){ 492 this.element=element; 493 this.parent=parent; 494 } 495 public boolean isleaf(){ 496 return left==null&&right==null; 497 } 498 public boolean hasTwochildren(){ 499 return left!=null&&right!=null; 500 501 } 502 503 } 504 }
2.二叉树的通用类(父类)
1 package DataStructure.Tree_new; 2 3 import DataStructure.Tree.printer.BinaryTreeInfo; 4 5 import java.util.LinkedList; 6 import java.util.Queue; 7 8 public class BinaryTree <E>implements BinaryTreeInfo { 9 protected int size; // 元素数量 10 protected Node<E> root; // 根节点 11 12 /** 13 * 访问器接口 ——> 访问器抽象类 14 * 增强遍历接口 15 */ 16 /*public static interface Visitor<E>{ 17 void visit(E element); 18 }*/ 19 public static abstract class Visitor<E> { 20 boolean stop; 21 // 如果返回true,就代表停止遍历 22 public abstract boolean visit(E element); 23 } 24 25 /** 26 * 内部类,节点类 27 */ 28 public static class Node<E> { 29 E element; // 元素值 30 Node<E> left; // 左节点 31 Node<E> right; // 右节点 32 Node<E> parent; // 父节点 33 34 public Node(E element, Node<E> parent) { 35 this.element = element; 36 this.parent = parent; 37 } 38 39 public boolean isLeaf() { // 是否叶子节点 40 return left == null && right == null; 41 } 42 43 public boolean hasTwoChildren() { // 是否有两个子节点 44 return left != null && right != null; 45 } 46 public boolean isLeftChild(){ // 判断自己是不是左子树 47 return parent!=null && this==parent.left; 48 } 49 public boolean isRightChild(){ // 判断自己是不是右子树 50 return parent!=null && this==parent.right; 51 } 52 /* 53 * 返回兄弟节点 54 */ 55 public Node<E> sibling() { // 红黑树中用到, 返回兄弟节点 56 if (isLeftChild()) { 57 return parent.right; 58 } 59 60 if (isRightChild()) { 61 return parent.left; 62 } 63 return null; 64 } 65 } 66 67 68 /** 69 * 元素的数量 70 */ 71 public int size() { 72 return size; 73 } 74 75 /** 76 * 是否为空 77 */ 78 public boolean isEmpty() { 79 return size == 0; 80 } 81 82 /** 83 * 清空所有的元素 84 */ 85 public void clear() { 86 root = null; 87 size = 0; 88 } 89 90 /** 91 * 前序遍历 92 */ 93 public void preorder(Visitor<E> visitor) { 94 if (visitor == null) return; 95 preorder(root, visitor); 96 } 97 public void preorder(Node<E> node, Visitor<E> visitor) { 98 if (node == null || visitor.stop) return; 99 // 根 100 visitor.stop = visitor.visit(node.element); 101 // 左 102 preorder(node.left, visitor); 103 // 右 104 preorder(node.right, visitor); 105 } 106 107 /** 108 * 中序遍历 109 */ 110 public void inorder(Visitor<E> visitor) { 111 if (visitor == null) return; 112 inorder(root, visitor); 113 } 114 public void inorder(Node<E> node, Visitor<E> visitor) { 115 if (node == null || visitor.stop) return; 116 // 左 117 inorder(node.left, visitor); 118 // 根 119 if (visitor.stop) return; 120 visitor.stop = visitor.visit(node.element); 121 // 右 122 inorder(node.right, visitor); 123 } 124 125 /** 126 * 后序遍历 127 */ 128 public void postorder(Visitor<E> visitor) { 129 if (visitor == null) return; 130 postorder(root, visitor); 131 } 132 public void postorder(Node<E> node, Visitor<E> visitor) { 133 if (node == null || visitor.stop) return; 134 // 左 135 postorder(node.left, visitor); 136 // 右 137 postorder(node.right, visitor); 138 // 根 139 if (visitor.stop) return; 140 visitor.stop = visitor.visit(node.element); 141 } 142 143 /** 144 * 层次遍历 145 */ 146 public void levelOrder(Visitor<E> visitor) { 147 if (root == null || visitor.stop) return; 148 Queue<Node<E>> queue = new LinkedList<>(); // 队列 149 queue.offer(root); 150 151 while (!queue.isEmpty()) { 152 Node<E> node = queue.poll(); 153 if (visitor.visit(node.element)) return; 154 155 if (node.left != null) { 156 queue.offer(node.left); 157 } 158 if (node.right != null) { 159 queue.offer(node.right); 160 } 161 } 162 } 163 164 /** 165 * 求树的高度(递归) 166 */ 167 public int height1() { 168 return height1(root); 169 } 170 public int height1(Node<E> node) { 171 if (node == null) return 0; 172 return 1 + Math.max(height1(node.left), height1(node.right)); 173 } 174 175 /** 176 * 求树的高度高度(迭代) 177 */ 178 public int height() { 179 if (root == null) return 0; 180 int levelSize = 1; // 存储每一层的元素数量 181 int height = 0; // 树的高度 182 Queue<Node<E>> queue = new LinkedList<>(); 183 queue.offer(root); 184 185 while (!queue.isEmpty()) { 186 Node<E> node = queue.poll(); 187 levelSize--; 188 if (node.left != null) { 189 queue.offer(node.left); 190 } 191 if (node.right != null) { 192 queue.offer(node.right); 193 } 194 if (levelSize == 0) { // 即将要访问下一层 195 levelSize = queue.size(); 196 height++; 197 } 198 } 199 return height; 200 } 201 202 /** 203 * 是否是完全二叉树 204 */ 205 public boolean isComplete() { 206 if (root == null) return false; 207 208 Queue<Node<E>> queue = new LinkedList<>(); 209 queue.offer(root); 210 211 // leaf代表是否要求后面都是叶子节点 212 // 比如遍历到一个节点 left == null && right == null 213 // 或者是 left != null && right == null 214 // 则要求这个节点后面的节点都是叶子节点 215 boolean leaf = false; 216 while (!queue.isEmpty()) { 217 Node<E> node = queue.poll(); 218 // 要求是叶子结点,但是当前节点不是叶子结点 219 if (leaf && !node.isLeaf()) { 220 return false; 221 } 222 if (node.left != null) { 223 queue.offer(node.left); 224 } else if (node.right != null) { 225 // node.left == null && node.right != null 226 return false; 227 } 228 if (node.right != null) { 229 queue.offer(node.right); 230 } else { 231 // node.left == null && node.right == null 232 // node.left != null && node.right == null 233 leaf = true; // 要求后面都是叶子节点 234 } 235 } 236 return true; 237 } 238 239 /** 240 * 前驱节点: 中序遍历时的前一个节点 241 * 求前驱节点 242 */ 243 protected Node<E> predecessor(Node<E> node) { 244 if (node == null) return null; 245 246 // 前驱节点在左子树中(left.right.right.right....) 247 Node<E> p = node.left; 248 if (p != null) { 249 // 左子树不为空,则找到它的最右节点 250 while (p.right != null) { 251 p = p.right; 252 } 253 return p; 254 } 255 256 // 能来到这里说明左子树为空, 则从父节点、祖父节点中寻找前驱节点 257 // 当父节点不为空, 且某节点为父节点的左子节点 258 // 则顺着父节点找, 直到找到【某结点为父节点或祖父节点的右子树中】时 259 while (node.parent != null && node.parent.left == node) { 260 node = node.parent; 261 } 262 263 // 来到这里有以下两种情况: 264 // node.parent == null 无前驱, 说明是根结点 265 // node.parent...right == node 找到【某结点为父节点或祖父节点的右子树中】 266 // 那么父节点就是某节点的前驱节点 267 return node.parent; 268 } 269 270 /** 271 * 后继节点: 中序遍历时的后一个节点 272 * 求后继节点 273 */ 274 protected Node<E> successor(Node<E> node) { 275 if (node == null) return null; 276 // 后继节点与前驱节点正好相反 277 278 // 后继节点在右子树中(node.right.left.left...) 279 if (node.right != null) { 280 Node<E> p = node.right; 281 while (p.left != null) { 282 p = p.left; 283 } 284 return p; 285 } 286 287 // 来到这里说明没有右节点, 则从父节点、祖父节点中寻找后继节点 288 // 当父节点不为空, 且某节点为父节点的右子节点 289 // 则顺着父节点找, 直到找到【某结点在父节点或祖父节点的左子树中】时 290 while (node.parent != null && node.parent.right == node) { 291 node = node.parent; 292 } 293 294 // 来到这里有以下两种情况: 295 // node.parent == null 无前驱,说明是根结点 296 // node.parent.left == node 找到【某结点在父节点或祖父节点的左子树中】 297 // 那么父节点就是某节点的后继节点 298 return node.parent; 299 } 300 301 /** 302 * 创建节点的方法,用于给AVL树创建节点 303 */ 304 protected Node<E> createNode(E element, Node<E> parent){ 305 return new Node<>(element, parent); // 默认返回一个通用节点 306 } 307 308 /** 309 * BinaryTreeInfo 工具,用来打印二叉树 310 */ 311 @Override 312 public Object root() { 313 return root; 314 } 315 316 @Override 317 public Object left(Object node) { 318 return ((Node<E>) node).left; 319 } 320 321 @Override 322 public Object right(Object node) { 323 return ((Node<E>) node).right; 324 } 325 326 @Override 327 public Object string(Object node) { 328 Node<E> myNode = (Node<E>) node; 329 String parentStr = "null"; 330 if (myNode.parent != null) { 331 parentStr = myNode.parent.element.toString(); 332 } 333 return myNode.element + "_p(" + parentStr + ")"; 334 } 335 }
3.二叉搜索树
1 package DataStructure.Tree_new; 2 3 import java.util.Comparator; 4 5 public class BST<E> extends BinaryTree<E> { // 继承通用二叉树类 6 7 // 比较器,根据传入的比较器实现 compareTo() 方法 8 private Comparator<E> comparator; 9 10 public BST(Comparator<E> comparator) { // 可以传一个比较器 11 this.comparator = comparator; 12 } 13 14 public BST() { // 不传比较器,相当于传入一个 null 15 this(null); // 16 } 17 18 /** 19 * 是否包含某元素 20 */ 21 public boolean contains(E element) { 22 return node(element) != null; 23 } 24 25 /** 26 * 添加元素 27 */ 28 public void add(E element) { 29 elementNotNullCheck(element); // 不能传入空节点 30 31 // 传入第一个节点, 若根节点为null, 则该节点为根节点 32 if (root == null) { 33 root = new Node<>(element, null); 34 size++; 35 return; 36 } 37 38 // 添加的不是第一个节点, 找到父节点 39 Node<E> node = root; 40 Node<E> parent = root; 41 int cmp = 0; 42 while (node != null) { 43 parent = node; // 父节点 44 // 比较【传入节点的元素值】与【父节点的元素值】 45 cmp = compareTo(element, node.element); 46 if (cmp > 0) { // 传入节点比父节点要大, 往右 47 node = node.right; 48 } else if (cmp < 0) { // 传入节点比父节点要小, 往左 49 node = node.left; 50 } else { // 相等, 最好是覆盖掉, 也可以采取其他操作, 看业务需求 51 node.element = element; 52 return; 53 } 54 } 55 56 // 上面只是找到了要添加位置的父节点, 下面要将元素添加进去 57 Node<E> newNode = new Node<>(element, parent); 58 if (cmp > 0) { 59 parent.right = newNode; 60 } else { 61 parent.left = newNode; 62 } 63 size++; 64 } 65 66 /** 67 * 根据传入的值删除元素 68 */ 69 public void remove(E element) { 70 remove(node(element)); 71 } 72 // 根据节点删除元素 73 private void remove(Node<E> node) { 74 if (node == null) return; 75 76 size--; 77 78 if (node.hasTwoChildren()) { // 度为2的节点 79 // 找到后继节点 80 Node<E> s = successor(node); 81 // 用后继节点的值覆盖度为2的节点的值 82 node.element = s.element; 83 // 删除后继节点 84 node = s; 85 } 86 87 // 删除node节点(node的度必然是1或者0) 88 Node<E> replacement = node.left != null ? node.left : node.right; 89 90 if (replacement != null) { // node是度为1的节点 91 // 更改parent 92 replacement.parent = node.parent; 93 // 更改parent的left、right的指向 94 if (node.parent == null) { // node是度为1的节点并且是根节点 95 root = replacement; 96 } else if (node == node.parent.left) { 97 node.parent.left = replacement; 98 } else { // node == node.parent.right 99 node.parent.right = replacement; 100 } 101 } else if (node.parent == null) { // node是叶子节点并且是根节点 102 root = null; 103 } else { // node是叶子节点,但不是根节点 104 if (node == node.parent.left) { 105 node.parent.left = null; 106 } else { // node == node.parent.right 107 node.parent.right = null; 108 } 109 } 110 } 111 112 // 根据元素值获取节点元素 113 private Node<E> node(E element) { 114 elementNotNullCheck(element); 115 116 Node<E> node = root; 117 while (node != null) { 118 int cmp = compareTo(element, node.element); 119 if (cmp < 0) { 120 node = node.left; 121 } else if (cmp > 0) { 122 node = node.right; 123 } else { // cmp == 0 124 return node; 125 } 126 } 127 return null; 128 } 129 130 // 节点元素比较 131 private int compareTo(E e1, E e2) { 132 if (comparator != null) { // 传入比较器则通过比较器比较 133 return comparator.compare(e1, e2); 134 } 135 // 没传比较器,元素内部必须自行实现了 Comparable 接口 136 return ((Comparable<E>) e1).compareTo(e2); 137 } 138 139 // 检测传入的节点是否为空 140 private void elementNotNullCheck(E element) { 141 if (element == null) { // 不能传入空节点 142 throw new IllegalArgumentException("element must not null"); 143 } 144 } 145 146 }