zoukankan      html  css  js  c++  java
  • HashTable 实现

    根据冲突解决的不同,可分为seperate chaining hash table, linear probing hash table, quadratic probing hash table.

    自己实现的最简单饿 seperate chaining hash table。

    package ADT;
    
    import java.util.LinkedList;
    /**
     * 自己实现的屌丝版的MySeperateChainingHashTable,
     * 
     * @author jd
     *
     * @param <K>
     * @param <V>
     */
    public class MySeperateChainingHashTable<K, V> {
        private static int M = 10;
        private LinkedList<Entry<K, V>>[] items;
    
        public MySeperateChainingHashTable() {
            items = (LinkedList<Entry<K, V>>[]) (new LinkedList[M]);
            for (int i = 0; i < M; i++) {
                items[i] = new LinkedList<Entry<K, V>>();
            }
        }
    
        public void put(K key, V value) {
            int idx = hash(key);
            LinkedList<Entry<K, V>> list = items[idx];
            for (Entry<K, V> each : list) {
                if (each.key.equals(key)) {
                    each.value = value;
                    return;
                }
            }
    
            list.add(new Entry<K,V>(key, value));
        }
    
        public V get(K key) {
            int idx = hash(key);
            LinkedList<Entry<K, V>> list = items[idx];
            for (Entry<K, V> each : list) {
                if (each.key.equals(key)) {
                    return each.value;
                }
            }
    
            return null;
        }
    
        private int hash(K key) {
            int res = key.hashCode();
            if (res < 0)
                res += M;
            return res % M;
        }
    
        private static class Entry<K, V> {
            public K key;
            public V value;
    
            public Entry(K key, V value) {
                this.key = key;
                this.value = value;
            }
    
        }
    
        public static void main(String[] args) {
            MySeperateChainingHashTable<Integer, String> hashtable = new MySeperateChainingHashTable<Integer, String>();
    
            for (int i = 0; i < 100; i++) {
                hashtable.put(i, i + "" + i);
            }
    
            for (int i = 0; i < 100; i++) {
                System.out.println(hashtable.get(i));
            }
    
        }
    
    }
    View Code

    教材里的范例代码:seperate chaining hash table

    package ADT;
    
    import java.util.LinkedList;
    import java.util.List;
    
    // SeparateChaining Hash table class
    //
    // CONSTRUCTION: an approximate initial size or default of 101
    //
    // ******************PUBLIC OPERATIONS*********************
    // void insert( x )       --> Insert x
    // void remove( x )       --> Remove x
    // boolean contains( x )  --> Return true if x is present
    // void makeEmpty( )      --> Remove all items
    
    /**
     * Separate chaining table implementation of hash tables. Note that all
     * "matching" is based on the equals method.
     * 
     * @author Mark Allen Weiss
     */
    public class SeparateChainingHashTable<T> {
        /**
         * Construct the hash table.
         */
        public SeparateChainingHashTable() {
            this(DEFAULT_TABLE_SIZE);
        }
    
        /**
         * Construct the hash table.
         * 
         * @param size
         *            approximate table size.
         */
        public SeparateChainingHashTable(int size) {
            theLists = new LinkedList[nextPrime(size)];
            for (int i = 0; i < theLists.length; i++)
                theLists[i] = new LinkedList<>();
        }
    
        /**
         * Insert into the hash table. If the item is already present, then do
         * nothing.
         * 
         * @param x
         *            the item to insert.
         */
        public void insert(T x) {
            List<T> whichList = theLists[myhash(x)];
            if (!whichList.contains(x)) {
                whichList.add(x);
    
                // Rehash; see Section 5.5
                if (++currentSize > theLists.length)
                    rehash();
            }
        }
    
        /**
         * Remove from the hash table.
         * 
         * @param x
         *            the item to remove.
         */
        public void remove(T x) {
            List<T> whichList = theLists[myhash(x)];
            if (whichList.contains(x)) {
                whichList.remove(x);
                currentSize--;
            }
        }
    
        /**
         * Find an item in the hash table.
         * 
         * @param x
         *            the item to search for.
         * @return true if x isnot found.
         */
        public boolean contains(T x) {
            List<T> whichList = theLists[myhash(x)];
            return whichList.contains(x);
        }
    
        /**
         * Make the hash table logically empty.
         */
        public void makeEmpty() {
            for (int i = 0; i < theLists.length; i++)
                theLists[i].clear();
            currentSize = 0;
        }
    
        /**
         * A hash routine for String objects.
         * 
         * @param key
         *            the String to hash.
         * @param tableSize
         *            the size of the hash table.
         * @return the hash value.
         */
        public static int hash(String key, int tableSize) {
            int hashVal = 0;
    
            for (int i = 0; i < key.length(); i++)
                hashVal = 37 * hashVal + key.charAt(i);
    
            hashVal %= tableSize;
            if (hashVal < 0)
                hashVal += tableSize;
    
            return hashVal;
        }
    
        private void rehash() {
            List<T>[] oldLists = theLists;
    
            // Create new double-sized, empty table
            theLists = new List[nextPrime(2 * theLists.length)];
            for (int j = 0; j < theLists.length; j++)
                theLists[j] = new LinkedList<>();
    
            // Copy table over
            currentSize = 0;
            for (List<T> list : oldLists)
                for (T item : list)
                    insert(item);
        }
    
        private int myhash(T x) {
            int hashVal = x.hashCode();
    
            hashVal %= theLists.length;
            if (hashVal < 0)
                hashVal += theLists.length;
    
            return hashVal;
        }
    
        private static final int DEFAULT_TABLE_SIZE = 101;
    
        /** The array of Lists. */
        private List<T>[] theLists;
        private int currentSize;
    
        /**
         * Internal method to find a prime number at least as large as n.
         * 
         * @param n
         *            the starting number (must be positive).
         * @return a prime number larger than or equal to n.
         */
        private static int nextPrime(int n) {
            if (n % 2 == 0)
                n++;
    
            for (; !isPrime(n); n += 2)
                ;
    
            return n;
        }
    
        /**
         * Internal method to test if a number is prime. Not an efficient algorithm.
         * 
         * @param n
         *            the number to test.
         * @return the result of the test.
         */
        private static boolean isPrime(int n) {
            if (n == 2 || n == 3)
                return true;
    
            if (n == 1 || n % 2 == 0)
                return false;
    
            for (int i = 3; i * i <= n; i += 2)
                if (n % i == 0)
                    return false;
    
            return true;
        }
    
        // Simple main
        public static void main(String[] args) {
            SeparateChainingHashTable<Integer> H = new SeparateChainingHashTable<>();
    
            long startTime = System.currentTimeMillis();
    
            final int NUMS = 2000000;
            final int GAP = 37;
    
            System.out.println("Checking... (no more output means success)");
    
            for (int i = GAP; i != 0; i = (i + GAP) % NUMS)
                H.insert(i);
            for (int i = 1; i < NUMS; i += 2)
                H.remove(i);
    
            for (int i = 2; i < NUMS; i += 2)
                if (!H.contains(i))
                    System.out.println("Find fails " + i);
    
            for (int i = 1; i < NUMS; i += 2) {
                if (H.contains(i))
                    System.out.println("OOPS!!! " + i);
            }
    
            long endTime = System.currentTimeMillis();
    
            System.out.println("Elapsed time: " + (endTime - startTime));
        }
    
    }
    View Code

    linear probing hash table,注意删除元素后,同一个cluster后面的元素都需要重新hash。

    package ADT;
    
    import java.util.LinkedList;
    import java.util.Queue;
    
    /*************************************************************************
     * Compilation: javac LinearProbingHashST.java Execution: java
     * LinearProbingHashST
     * 
     * Symbol table implementation with linear probing hash table.
     * 
     * % java LinearProbingHashST 128.112.136.11 208.216.181.15 null
     * 
     * 
     *************************************************************************/
    
    public class LinearProbingHashST<Key, Value> {
        private static final int INIT_CAPACITY = 4;
    
        private int N; // number of key-value pairs in the symbol table
        private int M; // size of linear probing table
        private Key[] keys; // the keys
        private Value[] vals; // the values
    
        // create an empty hash table - use 16 as default size
        public LinearProbingHashST() {
            this(INIT_CAPACITY);
        }
    
        // create linear proving hash table of given capacity
        public LinearProbingHashST(int capacity) {
            M = capacity;
            keys = (Key[]) new Object[M];
            vals = (Value[]) new Object[M];
        }
    
        // return the number of key-value pairs in the symbol table
        public int size() {
            return N;
        }
    
        // is the symbol table empty?
        public boolean isEmpty() {
            return size() == 0;
        }
    
        // does a key-value pair with the given key exist in the symbol table?
        public boolean contains(Key key) {
            return get(key) != null;
        }
    
        // hash function for keys - returns value between 0 and M-1
        private int hash(Key key) {
            return (key.hashCode() & 0x7fffffff) % M;
        }
    
        // resize the hash table to the given capacity by re-hashing all of the keys
        private void resize(int capacity) {
            LinearProbingHashST<Key, Value> temp = new LinearProbingHashST<Key, Value>(capacity);
            for (int i = 0; i < M; i++) {
                if (keys[i] != null) {
                    temp.put(keys[i], vals[i]);
                }
            }
            keys = temp.keys;
            vals = temp.vals;
            M = temp.M;
        }
    
        // insert the key-value pair into the symbol table
        public void put(Key key, Value val) {
            if (val == null) {
                delete(key);
                return;
            }
    
            // double table size if 50% full
            if (N >= M / 2)
                resize(2 * M);
    
            int i;
            for (i = hash(key); keys[i] != null; i = (i + 1) % M) {
                if (keys[i].equals(key)) {
                    vals[i] = val;
                    return;
                }
            }
            keys[i] = key;
            vals[i] = val;
            N++;
        }
    
        // return the value associated with the given key, null if no such value
        public Value get(Key key) {
            for (int i = hash(key); keys[i] != null; i = (i + 1) % M)
                if (keys[i].equals(key))
                    return vals[i];
            return null;
        }
    
        // delete the key (and associated value) from the symbol table
        public void delete(Key key) {
            if (!contains(key))
                return;
    
            // find position i of key
            int i = hash(key);
            while (!key.equals(keys[i])) {
                i = (i + 1) % M;
            }
    
            // delete key and associated value
            keys[i] = null;
            vals[i] = null;
    
            // rehash all keys in same cluster
            i = (i + 1) % M;
            while (keys[i] != null) {
                // delete keys[i] an vals[i] and reinsert
                Key keyToRehash = keys[i];
                Value valToRehash = vals[i];
                keys[i] = null;
                vals[i] = null;
                N--;
                put(keyToRehash, valToRehash);
                i = (i + 1) % M;
            }
    
            N--;
    
            // halves size of array if it's 12.5% full or less
            if (N > 0 && N <= M / 8)
                resize(M / 2);
    
            assert check();
        }
    
        // return all of the keys as in Iterable
        public Iterable<Key> keys() {
            Queue<Key> queue = new LinkedList<Key>();
            for (int i = 0; i < M; i++)
                if (keys[i] != null)
                    queue.add(keys[i]);
            return queue;
        }
    
        // integrity check - don't check after each put() because
        // integrity not maintained during a delete()
        private boolean check() {
    
            // check that hash table is at most 50% full
            if (M < 2 * N) {
                System.err.println("Hash table size M = " + M + "; array size N = " + N);
                return false;
            }
    
            // check that each key in table can be found by get()
            for (int i = 0; i < M; i++) {
                if (keys[i] == null)
                    continue;
                else if (get(keys[i]) != vals[i]) {
                    System.err.println("get[" + keys[i] + "] = " + get(keys[i]) + "; vals[i] = " + vals[i]);
                    return false;
                }
            }
            return true;
        }
    
        /***********************************************************************
         * Unit test client.
         ***********************************************************************/
        public static void main(String[] args) {
            LinearProbingHashST<String, Integer> st = new LinearProbingHashST<String, Integer>();
    
        }
    }
    View Code

    quadratic probing hash table.

    package ADT;
    
    // QuadraticProbing Hash table class
    //
    // CONSTRUCTION: an approximate initial size or default of 101
    //
    // ******************PUBLIC OPERATIONS*********************
    // bool insert( x )       --> Insert x
    // bool remove( x )       --> Remove x
    // bool contains( x )     --> Return true if x is present
    // void makeEmpty( )      --> Remove all items
    
    /**
     * Probing table implementation of hash tables. Note that all "matching" is
     * based on the equals method.
     * 
     * @author Mark Allen Weiss
     */
    public class QuadraticProbingHashTable<T> {
        /**
         * Construct the hash table.
         */
        public QuadraticProbingHashTable() {
            this(DEFAULT_TABLE_SIZE);
        }
    
        /**
         * Construct the hash table.
         * 
         * @param size
         *            the approximate initial size.
         */
        public QuadraticProbingHashTable(int size) {
            allocateArray(size);
            doClear();
        }
    
        /**
         * Insert into the hash table. If the item is already present, do nothing.
         * 
         * @param x
         *            the item to insert.
         */
        public boolean insert(T x) {
            // Insert x as active
            int currentPos = findPos(x);
            if (isActive(currentPos))
                return false;
    
            array[currentPos] = new HashEntry<>(x, true);
            theSize++;
    
            // Rehash; see Section 5.5
            if (++occupied > array.length / 2)
                rehash();
    
            return true;
        }
    
        /**
         * Expand the hash table.
         */
        private void rehash() {
            HashEntry<T>[] oldArray = array;
    
            // Create a new double-sized, empty table
            allocateArray(2 * oldArray.length);
            occupied = 0;
            theSize = 0;
    
            // Copy table over
            for (HashEntry<T> entry : oldArray)
                if (entry != null && entry.isActive)
                    insert(entry.element);
        }
    
        /**
         * Method that performs quadratic probing resolution.
         * 
         * @param x
         *            the item to search for.
         * @return the position where the search terminates.
         */
        private int findPos(T x) {
            int offset = 1;
            int currentPos = myhash(x);
    
            while (array[currentPos] != null && !array[currentPos].element.equals(x)) {
                currentPos += offset; // Compute ith probe
                offset += 2;
                if (currentPos >= array.length)
                    currentPos -= array.length;
            }
    
            return currentPos;
        }
    
        /**
         * Remove from the hash table.
         * 
         * @param x
         *            the item to remove.
         * @return true if item removed
         */
        public boolean remove(T x) {
            int currentPos = findPos(x);
            if (isActive(currentPos)) {
                array[currentPos].isActive = false;
                theSize--;
                return true;
            } else
                return false;
        }
    
        /**
         * Get current size.
         * 
         * @return the size.
         */
        public int size() {
            return theSize;
        }
    
        /**
         * Get length of internal table.
         * 
         * @return the size.
         */
        public int capacity() {
            return array.length;
        }
    
        /**
         * Find an item in the hash table.
         * 
         * @param x
         *            the item to search for.
         * @return the matching item.
         */
        public boolean contains(T x) {
            int currentPos = findPos(x);
            return isActive(currentPos);
        }
    
        /**
         * Return true if currentPos exists and is active.
         * 
         * @param currentPos
         *            the result of a call to findPos.
         * @return true if currentPos is active.
         */
        private boolean isActive(int currentPos) {
            return array[currentPos] != null && array[currentPos].isActive;
        }
    
        /**
         * Make the hash table logically empty.
         */
        public void makeEmpty() {
            doClear();
        }
    
        private void doClear() {
            occupied = 0;
            for (int i = 0; i < array.length; i++)
                array[i] = null;
        }
    
        private int myhash(T x) {
            int hashVal = x.hashCode();
    
            hashVal %= array.length;
            if (hashVal < 0)
                hashVal += array.length;
    
            return hashVal;
        }
    
        private static class HashEntry<T> {
            public T element; // the element
            public boolean isActive; // false if marked deleted
    
            public HashEntry(T e) {
                this(e, true);
            }
    
            public HashEntry(T e, boolean i) {
                element = e;
                isActive = i;
            }
        }
    
        private static final int DEFAULT_TABLE_SIZE = 101;
    
        private HashEntry<T>[] array; // The array of elements
        private int occupied; // The number of occupied cells
        private int theSize; // Current size
    
        /**
         * Internal method to allocate array.
         * 
         * @param arraySize
         *            the size of the array.
         */
        private void allocateArray(int arraySize) {
            array = new HashEntry[nextPrime(arraySize)];
        }
    
        /**
         * Internal method to find a prime number at least as large as n.
         * 
         * @param n
         *            the starting number (must be positive).
         * @return a prime number larger than or equal to n.
         */
        private static int nextPrime(int n) {
            if (n % 2 == 0)
                n++;
    
            for (; !isPrime(n); n += 2)
                ;
    
            return n;
        }
    
        /**
         * Internal method to test if a number is prime. Not an efficient algorithm.
         * 
         * @param n
         *            the number to test.
         * @return the result of the test.
         */
        private static boolean isPrime(int n) {
            if (n == 2 || n == 3)
                return true;
    
            if (n == 1 || n % 2 == 0)
                return false;
    
            for (int i = 3; i * i <= n; i += 2)
                if (n % i == 0)
                    return false;
    
            return true;
        }
    
        // Simple main
        public static void main(String[] args) {
            QuadraticProbingHashTable<String> H = new QuadraticProbingHashTable<>();
    
            long startTime = System.currentTimeMillis();
    
            final int NUMS = 2000000;
            final int GAP = 37;
    
            System.out.println("Checking... (no more output means success)");
    
            for (int i = GAP; i != 0; i = (i + GAP) % NUMS)
                H.insert("" + i);
            for (int i = GAP; i != 0; i = (i + GAP) % NUMS)
                if (H.insert("" + i))
                    System.out.println("OOPS!!! " + i);
            for (int i = 1; i < NUMS; i += 2)
                H.remove("" + i);
    
            for (int i = 2; i < NUMS; i += 2)
                if (!H.contains("" + i))
                    System.out.println("Find fails " + i);
    
            for (int i = 1; i < NUMS; i += 2) {
                if (H.contains("" + i))
                    System.out.println("OOPS!!! " + i);
            }
    
            long endTime = System.currentTimeMillis();
    
            System.out.println("Elapsed time: " + (endTime - startTime));
            System.out.println("H size is: " + H.size());
            System.out.println("Array size is: " + H.capacity());
        }
    
    }
    View Code
  • 相关阅读:
    Find the total area covered by two rectilinear rectangles in a 2D plane. 208MM
    signal num一个int数组,里面数值都是成对出现,只有一个是单独的,找出单独者。360ms
    BitAdd.ava 328mm
    如何评价代码好坏
    模拟手机文件管理之查看与选择功能
    ViewPager图片滑动轮换
    Selector的2种样式
    关于iOS开发开心蛙家长iOS端开发过程中的零碎知识归纳(4)---关于全局文件PCH的设置相关小知识
    关于iOS开发开心蛙家长iOS端开发过程中的零碎知识归纳(3)---主界面tabBar搭建
    关于iOS开发开心蛙家长iOS端开发过程中的零碎知识归纳(2)---关于进入App进入欢迎页面还是直接进入主页工具类的实现--之欢迎页的实现
  • 原文地址:https://www.cnblogs.com/jdflyfly/p/3841965.html
Copyright © 2011-2022 走看看