• 键值表


    什么是键值表

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

    对外接口

    • 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");
        }
    
    }
    
  • 相关阅读:
    部分Gamefest 2011的材料已经放出
    glloader 3.7.0发布,支持最新的OpenGL 4.2
    关于D3D11,你必须了解的几件事情(二)
    不争气的geometry shader
    day2:数据类型、字符编码、文件处理
    jquery 常用
    Eclipse插件开发之EasyExplorer
    如何切图&PS切图&网页切图
    PS切图的相关技巧
    Eclipse快捷键大全(转载)
  • 原文地址:https://www.cnblogs.com/mthoutai/p/7232102.html
Copyright © 2020-2023  润新知