普林斯顿·算法·PART I:HASH TABLES

1.哈希查询算法由两部分组成

哈希函数将要查询的键(key)转换成数组的角标。
面对的问题:多个不同的键(key)经过hash之后转换成相同数组角标
有两种方案解决冲突:各自的链(separate chaining)、直线的探测(linear probing)

2.单独的链

两个或多个键经过哈希函数得到相同的角标值。将这些碰撞的项链接到单独的链表中,这种方法称之为单独的链(separate chaining)。

(1) 通过hash函数发现那个列表包含key;

(2)按照顺序列表的顺序查询key;

3.直线的探查

另一个实现哈表的方法是将N个键值对存放在一个长度为M(M>N)的哈希表中,依靠表中的空元素项去解决冲突。这样的方法被称为**开放寻址(open-addressing)**的哈希方法。

最简单的开发寻址方法被称之为直线的探查(linear probing): 当这儿有一个冲突(通过哈希函数得到的表格角标已经被其他不同的key所占用),那么我们就需要检查表格中下一个项(将角标加1)。

**直线的探查(linear probing)**会遇到三种情况:

键等于查询的键:键存在
空位置(这个角标上没有键):没有查到
键不等于查询的键:试着查询下一个

该算法的实现思路如下:

通过哈希函数计算出键(key0)所在表格的角标,检查查询到的键(key)是否和刚做哈希函数的键(key0)相等,继续(通过增加角标,当达到表格结尾的时候就返回表格的头)直到查到键(key0)或者查到一个空的表格项。
HashFunctionTest.java

package com.hef.algorithms.chapter3.item34;

/**
 * @Date 2020/2/5
 * @Author lifei
 */
public class HashFunctionTest {

    private static final int R = 31;

    public static void main(String[] args) {
        int s = stringHashTestFive("S");
        System.out.println(s);

        System.out.println(("S".hashCode()&0x7fffffff)%5);
    }



    private static int stringHashTestFive(String str){
        return stringHashTest(str, 5);
    }

    private static int stringHashTest(String str, int M){
        int hash = 0;
        for (int i=0;i<str.length();i++){
            hash = (R+str.charAt(i))%M;
        }
        return hash;
    }


}

LinearProbingHashST.java

package com.hef.algorithms.chapter3.item34;

/**
 * @Date 2020/2/7
 * @Author lifei
 */
public class LinearProbingHashST<Key, Value> {

    // number of key-value pairs in the table
    private int N;
    // size of linear-probing table
    private int M = 16;
    // the keys
    private Key[] keys;
    // the values
    private Value[] vals;


    public LinearProbingHashST(){
        keys = (Key[]) new Object[M];
        vals = (Value[]) new Object[M];
    }

    private LinearProbingHashST(int cap){
        keys = (Key[]) new Object[cap];
        vals = (Value[]) new Object[cap];
    }

    private int hash(Key key){
        return (key.hashCode() & 0x7fffffff) % M;
    }

    //
    private void resize(int cap){
        LinearProbingHashST<Key, Value> t;
        t = new LinearProbingHashST<>(cap);
        for (int i = 0; i < M; i++) {
            if (keys[i]!=null){
                t.put(keys[i], vals[i]);
            }
        }
        keys = t.keys;
        vals = t.vals;
        M    = t.M;
    }

    public void put(Key key, Value val){
        // double M
        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++;
    }

    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;
    }

    public boolean contains(Key key){
        for (int i = hash(key); keys[i]!=null; i=(i+1)%M) {
            if (keys[i].equals(key)){
                return true;
            }
        }
        return false;
    }

    public void delete(Key key){
        if (!contains(key)) return;
        int i = hash(key);
        while (!key.equals(keys[i])){
            i = (i+1)%M;
        }
        keys[i] = null;
        vals[i] = null;
        i = (i+1)%M;
        while (keys[i]!=null){
            Key keyToRedo = keys[i];
            Value valToRedo = vals[i];
            keys[i] = null;
            vals[i] = null;
            N--;
            put(keyToRedo, valToRedo);
            i = (i+1)%M;
        }
        N--;
        if (N>0 && N==M/8) resize(M/2);
    }
}

SeparateChainingHashST.java

package com.hef.algorithms.chapter3.item34;

import java.util.Iterator;

/**
 * @Date 2020/2/6
 * @Author lifei
 */
public class SeparateChainingHashST<Key, Value> {

    // number of key-value paris
    private int N;
    // hash table size
    private int M;
    // array of ST objects
    private SequentialSearchST<Key, Value>[] st;

    public SeparateChainingHashST(){
        this(997);
    }

