java黑皮书27.01-02----(应用开放地址法的线性探测法来实现MyMap)(应用开放地址法的二次探测法来实现MyMap)

问题描述

提示:这里我们默认有MyMap这个类,代码中我也会给出来:

书上代码用的是分离链接法来解决地址冲突的,这里要求我们改用线性探测法来实现。将散列表初始大小设置为4,使用 f(key) = key % size , size是散列表的大小。


难点分析:

提示:线性探测法,当前位置有元素就找下一个,如果有,又找下一个,知道找到位置放下元素:

首先,是放元素,我们将键值对放到Entry中,散列表中储存Entry对象,所以我们将根据Hash函数得到的散列表的下标,对下标进行冲突的解决(可能Hash得到的下标是相同的)。

添加元素:如果散列表当前下标有元素,就找下一个,这样一直下去,直到找到一个位置放好当前元素。

查找:根据输入的键,转化成散列表的下标,通过下标,慢慢寻找,找到退出,返回找到的值,或者达到一个空单元退出,返回null。

删除:将当前散列表的当前下标的元素标记为空就好。


解决方案:

提示:这里直接改造的书上的代码(java语言程序设计<进阶版>):

import java.util.Scanner;
import java.util.Set;

public class Lab27_01 {
    public static void main(String[] args) {
//        //题目要求的测试程序
//        MyHashMapForLinear<Integer, Integer> map = new MyHashMapForLinear<>();
//        Scanner input = new Scanner(System.in);
//
//        System.out.print("Enter integer keys, input ends with a negative value: ");
//        int key = input.nextInt();
//        while (key >= 0) {
//            map.put(key, key);
//            key = input.nextInt();
//        }
//
//        System.out.print("Enter key1: ");
//        int key1 = input.nextInt();
//        System.out.println("Is " + key1 + " in the map? " + map.containsKey(key1));
//
//        System.out.print("Enter key2: ");
//        int key2 = input.nextInt();
//        System.out.println("Is " + key2 + " in the map? " + map.containsKey(key2));
//
//        System.out.println("The map size is " + map.size());
//
//        map.remove(2);
//        System.out.println("After removing key 2 from the map, is key 2 in the map? " + map.containsKey(2));
//        System.out.println("The map size is " + map.size());

        //书上的测试程序
        MyHashMapForLinear<String, Integer> map = new MyHashMapForLinear<>();
        map.put("Smith", 30);
        map.put("Anderson", 31);
        map.put("Lewis", 29);
        map.put("Cook", 29);
        map.put("Smith", 65);

        System.out.println("Entries in map: " + map);

        System.out.println("The age for " + "Lewis is " +
                map.get("Lewis"));

        System.out.println("Is Smith in the map? " +
                map.containsKey("Smith"));
        System.out.println("Is age 33 in the map? " +
                map.containsValue(33));

        map.remove("Smith");
        System.out.println("Entries in map: " + map);

        map.clear();
        System.out.println("Entries in map: " + map);
    }

}

interface MyMapForLab27_01<K, V> {
    /**
     * Remove all of the entries from this map
     */
    public void clear();

    /**
     * Return true if the specified key is in the map
     */
    public boolean containsKey(K key);

    /**
     * Return true if this map contains the specified value
     */
    public boolean containsValue(V value);

    /**
     * Return a set of entries in the map
     *
     * @return
     */
    public Set<Entry<K, V>> entrySet();

    /**
     * Return the first value that matches the specified key
     */
    public V get(K key);

    /**
     * Return true if this map contains no entries
     */
    public boolean isEmpty();

    /**
     * Return a set consisting of the keys in this map
     */
    public java.util.Set<K> keySet();

    /**
     * Add an entry (key, value) into the map
     */
    public V put(K key, V value);

    /**
     * Remove the entries for the specified key
     */
    public void remove(K key);

    /**
     * Return the number of mappings in this map
     */
    public int size();

    /**
     * Return a set consisting of the values in this map
     */
    public java.util.Set<V> values();

    /**
     * Define inner class for Entry
     */
    public static class Entry<K, V> {
        K key;
        V value;

        public Entry(K key, V value) {
            this.key = key;
            this.value = value;
        }

