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 }

 

posted @ 2016-04-19 21:03  回看欧洲  阅读(236)  评论(0编辑  收藏  举报