1. 程式人生 > >鍵值表

鍵值表

scrip ride pac else data -s code == spl

什麽是鍵值表

鍵值表是鍵值對集合,相似字典,支持存入鍵值對,按鍵查值等操作。

對外接口

  • 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(); }

0基礎實現

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實現

在上面的0基礎實現中。每次查詢都要遍歷了整個字典。效率為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");
    }

}

鍵值表