使用二叉搜索树实现一个简单的Map

Posted 小小的平庸

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用二叉搜索树实现一个简单的Map相关的知识,希望对你有一定的参考价值。

  之前看了刘新宇大大的《算法新解》有了点收获,闲来无事,便写了一个二叉搜索树实现的Map类。

java的Map接口有很多不想要的方法,自己定义了一个

1 public interface IMap<K, V> {
2     V get(K k);
3 
4     void put(K k, V v);
5 
6     V remove(K k);
7 }

具体实现:

 

  1 public class BSTree<K, V> implements IMap<K, V> {
  2     Entry<K, V> head = null;
  3 
  4     @Override
  5     public V get(K k) {
  6         return get(head, k);
  7     }
  8 
  9     private V get(Entry<K, V> node, K k) {
 10         if (node == null) {
 11             return null;
 12         }
 13         int compare = compare(node.key, k);
 14         if (compare == 0) {
 15             return node.value;
 16         } else if (compare > 1) {
 17             return get(node.right, k);
 18         } else {
 19             return get(node.left, k);
 20         }
 21     }
 22 
 23     @Override
 24     public void put(K k, V v) {
 25         //1.head is null
 26         if (head == null) {
 27             head = new Entry<>(k, v, null);
 28         }
 29         //2.head is not null
 30         else {
 31             put(head, k, v);
 32         }
 33     }
 34 
 35     private void put(Entry<K, V> node, K k, V v) {
 36         int compare = compare(node.key, k);
 37         if (compare == 0) {
 38             node.value = v;
 39         } else if (compare > 1) {
 40             if (node.right == null) {
 41                 node.right = new Entry<>(k, null, node);
 42             }
 43             put(node.right, k, v);
 44         } else {
 45             if (node.left == null) {
 46                 node.left = new Entry<>(k, null, node);
 47             }
 48             put(node.left, k, v);
 49         }
 50     }
 51 
 52     private int compare(K key, K k) {
 53         return ((Comparable) key).compareTo(k);
 54     }
 55 
 56     @Override
 57     public V remove(K k) {
 58         return remove(head, k);
 59     }
 60 
 61     private V remove(Entry<K, V> node, K k) {
 62         if (node == null) {
 63             return null;
 64         }
 65         int compare = compare(node.key, k);
 66         if (compare == 0) {
 67             //1.no child
 68             if (node.left == null && node.right == null) {
 69                 if (node.parent == null)
 70                     head = null;
 71                 else if (node == node.parent.left) {
 72                     node.parent.left = null;
 73                 } else {
 74                     node.parent.right = null;
 75                 }
 76                 return node.value;
 77             }
 78             //2.has right child
 79             else if (node.right != null) {
 80                 V oldValue = node.value;
 81                 Entry<K, V> newNode = findMin(node.right);
 82                 node.key=newNode.key;
 83                 node.value = newNode.value;
 84                 newNode.parent.right = null;
 85                 return oldValue;
 86             }
 87             //3.has no right child,has left child
 88             else{
 89                 V oldValue = node.value;
 90                 Entry<K, V> newNode = findMax(node.left);
 91                 node.key=newNode.key;
 92                 node.value = newNode.value;
 93                 newNode.parent.left= null;
 94                 return oldValue;
 95             }
 96 
 97         } else if (compare > 0) {
 98             return remove(node.right, k);
 99         } else {
100             return remove(node.left, k);
101         }
102     }
103 
104     private Entry<K, V> findMax(Entry<K, V> left) {
105         if (left.right == null) {
106             return left;
107         }else{
108             return findMax(left.right);
109         }
110     }
111 
112     private Entry<K, V> findMin(Entry<K, V> right) {
113         if (right.left == null) {
114             return right;
115         }else {
116             return findMin(right.left);
117         }
118     }
119 
120     class Entry<K, V> {
121         K key;
122         V value;
123         Entry<K, V> left;
124         Entry<K, V> right;
125         Entry<K, V> parent;
126 
127         private Entry(K key, V value, Entry<K, V> parent) {
128             this.key = key;
129             this.value = value;
130             left = null;
131             right = null;
132             this.parent = parent;
133         }
134     }
135 
136 }

 

测试的类:

 1 public class BSTreeTest {
 2     private static int write_num = 100_0000;
 3     private static int read_num = 100_0000;
 4 
 5     public static void main(String[] args) {
 6 //        IMap<String,Integer> map = new BSTree();
 7 //        Map<String, Integer> map = new TreeMap<>();
 8 //        Map<String, Integer> map = new HashMap<>();
 9         Map<String, Integer> map = new LinkedHashMap<>();
10         long start = System.nanoTime();
11         for (int i = 0; i < write_num; i++) {
12             map.put("" + i, i);
13         }
14         for (int i = 0; i < read_num; i++) {
15             Integer s = map.get(i + "");
16             assert s.equals(i);
17         }
18         for (int i = 0; i < read_num / 2; i++) {
19             map.remove(i + "");
20         }
21         for (int i = 0; i < read_num / 2; i++) {
22             Integer s = map.get(i + "");
23             assert s == null;
24         }
25         for (int i = read_num / 2; i < read_num / i++; i++) {
26             Integer s = map.get(i + "");
27             assert s.equals(i);
28         }
29         System.out.println("map cost:" + (System.nanoTime() - start));
30     }
31 }

 

在各自只运行一次的情况下测试数据如下:

map cost:1125174394 //myMap
map cost:812963047  //TreeMap
map cost:475993738  //HashMap
map cost:475993738  //LinkedHashMap

 

由于二叉搜索树没有自平衡机制,搜索的时间在O(n)与O(lgn)之间摇摆,因此对比java用红黑树实现的TreeMap时间O(lgn)要多上很多。 

以上是关于使用二叉搜索树实现一个简单的Map的主要内容,如果未能解决你的问题,请参考以下文章

182Java8利用二叉查找树实现Map

二叉搜索树

TreeMap和TreeSet即Java中利用二叉搜索树实现的Map和Set

C++ AVL树

容器————unordered_map

二叉查找树简单实现