二叉查找树的java实现

  1 package 查找;
  2 
  3 import java.util.ArrayList;
  4 import java.util.List;
  5 
  6 public class BST<Key extends Comparable<Key>, Value> {
  7     private class Node {
  8         private Key key; //
  9         private Value value;//
 10         private Node left, right; // 指向子树的链接
 11         private int n; // 以该节点为根的子树中的节点总数
 12 
 13         public Node(Key key, Value val, int n) {
 14             this.key = key;
 15             this.value = val;
 16             this.n = n;
 17         }
 18     }
 19 
 20     private Node root;
 21 
 22     public int size() {
 23         return size(root);
 24     }
 25 
 26     private int size(Node x) {
 27         if (x == null)
 28             return 0;
 29         else
 30             return x.n;
 31     }
 32 
 33     /**
 34      * 如果树是空的,则查找未命中 如果被查找的键小于根节点,则在左子树中继续查找 如果被查找的键大于根节点,则在右子树中继续查找
 35      * 如果被查找的键和根节点的键相等,查找命中
 36      * 
 37      * @param key
 38      * @return
 39      */
 40     public Value get(Key key) {
 41         return get(root, key);
 42     }
 43 
 44     private Value get(Node x, Key key) {
 45         if (x == null)
 46             return null;
 47         int cmp = key.compareTo(x.key);
 48         if (cmp < 0)
 49             return get(x.left, key);
 50         else if (cmp > 0)
 51             return get(x.right, key);
 52         else
 53             return x.value;
 54     }
 55 
 56     /**
 57      * 二叉查找树的一个很重要的特性就是插入的实现难度和查找差不多。 
 58      * 当查找到一个不存在与树中的节点(null)时,new 新节点,并将上一路径指向该节点
 59      * 
 60      * @param key
 61      * @param val
 62      */
 63     public void put(Key key, Value val) {
 64         root = put(root, key, val);
 65     }
 66 
 67     private Node put(Node x, Key key, Value val) {
 68         if (x == null)
 69             return new Node(key, val, 1);
 70         int cmp = key.compareTo(x.key);
 71         if (cmp < 0)
 72             x.left = put(x.left, key, val);
 73         else if (cmp > 0)
 74             x.right = put(x.right, key, val);
 75         else
 76             x.value = val;
 77         x.n = 1 + size(x.left) + size(x.right); // 要及时更新节点的子树数量
 78         return x;
 79     }
 80 
 81     public Key min() {
 82         return min(root).key;
 83     }
 84 
 85     private Node min(Node x) {
 86         if (x.left == null)
 87             return x;
 88         return min(x.left);
 89     }
 90 
 91     public Key max() {
 92         return max(root).key;
 93     }
 94 
 95     private Node max(Node x) {
 96         if (x.right == null)
 97             return x;
 98         return max(x.right);
 99     }
100 
101     /**
102      * 向下取整:找出小于等于该键的最大键
103      * 
104      * @param key
105      * @return
106      */
107     public Key floor(Key key) {
108         Node x = floor(root, key);
109         if (x == null)
110             return null;
111         else
112             return x.key;
113     }
114 
115     /**
116      * 如果给定的键key小于二叉查找树的根节点的键,那么小于等于key的最大键一定出现在根节点的左子树中
117      * 如果给定的键key大于二叉查找树的根节点,那么只有当根节点右子树中存在大于等于key的节点时,
118      * 小于等于key的最大键才会出现在右子树中,否则根节点就是小于等于key的最大键
119      * 
120      * @param x
121      * @param key
122      * @return
123      */
124     private Node floor(Node x, Key key) {
125         if (x == null)
126             return null;
127         int cmp = key.compareTo(x.key);
128         if (cmp == 0)
129             return x;
130         else if (cmp < 0)
131             return floor(x.left, key);
132         else {
133             Node t = floor(x.right, key);
134             if (t == null)
135                 return x;
136             else
137                 return t;
138         }
139     }
140 
141     /**
142      * 向上取整:找出大于等于该键的最小键
143      * 
144      * @param key
145      * @return
146      */
147     public Key ceiling(Key key) {
148         Node x = ceiling(root, key);
149         if (x == null)
150             return null;
151         else
152             return x.key;
153     }
154 
155     /**
156      * 如果给定的键key大于二叉查找树的根节点的键,那么大于等于key的最小键一定出现在根节点的右子树中
157      * 如果给定的键key小于二叉查找树的根节点,那么只有当根节点左子树中存在大于等于key的节点时,
158      * 大于等于key的最小键才会出现在左子树中,否则根节点就是大于等于key的最小键
159      * 
160      * @param x
161      * @param key
162      * @return
163      */
164     private Node ceiling(Node x, Key key) {
165         if (x == null)
166             return null;
167         int cmp = key.compareTo(x.key);
168         if (cmp == 0)
169             return x;
170         else if (cmp > 0) {
171             return ceiling(x.right, key);
172         } else {
173             Node t = floor(x.left, key);
174             if (t == null)
175                 return x;
176             else
177                 return t;
178         }
179     }
180 
181     /**
182      * 选择排名为k的节点
183      * 
184      * @param k
185      * @return
186      */
187     public Key select(int k) {
188         return select(root, k).key;
189     }
190 
191     private Node select(Node x, int k) {
192         if (x == null)
193             return null;
194         int t = size(x.left);
195         if (t > k)
196             return select(x.left, k);
197         else if (t < k)
198             return select(x.right, k - t - 1);// 根节点也要排除掉
199         else
200             return x;
201     }
202 
203     /**
204      * 查找给定键值的排名
205      * 
206      * @param key
207      * @return
208      */
209     public int rank(Key key) {
210         return rank(key, root);
211     }
212 
213     private int rank(Key key, Node x) {
214         if (x == null)
215             return 0;
216         int cmp = key.compareTo(x.key);
217         if (cmp < 0)
218             return rank(key, x.left);
219         else if (cmp > 0)
220             return 1 + size(x.left) + rank(key, x.right);
221         else
222             return size(x.left);
223     }
224     /**
225      * 删除最小键值对
226      */
227     public void deleteMin(){
228         root = deleteMin(root);
229     }
230     /**
231      * 不断深入根节点的左子树直到遇见一个空链接,然后将指向该节点的链接指向该结点的右子树
232      * 此时已经没有任何链接指向要被删除的结点,因此它会被垃圾收集器清理掉
233      * @param x
234      * @return
235      */
236     private Node deleteMin(Node x){
237         if(x.left == null) return x.right;
238         x.left = deleteMin(x.left);
239         x.n = 1 + size(x.left)+size(x.right);
240         return x;
241     }
242     
243     public void deleteMax(){
244         root = deleteMax(root);
245     }
246     private Node deleteMax(Node x){
247         if(x.right == null ) return x.left;
248         x.right = deleteMax(x.right);
249         x.n = size(x.left)+size(x.right) + 1;
250         return x;
251     }
252     
253     public void delete(Key key){
254         root = delete(root,key);
255     }
256     private Node delete(Node x, Key key){
257         if(x == null) return null;
258         int cmp = key.compareTo(x.key);
259         if(cmp < 0) x.left = delete(x.left,key);
260         else if(cmp > 0) x.right = delete(x.right,key);
261         else{
262             if(x.right == null) return x.left;
263             if(x.left == null ) return x.right;
264             /**
265              * 如果被删除节点有两个子树,将被删除节点暂记为t
266              * 从t的右子树中选取最小的节点x,将这个节点x的左子树设为t的左子树
267              * 这个节点x的右子树设为t的右子树中删除了最小节点的子树,这样就成功替换了t的位置
268              */
269             Node t = x;
270             x = min(t.right);
271             x.right = deleteMin(t.right);
272             x.left = t.left;
273         }
274         x.n = size(x.left) + size(x.right) +1;
275         return x;
276     }
277     
278     public String toString(){
279         StringBuilder sb = new StringBuilder();
280         toString(root,sb);
281         sb.deleteCharAt(sb.length()-1);
282         return sb.toString();
283     }
284     private void toString(Node x, StringBuilder sb){
285         if(x == null ) return;
286         toString(x.left,sb);
287         sb.append("<"+x.key+","+x.value+">,");
288         toString(x.right,sb);
289     }
290     
291     public List<Key> keys(){
292         return keys(min(),max());
293     }
294     public List<Key> keys(Key lo, Key hi){
295         List<Key> list = new ArrayList<Key>();
296         keys(root, list, lo, hi);
297         return list;
298     }
299     private void keys(Node x, List<Key> list, Key lo, Key hi){
300         if(x == null) return;
301         int cmplo = lo.compareTo(x.key);
302         int cmphi = hi.compareTo(x.key);
303         if(cmplo < 0 ) keys(x.left,list,lo,hi);
304         if(cmplo <= 0 && cmphi >= 0) list.add(x.key);
305         if(cmphi > 0 ) keys(x.right,list,lo,hi);
306     }
307     public static void main(String[] args){
308         BST<Integer,String> bst = new BST<Integer,String>();
309         bst.put(5, "e");
310         bst.put(1, "a");
311         bst.put(4, "d");
312         bst.put(9, "i");
313         bst.put(10, "j");
314         bst.put(2, "b");
315         bst.put(7, "g");
316         bst.put(3, "c");
317         bst.put(8, "h");
318         bst.put(6, "f");        
319         List<Integer> keys = bst.keys();
320         for(int key : keys){
321             System.out.print("<"+key+","+bst.get(key)+">,");
322         }
323         System.out.println();
324         bst.deleteMin();
325         System.out.println(bst.toString());
326         bst.deleteMax();
327         System.out.println(bst.toString());
328         bst.delete(7);
329         System.out.println(bst.toString());
330     }
331 }

 

树还是应该做成可视化的方便查看和调试,后续我将更新一个可视化的生成图的版本出来,恩,一定要记得这件事

posted @ 2017-08-09 19:29  evasean  阅读(634)  评论(0编辑  收藏  举报