键值表

来源:互联网 发布:sql count(1) 编辑:程序博客网 时间:2022/05/28 05:20

什么是键值表

键值表是键值对集合,类似字典,支持存入键值对,按键查值等操作。

对外接口

  • public void put(Key key, Value val);
  • public Value get(Key key);
  • public boolean contains(Key key);
  • public Value remove(Key key);
  • public int size();
  • public boolean isEmpty();

接口代码

public interface IMap<Key, Value> {    /**     * 存入键值对     *      * @param key     *            键     * @param value     *            值     */    public void put(Key key, Value value);    /**     * 按鍵查值     *      * @param key     *            鍵     * @return 值     */    public Value get(Key key);    /**     * 判断是否包含某键     *      * @param key     *            键     * @return <code>true</code> 若包含;否则,<code>false</code>     */    public boolean contains(Key key);    /**     * 删除键为key的键值对     *      * @param key     *            键     */    public Value remove(Key key);    /**     * 返回键值对个数     *      * @return 键值对个数     */    public int size();    /**     * 判断键值表是否为空     *      * @return <code>true</code> 如果键值表为空;否则,<code>false</code>。     */    public boolean isEmpty();}

初级实现

package com.gmail.dailyefforts.ds;import java.util.HashMap;import java.util.Map;import java.util.Random;public class SimpleLinkedMap<Key, Value> implements IMap<Key, Value>{    private class Node {        private Node prev;        private Key key;        private Value val;        private Node next;        public Node(Node prev, Key key, Value val, Node next) {            this.prev = prev;            this.key = key;            this.val = val;            this.next = next;        }        @Override        public String toString() {            return String.format("%s=%s", String.valueOf(key),                    String.valueOf(val));        }    }    private int size;    private Node first;    private Node last;    @Override    public void put(Key key, Value val) {        for (Node x = first; x != null; x = x.next) {            if (key.equals(x.key)) {                x.val = val;                return;            }        }        Node oldLast = last;        last = new Node(last, key, val, null);        if (oldLast != null) {            oldLast.next = last;        }        size++;        if (first == null) {            first = last;        }    }    @Override    public Value remove(Key key) {        for (Node x = first; x != null; x = x.next) {            if (key.equals(x.key)) {                if (x.prev == null) {                    first = x.next;                } else {                    x.prev.next = x.next;                }                if (x.next == null) {                    last = x.prev;                } else {                    x.next.prev = x.prev;                }                size--;                return x.val;            }        }        return null;    }    @Override    public boolean contains(Key key) {        return get(key) != null;    }    @Override    public Value get(Key key) {        for (Node x = first; x != null; x = x.next) {            if (key.equals(x.key)) {                return x.val;            }        }        return null;    }    @Override    public int size() {        return size;    }    @Override    public boolean isEmpty() {        return size() == 0;    }    @Override    public String toString() {        StringBuilder builder = new StringBuilder();        builder.append('{');        for (Node x = first; x != null; x = x.next) {            builder.append(x);            if (x.next != null) {                builder.append(", ");            }        }        builder.append('}');        return builder.toString();    }    public static void main(String[] args) {        final int N = 100 * 100;        SimpleLinkedMap<Integer, String> map = new SimpleLinkedMap<>();        Map<Integer, String> map2 = new HashMap<>();        for (int i = 0; i < N; i++) {            Integer key = Integer.valueOf(i);            String value = "item-" + i;            map2.put(key, value);            map.put(key, value);        }//      System.out.println(map2);//      System.out.println(map);        Random random = new Random(System.currentTimeMillis());        for (int i = 0; i < N / 2; i++) {            final int key = random.nextInt(N);            final String a = map.remove(key);            final String b = map2.remove(key);            if (a == null) {                assert (b == null);            } else {                assert (a.equals(b));            }        }        assert(map.size() == map2.size());        for (int i = 0; i < N; i++) {            final String a = map.get(i);            final String b = map2.get(i);            if (a == null) {                assert (b == null);            } else {                assert (a.equals(b));            }        }    }}

Hash实现

在上面的初级实现中,每次查询都要遍历了整个字典,效率为O(n)。现实中,我们从字典中查询某个单词时,我们借助索引来提高效率,而不是从该字典收录的第一个词开始逐个遍历整个字典。
我们可以利用hash来建立索引,遇到索引相同时再用链表存储。

package com.gmail.dailyefforts.ds;import java.util.HashMap;import java.util.Map;import java.util.Random;public class MyHashMap<Key, Value> implements IMap<Key, Value> {    private int size;    private static final int M = 100 * 100;    private SimpleLinkedMap<Key, Value>[] a = (SimpleLinkedMap<Key, Value>[]) new SimpleLinkedMap[M];    @Override    public void put(Key key, Value value) {        SimpleLinkedMap<Key, Value> map = map(key);        if (!map.contains(key)) {            size++;        }        map.put(key, value);    }    private int hash(Key key) {        // [0, M]        return key.hashCode() & 0x7fffffff % M;    }    private SimpleLinkedMap<Key, Value> map(Key key) {        int index = hash(key);        if (a[index] == null) {            a[index] = new SimpleLinkedMap<Key, Value>();        }        return a[index];    }    @Override    public Value get(Key key) {        return map(key).get(key);    }    @Override    public boolean contains(Key key) {        return map(key).contains(key);    }    @Override    public Value remove(Key key) {        Value value = map(key).remove(key);        if (value != null) {            size--;        }        return value;    }    @Override    public int size() {        return this.size;    }    @Override    public String toString() {        return super.toString();    }    @Override    public boolean isEmpty() {        return size() == 0;    }    public static void main(String[] args) {        final int N = 100 * 100 * 100;        MyHashMap<Integer, String> map = new MyHashMap<>();        Map<Integer, String> mapRef = new HashMap<>();        for (int i = 0; i < N; i++) {            Integer key = Integer.valueOf(i);            String value = "item-" + i;            map.put(key, value);            mapRef.put(key, value);        }        assert(map.size() == mapRef.size());        Random random = new Random(System.currentTimeMillis());        for (int i = 0; i < N / 2; i++) {            final int key = random.nextInt(N);            assert (map.contains(key) == mapRef.containsKey(key));            final String a = map.remove(key);            final String b = mapRef.remove(key);            if (a == null) {                assert (b == null);            } else {                assert (a.equals(b));            }        }        assert (map.size() == mapRef.size());        for (int i = 0; i < N; i++) {            final int key = random.nextInt(N);            final String a = map.get(key);            final String b = mapRef.get(key);            if (a == null) {                assert (b == null);            } else {                assert (a.equals(b));            }        }        System.out.println("test passed");    }}
0 0