        public K getKey() {
            return key;
        }

        public V getValue() {
            return value;
        }

        @Override
        public String toString() {
            return "[" + key + ", " + value + "]";
        }
    }
}

class MyHashMapForLinear<K, V> implements MyMapForLab27_01<K, V> {
    // Define the default hash table size. Must be a power of 2
    private static int DEFAULT_INITIAL_CAPACITY = 4;//初始散列表大小为4

    // Define the maximum hash table size. 1 << 30 is same as 2^30
    private static int MAXIMUM_CAPACITY = 1 << 30;

    // Current hash table capacity. Capacity is a power of 2
    private int size;// 散列表的大小

    // Define default load factor
    private static float DEFAULT_MAX_LOAD_FACTOR = 0.5f;//装填因子的阈值改为0.5

    // Specify a load factor used in the hash table
    private float loadFactorThreshold;

    // The number of entries in the map
    private int len = 0;// 实际包含的条目数

    MyMapForLab27_01.Entry<K, V>[] table;// 每个条目一个键值对

    /**
     * Construct a map with the default capacity and load factor
     */
    public MyHashMapForLinear() {
        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_MAX_LOAD_FACTOR);
    }

    /**
     * Construct a map with the specified initial capacity and
     * default load factor
     */
    public MyHashMapForLinear(int initialCapacity) {
        this(initialCapacity, DEFAULT_MAX_LOAD_FACTOR);
    }

    /**
     * Construct a map with the specified initial capacity
     * and load factor
     */
    public MyHashMapForLinear(int initialCapacity, float loadFactorThreshold) {
        if (initialCapacity > MAXIMUM_CAPACITY)
            this.size = MAXIMUM_CAPACITY;
        else
            this.size = trimToPowerOf2(initialCapacity);

        this.loadFactorThreshold = loadFactorThreshold;
        table = new MyMapForLab27_01.Entry[size];
    }

    @Override
    /** Remove all of the entries from this map */
    public void clear() {
        table = new MyMapForLab27_01.Entry[size];
        len = 0;
    }

    @Override
    /** Return true if the specified key is in the map */
    public boolean containsKey(K key) {
        if (get(key) != null)
            return true;
        else
            return false;
    }

    @Override
    /** Return true if this map contains the value */
    // 修改此方法
    public boolean containsValue(V value) {
        for (int i = 0; i < size; i++) {
            if (table[i] != null) {
                Entry<K, V> bucket = table[i];
                if (bucket.getValue().equals(value))
                    return true;
            }
        }

        return false;
    }

    @Override
    /** Return a set of entries in the map */
    // 修改此方法
    public Set<MyMapForLab27_01.Entry<K, V>> entrySet() {
        java.util.Set<MyMapForLab27_01.Entry<K, V>> set =
                new java.util.HashSet<>();

        for (int i = 0; i < size; i++) {
            if (table[i] != null) {
                Entry<K, V> bucket = table[i];
                set.add(bucket);
            }
        }

        return set;
    }

    @Override
    /** Return the value that matches the specified key */
    //改变此方法---->挨个查找,为空退出
    public V get(K key) {
        int bucketIndex = hash(key.hashCode());
        for (int i = bucketIndex; i < size; i++) {
            if (table[i % size] != null) {
                Entry<K, V> bucket = table[i % size];
                if (bucket.getKey().equals(key))
                    return bucket.getValue();
            } else
                return null;
        }

        return null;
    }

    @Override
    /** Return true if this map contains no entries */
    public boolean isEmpty() {
        return len == 0;
    }

    @Override
    /** Return a set consisting of the keys in this map */
    public java.util.Set<K> keySet() {
        java.util.Set<K> set = new java.util.HashSet<>();

        for (int i = 0; i < size; i++) {
            if (table[i] != null) {
                Entry<K, V> bucket = table[i];
                set.add(bucket.getKey());
            }
        }

        return set;
    }

    @Override
    /** Add an entry (key, value) into the map */
    public V put(K key, V value) {
        Set<K> set = keySet();
        if (set.contains(key)) {// 如果散列表中包含该键
            int bucketIndex = hash(key.hashCode());
            for (int i = bucketIndex; i < size; i++) {
                if (table[i % size] != null) {
                    Entry<K, V> bucket = table[i % size];
                    if (bucket.getKey().equals(key)) {
                        V oldValue = bucket.getValue();
                        bucket.value = value;
                        return oldValue;
                    }
                } else
                    break;
            }
        }

        // Check load factor
        if (len >= size * loadFactorThreshold) {
            if (size == MAXIMUM_CAPACITY)
                throw new RuntimeException("Exceeding maximum capacity");

            rehash();
        }

        int bucketIndex = hash(key.hashCode());
        if (table[bucketIndex] == null) {
            table[bucketIndex] = new Entry<>(key, value);
            len++;
            return value;
        }
        while (table[bucketIndex % size] != null) bucketIndex++;
        table[bucketIndex % size] = new MyMapForLab27_01.Entry<>(key, value);
        len++; // Increase size

        return value;
    }

    @Override
    /** Remove the entries for the specified key */
    public void remove(K key) {
        int bucketIndex = hash(key.hashCode());
        Set<K> set = keySet();
        if (set.contains(key)) {
            for (int i = bucketIndex; i < size; i++) {
                if (table[i % size] != null) {
                    Entry<K, V> bucket = table[i % size];
                    if (bucket.getKey().equals(key)) {
                        table[i % size] = null;
                        len--;
                        break;
                    } else
                        break;
                }
            }
        }
    }

    @Override
    /** Return the number of entries in this map */
    public int size() {
        return len;
    }

    @Override
    /** Return a set consisting of the values in this map */
    public java.util.Set<V> values() {
        java.util.Set<V> set = new java.util.HashSet<>();

        for (int i = 0; i < size; i++) {
            if (table[i] != null) {
                Entry<K, V> bucket = table[i];
                set.add(bucket.getValue());
            }
        }

        return set;
    }

    /**
     * Hash function
     * 改变 hash 函数, 并且保证返回为正数
     */
    private int hash(int hashCode) {
        return Math.abs(supplementalHash(hashCode) % size);
    }

    /**
     * Ensure the hashing is evenly distributed
     */
    private static int supplementalHash(int h) {
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }

    /**
     * Return a power of 2 for initialCapacity
     */
    private int trimToPowerOf2(int initialCapacity) {
        int capacity = 1;
        while (capacity < initialCapacity) {
            capacity <<= 1;
        }

        return capacity;
    }

    /**
     * Rehash the map
     */
    private void rehash() {
        java.util.Set<Entry<K, V>> set = entrySet(); // Get entries
        size <<= 1; // Double capacity
        table = new Entry[size]; // Create a new hash table
        len = 0; // Reset size to 0

        for (Entry<K, V> entry : set) {
            put(entry.getKey(), entry.getValue()); // Store to new table
        }
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder("[");

        for (int i = 0; i < size; i++)
            if (table[i] != null)
                builder.append(table[i]);


        builder.append("]");
        return builder.toString();
    }
}

