12、二分查找+二叉搜索树
二分查找要求使用顺序数组,此处用例为递增的int数组
1 package ren.laughing.datastructure.algorithm; 2 3 /** 4 * 5 * @author Laughing_Lz 6 * @time 2016年4月19日 7 */ 8 public class Search { 9 /** 10 * 二分查找/折半查找(此处使用增序数组) 11 * 12 * @param s 13 * 增序的数组 14 * @param low 15 * 最小元素下标 16 * @param high 17 * 最大元素下标 18 * @param key 19 * 要查找元素 20 */ 21 public int binSearch(int[] s, int low, int high, int key) { 22 // 递归查询 23 if (low > high) { 24 return -1; 25 } 26 int middle = (low + high) / 2; 27 if (key > s[middle]) { 28 middle++; 29 return binSearch(s, middle, high, key); 30 } else if (key < s[middle]) { 31 middle--; 32 return binSearch(s, low, middle, key); 33 } else { 34 return middle; 35 } 36 } 37 38 public static void main(String[] args) { 39 Search search = new Search(); 40 int[] s = new int[] { 2, 11, 22, 33, 44, 55, 66 }; 41 int result = search.binSearch(s, 0, 6, 42); 42 System.out.println(result); 43 } 44 }
关于二叉搜索树,实现功能有:search, min,max,getSuccessor,getPredecessor,insert,remove
1 package ren.laughing.datastructure.baseImpl; 2 3 import java.util.Comparator; 4 5 import ren.laughing.datastructure.base.Node; 6 7 /** 8 * 二叉搜索树的实现 ★该二叉搜索树按中序遍历,元素增序 9 * 10 * @author Laughing_Lz 11 * @time 2016年4月19日 12 */ 13 public class BSTree extends BinaryTreeLinked implements Comparator<Integer> { 14 private BinTreeNode root;// 树的根结点 15 private BinTreeNode startBN;// ★待平衡出发点 16 17 public BSTree() { 18 super(); 19 } 20 21 public BSTree(BinTreeNode root) { 22 super(); 23 this.root = root; 24 } 25 26 /** 27 * 查找元素在二叉搜索树中的结点位置 28 * 29 * @param obj 30 * @return 31 */ 32 public Node serch(Object obj) { 33 return BSTreeRecursion(root, obj); 34 } 35 36 /** 37 * 查找二叉搜索树中元素位置的递归算法 38 * 39 * @param root 40 * @param obj 41 * @return 42 */ 43 private Node BSTreeRecursion(BinTreeNode root, Object obj) { 44 if (root == null) { 45 return null; 46 } 47 switch (compare((Integer) obj, (Integer) root.getData())) { 48 case 0:// 等于 49 return root; 50 case -1:// 小于 51 return BSTreeRecursion(root.getLChild(), obj); 52 default:// 大于 53 return BSTreeRecursion(root.getRChild(), obj); 54 } 55 } 56 57 /** 58 * 获取以btn为根的二叉搜索树最小元素位置结点 59 * 60 * @param btn 61 * @return 62 */ 63 public Node min(BinTreeNode btn) { 64 if (btn != null) { 65 while (btn.hasLChild()) { 66 btn = btn.getLChild(); 67 } 68 } 69 return btn; 70 } 71 72 /** 73 * 获取以btn为根的二叉搜索树最大元素位置结点 74 * 75 * @param btn 76 * @return 77 */ 78 public Node max(BinTreeNode btn) { 79 if (btn != null) { 80 while (btn.hasRChild()) { 81 btn = btn.getRChild(); 82 } 83 } 84 return btn; 85 } 86 87 /** 88 * 获取某结点btn在中序遍历序列中的后续结点 89 * 90 * @param btn 91 * @return 92 */ 93 public BinTreeNode getSuccessor(BinTreeNode btn) { 94 if (btn == null) { 95 return null; 96 } 97 if (btn.hasRChild()) {// 1、如果有右子树,后续结点是右子树中元素最小的结点 98 return (BinTreeNode) min(btn.getRChild()); 99 } 100 while (btn.isRChild()) {// 2、如果没有右子树,且存在后续结点,则是从该结点到root根结点路径上第一个作为左孩子结点的父结点 101 btn = btn.getParent(); 102 } 103 return btn.getParent();// 2&3、若没右子树,且不是右孩子,则后续结点是此结点的父结点 104 } 105 106 /** 107 * 获取某结点btn在中序遍历序列中的前驱结点 108 * 109 * @param btn 110 * @return 111 */ 112 public BinTreeNode getPredecessor(BinTreeNode btn) { 113 if (btn == null) { 114 return null; 115 } 116 if (btn.hasLChild()) {// 1、如果有左子树,前驱结点是左子树中元素最大的结点 117 return (BinTreeNode) max(btn.getLChild()); 118 } 119 while (btn.isLChild()) {// 2、如果没有左子树,且存在前驱结点,则是从该结点到root根节点路径上第一个作为右孩子结点的父结点 120 btn = btn.getParent(); 121 } 122 return btn.getParent();// 2&3、若没左子树,且不是左孩子,则前驱结点是此结点的父结点 123 } 124 125 /** 126 * 插入元素,只能插在叶子结点 127 * 128 * @param obj 129 */ 130 public void insert(Object obj) { 131 BinTreeNode p = null; 132 BinTreeNode current = root; 133 while (current != null) {// 找到待插入位置 134 p = current; 135 if (compare((Integer) obj, (Integer) current.getData()) < 0) {// 小于 136 current = current.getLChild(); 137 } else {// 大于 138 current = current.getRChild(); 139 } 140 } 141 startBN = p;// 待平衡出发点 ★暂时不考虑 142 if (p == null) { 143 root = new BinTreeNode(obj);// ★感觉没意义? 144 } else if (compare((Integer) obj, (Integer) p.getData()) < 0) { 145 p.setLChild(new BinTreeNode(obj)); 146 } else { 147 p.setRChild(new BinTreeNode(obj)); 148 } 149 } 150 151 /** 152 * 删除结点:三种情况 第一种,该结点是叶子结点,直接删除 第二种,该结点只有左孩子或者右孩子,令其左/右孩子为其父结点的左/右孩子即可 153 * 第三种,该结点既有左孩子又有右孩子,需要使用前驱/后续结点的元素替换要删除结点元素,再按第一/二种情况删除替换的结点 154 * 155 * @param obj 156 * @return 157 */ 158 public Object remove(Object obj) { 159 BinTreeNode btn = (BinTreeNode) BSTreeRecursion(root, obj); 160 if (btn == null) {// 查找不到该元素 161 return null; 162 } 163 BinTreeNode del = null; // 待删结点 164 BinTreeNode subT = null; // ★待删结点的子树 165 if (!btn.hasLChild() || !btn.hasRChild()) // 若该结点没有左孩子或没有右孩子,或者该结点没有孩子 166 del = btn;// 则要删除的结点即为该结点本身 167 else {// 若该结点既有左孩子又有右孩子,则先用前驱结点的元素(后续结点也可)替换,再将替换结点删除 168 del = getPredecessor(btn);// 要删除的结点为替换结点 169 Object old = btn.getData(); 170 btn.setData(del.getData());// ★此处使用前驱结点的元素替换 171 del.setData(old);// ★此处为统一将移除元素返回return★ 172 } 173 startBN = del.getParent(); // ★待平衡出发点,暂不考虑 174 // ★此时待删结点只有左子树或右子树 why? 175 if (del.hasLChild()) { 176 subT = del.getLChild(); 177 } else { 178 subT = del.getRChild(); 179 } 180 if (del == root) { // 若待删结点为根 ★★ 181 if (subT != null) { 182 subT.server();// 与原根结点断开 183 } 184 root = subT; 185 } else if (subT != null) {// 若待删结点不为根结点且不是叶子结点 186 if (del.isLChild()) { 187 del.getParent().setLChild(subT); 188 } else { 189 del.getParent().setRChild(subT); 190 } 191 } else {// 若待删结点为叶子结点 192 del.server(); 193 } 194 return del.getData();// 返回删除结点的元素(注意第三种情况) 195 } 196 197 /** 198 * 实现Comparator接口 默认数据元素(getData)为int类型 199 */ 200 @Override 201 public int compare(Integer o1, Integer o2) { 202 return o1.compareTo(o2); 203 } 204 }
—————————————————————————————————————行走在人猿的并行线——Laughing_Lz