    // Create M linked lists
    public SeparateChainingHashST(int M){
        this.M = M;
        st = (SequentialSearchST<Key, Value>[]) new SequentialSearchST[M];
        for (int i = 0; i < M; i++) {
            st[i] = new SequentialSearchST();
        }
    }

    private int hash(Key key){
        return (key.hashCode() & 0x7fffffff) % M;
    }

    public Value get(Key key){
        return (Value) st[hash(key)].get(key);
    }

    public void put(Key key, Value val){
        st[hash(key)].put(key,val);
        N++;
    }

    public Iterable<Key> keys(){
        return new KeyIterable();
    }

    private class KeyIterable implements Iterable<Key>{
        @Override
        public Iterator<Key> iterator() {
            return new KeyIterator();
        }
    }

    private class KeyIterator implements Iterator<Key>{

        private int tempIndex = 0;
        private Iterator<Key> currentIterator;
        public KeyIterator(){
            for (int i=0;i<M;i++) {
                if (!st[i].isEmpty()){
                    currentIterator = st[i].keys().iterator();
                    tempIndex=i;
                    break;
                }
            }
        }

        @Override
        public boolean hasNext() {
            if (currentIterator==null) return false;
            return currentIterator.hasNext();
        }

        @Override
        public Key next() {
            Key key = currentIterator.next();
            if (!currentIterator.hasNext()){
                currentIterator = nextIterator();
            }
            return key;
        }

        private Iterator<Key> nextIterator(){
            for (int i = tempIndex+1; i < M; i++) {
                if (!st[i].isEmpty()){
                    tempIndex = i;
                    return st[i].keys().iterator();
                }
            }
            return null;
        }
    }

    public static void main(String[] args) {
        SeparateChainingHashST<String, Integer> separateChainingHashST = new SeparateChainingHashST<>();
        separateChainingHashST.put("aa",23);
        separateChainingHashST.put("world", 12);
        separateChainingHashST.put("hello", 33);
        Iterable<String> iterable = separateChainingHashST.keys();
        Iterator<String> iterator = iterable.iterator();
        while (iterator.hasNext()){
            String next = iterator.next();
            System.out.println(next);
        }
    }
}

SequentialSearchST.java

package com.hef.algorithms.chapter3.item34;

import java.util.Iterator;

/**
 * 顺序查询的key-value 表
 *
 * @Date 2020/2/6
 * @Author lifei
 */
public class SequentialSearchST<Key, Value> {

    private Node first;

    private class Node {
        Key key;
        Value val;
        Node next;

        public Node(Key key, Value val, Node next) {
            this.key = key;
            this.val = val;
            this.next = next;
        }
    }

    public boolean isEmpty(){
        if (first==null) return true;
        return false;
    }

    /**
     * Search for key, return associated value
     *
     * @param key
     * @return
     */
    public Value get(Key key) {
        for (Node x = first; x != null; x = x.next) {
            if (key.equals(x.key)) {
                return x.val;
            }
        }
        return null;
    }

    /**
     * Search for key. Update value if found; grow table if new
     *
     * @param key
     * @param val
     */
    public void put(Key key, Value val) {
        for (Node x = first; x != null; x = x.next) {
            // Search hit: update val
            if (key.equals(x.key)) {
                x.val = val;
                return;
            }
        }
        // Search miss: add new node
        first = new Node(key, val, first);
    }

    public Iterable<Key> keys() {
        return new KeyIterable();
    }

    private class KeyIterable implements Iterable<Key> {

        @Override
        public Iterator<Key> iterator() {
            return new KeyIterator();
        }
    }

    private class KeyIterator implements Iterator<Key> {

        private Node current = first;

        @Override
        public boolean hasNext() {
            if (current == null) return false;
            return true;
        }

        @Override
        public Key next() {
            Key key = current.key;
            current = current.next;
            return key;
        }
    }

    public static void main(String[] args) {
        SequentialSearchST<String, Integer> sequentialSearchST = new SequentialSearchST<>();
        sequentialSearchST.put("aa", 23);
        sequentialSearchST.put("bb", 33);
        sequentialSearchST.put("cc", 12);
        System.out.println(sequentialSearchST.first.key);
        Iterable<String> keys = sequentialSearchST.keys();
        Iterator<String> iterator = keys.iterator();
        while (iterator.hasNext()) {
            String next = iterator.next();
            System.out.println(next);
        }

    }
}

https://github.com/hefrankeleyn/AlgorithmsBook/blob/master/AlgorithmsPro/src/main/java/com/hef/algorithms/chapter3/item34/SequentialSearchST.java

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值