二次探测法和其十分类似,线性探测能看懂,二次探测一般没问题

import java.util.LinkedList;
import java.util.Set;

public class Lab27_02 {
    public static void main(String[] args) {
        //书上的测试程序
        MyHashMapForQuad<String, Integer> map = new MyHashMapForQuad<>();
        map.put("Smith", 30);
        map.put("Anderson", 31);
        map.put("Lewis", 29);
        map.put("Cook", 29);
        map.put("Smith", 65);

        System.out.println("Entries in map: " + map);

        System.out.println("The age for " + "Lewis is " +
                map.get("Lewis"));

        System.out.println("Is Smith in the map? " +
                map.containsKey("Smith"));
        System.out.println("Is age 33 in the map? " +
                map.containsValue(33));

        map.remove("Smith");
        System.out.println("Entries in map: " + map);

        map.clear();
        System.out.println("Entries in map: " + map);
    }
}

interface MyMapForLab27_02<K, V> {
    /**
     * Remove all of the entries from this map
     */
    public void clear();

    /**
     * Return true if the specified key is in the map
     */
    public boolean containsKey(K key);

    /**
     * Return true if this map contains the specified value
     */
    public boolean containsValue(V value);

    /**
     * Return a set of entries in the map
     *
     * @return
     */
    public Set<Entry<K, V>> entrySet();

    /**
     * Return the first value that matches the specified key
     */
    public V get(K key);

    /**
     * Return true if this map contains no entries
     */
    public boolean isEmpty();

    /**
     * Return a set consisting of the keys in this map
     */
    public java.util.Set<K> keySet();

    /**
     * Add an entry (key, value) into the map
     */
    public V put(K key, V value);

    /**
     * Remove the entries for the specified key
     */
    public void remove(K key);

    /**
     * Return the number of mappings in this map
     */
    public int size();

    /**
     * Return a set consisting of the values in this map
     */
    public java.util.Set<V> values();

    /**
     * Define inner class for Entry
     */
    public static class Entry<K, V> {
        K key;
        V value;

        public Entry(K key, V value) {
            this.key = key;
            this.value = value;
        }

        public K getKey() {
            return key;
        }

        public V getValue() {
            return value;
        }

        @Override
        public String toString() {
            return "[" + key + ", " + value + "]";
        }
    }
}

class MyHashMapForQuad<K, V> implements MyMapForLab27_02<K, V> {
    // Define the default hash table size. Must be a power of 2
    private static int DEFAULT_INITIAL_CAPACITY = 4; // 初始大小

    // Define the maximum hash table size. 1 << 30 is same as 2^30
    private static int MAXIMUM_CAPACITY = 1 << 30;

    // Current hash table capacity. Capacity is a power of 2
    private int size;

    // Define default load factor
    private static float DEFAULT_MAX_LOAD_FACTOR = 0.5f;// 装填因子改为,0.5

    // Specify a load factor used in the hash table
    private float loadFactorThreshold;

    // The number of entries in the map
    private int len = 0; // 实际条目数

    // Hash table is an array with each cell that is a linked list
    Entry<K, V>[] table;

    /**
     * Construct a map with the default capacity and load factor
     */
    public MyHashMapForQuad() {
        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_MAX_LOAD_FACTOR);
    }

    /**
     * Construct a map with the specified initial capacity and
     * default load factor
     */
    public MyHashMapForQuad(int initialCapacity) {
        this(initialCapacity, DEFAULT_MAX_LOAD_FACTOR);
    }

    /**
     * Construct a map with the specified initial capacity
     * and load factor
     */
    public MyHashMapForQuad(int initialCapacity, float loadFactorThreshold) {
        if (initialCapacity > MAXIMUM_CAPACITY)
            this.size = MAXIMUM_CAPACITY;
        else
            this.size = trimToPowerOf2(initialCapacity);

        this.loadFactorThreshold = loadFactorThreshold;
        table = new MyMapForLab27_02.Entry[size];
    }


    @Override
    /** Remove all of the entries from this map */
    public void clear() {
        table = new MyMapForLab27_02.Entry[size];
        len = 0;
    }

    @Override
    /** Return true if the specified key is in the map */
    public boolean containsKey(K key) {
        if (get(key) != null)
            return true;
        else
            return false;
    }

    @Override
    /** Return true if this map contains the value */
    // 修改此方法-----> 直接用values来判断就好
    public boolean containsValue(V value) {
        Set<V> set = values();
        return set.contains(value);
    }

    @Override
    /** Return a set of entries in the map */
    public Set<MyMapForLab27_02.Entry<K, V>> entrySet() {
        java.util.Set<MyMapForLab27_02.Entry<K, V>> set =
                new java.util.HashSet<>();

        for (int i = 0; i < size; i++) {
            if (table[i] != null) {
                MyMapForLab27_02.Entry<K, V> bucket = table[i];
                set.add(bucket);
            }
        }

        return set;
    }

    @Override
    /** Return the value that matches the specified key */
    //改变此方法---->二次探测查找,为空退出
    public V get(K key) {
        int bucketIndex = hash(key.hashCode());
        for (int i = 0; i < size; i++) {
            if (table[(bucketIndex + i * i)] != null) {
                MyMapForLab27_02.Entry<K, V> bucket = table[(bucketIndex + i * i) % size];
                if (bucket.getKey().equals(key))
                    return bucket.getValue();
            } else
                return null;
        }

        return null;
    }

    @Override
    /** Return true if this map contains no entries */
    public boolean isEmpty() {
        return len == 0;
    }

    @Override
    /** Return a set consisting of the keys in this map */
    public java.util.Set<K> keySet() {
        java.util.Set<K> set = new java.util.HashSet<>();

        for (int i = 0; i < size; i++) {
            if (table[i] != null) {
                MyMapForLab27_02.Entry<K, V> bucket = table[i];
                set.add(bucket.getKey());
            }
        }

        return set;
    }

    @Override
    /** Add an entry (key, value) into the map */
    public V put(K key, V value) {
        Set<K> set = keySet();
        if (set.contains(key)) {// 散列表中包含该键
            int bucketIndex = hash(key.hashCode());
            for (int i = 0; i < size; i++) {
                if (table[(bucketIndex + i * i)] != null) {
                    MyMapForLab27_02.Entry<K, V> bucket = table[(bucketIndex + i * i)];
                    if (bucket.getKey().equals(key)) {
                        V oldValue = bucket.getValue();
                        bucket.value = value;
                        return oldValue;
                    }
                } else
                    break;
            }
        }

        // Check load factor
        if (len >= size * loadFactorThreshold) {
            if (size == MAXIMUM_CAPACITY)
                throw new RuntimeException("Exceeding maximum capacity");

            rehash();
        }

        int bucketIndex = hash(key.hashCode());
        if (table[bucketIndex] == null) {
            table[bucketIndex] = new MyMapForLab27_02.Entry<>(key, value);
            len++;
            return value;
        }
        int i = 0;
        while (table[(bucketIndex + i * i) % size] != null) i++;
        table[(bucketIndex + i * i) % size] = new MyMapForLab27_02.Entry<>(key, value);
        len++; // Increase size

        return value;
    }

    @Override
    /** Remove the entries for the specified key */
    public void remove(K key) {
        int bucketIndex = hash(key.hashCode());
        Set<K> set = keySet();
        if (set.contains(key)) {
            for (int i = 0; i < size; i++) {
                if (table[(bucketIndex + i * i) % size] != null) {
                    MyMapForLab27_02.Entry<K, V> bucket = table[(bucketIndex + i * i) % size];
                    if (bucket.getKey().equals(key)) {
                        table[(bucketIndex + i * i) % size] = null;
                        len--;
                        break;
                    } else
                        break;
                }
            }
        }
    }

    @Override
    /** Return the number of entries in this map */
    public int size() {
        return len;
    }

    @Override
    /** Return a set consisting of the values in this map */
    public java.util.Set<V> values() {
        java.util.Set<V> set = new java.util.HashSet<>();

        for (int i = 0; i < size; i++) {
            if (table[i] != null) {
                MyMapForLab27_02.Entry<K, V> bucket = table[i];
                set.add(bucket.getValue());
            }
        }

        return set;
    }

    /**
     * Hash function
     * 改变 hash 函数, 并且保证返回为正数
     */
    private int hash(int hashCode) {
        return Math.abs(supplementalHash(hashCode) % size);
    }

    /**
     * Ensure the hashing is evenly distributed
     */
    private static int supplementalHash(int h) {
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }

    /**
     * Return a power of 2 for initialCapacity
     */
    private int trimToPowerOf2(int initialCapacity) {
        int capacity = 1;
        while (capacity < initialCapacity) {
            capacity <<= 1;
        }

        return capacity;
    }

    /**
     * Rehash the map
     */
    private void rehash() {
        java.util.Set<MyMapForLab27_02.Entry<K, V>> set = entrySet(); // Get entries
        size <<= 1; // Double capacity
        table = new MyMapForLab27_02.Entry[size]; // Create a new hash table
        len = 0; // Reset size to 0

        for (MyMapForLab27_02.Entry<K, V> entry : set) {
            put(entry.getKey(), entry.getValue()); // Store to new table
        }
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder("[");

        for (int i = 0; i < size; i++)
            if (table[i] != null)
                builder.append(table[i]);


        builder.append("]");
        return builder.toString();
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值