Hash算法

package com.cskaoyan.hashmap;

import java.util.LinkedHashSet;
import java.util.Set;

/*
API:
    // void put(K key, V value)
    // V get(K key)
    // void delete(K key)
    // void clear()
    // boolean contains(K key)
    // boolean isEmpty()
    // int size()
    // Set<K> keys()
 */
public class MyHashMap<K, V> {
    // 常量
    private static final int DEFAULT_ARRAY_SIZE = 16;
    private static final int MAX_ARRAY_SIZE = 1 << 30;
    private static final float DEFAULT_LOAD_FACTOR = 0.75f;
    // 属性
    private Entry[] table;
    private int size;
    private float loadFactor;
    private int threshold; //阈值, 当size达到threshold时候就需要扩容了

    private static class Entry {
        Object key;
        Object value;
        int hash;
        Entry next;

        public Entry(Object key, Object value, int hash, Entry next) {
            this.key = key;
            this.value = value;
            this.hash = hash;
            this.next = next;
        }

        @Override
        public String toString() {
            return key + "=" + value;
        }
    }

    // 构造方法
    public MyHashMap() {
        this(DEFAULT_ARRAY_SIZE, DEFAULT_LOAD_FACTOR);
    }

    public MyHashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

    public MyHashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity <= 0 || initialCapacity > MAX_ARRAY_SIZE) {
            throw new IllegalArgumentException("initialCapacity=" + initialCapacity);
        }
        if (loadFactor <= 0) {
            throw new IllegalArgumentException("loadFactor=" + loadFactor);
        }
        // 求大于等于initialCapacity最小的2的幂
        int capacity = calculateCapacity(initialCapacity);
        table = new Entry[capacity];
        this.loadFactor = loadFactor;
        threshold = (int) (table.length * loadFactor);
    }

    private int calculateCapacity(int cap) {
        int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return n + 1;
    }

    /**
     * 添加键值对,如果键已经存在,则更新它关联的值
     *
     * @param key   键
     * @param value 值
     * @return 原来的值,如果key不存在返回 null
     */
    @SuppressWarnings("unchecked")
    public V put(K key, V value) {
        if (key == null || value == null) {
            throw new IllegalArgumentException("Key or value cannot be null.");
        }
        int hash = hash(key);
        int index = indexFor(hash, table.length);
        // 遍历链表, 查找key
        for (Entry e = table[index]; e != null; e = e.next) {
            if (hash == e.hash && (key == e.key || key.equals(e.key))) {
                // 更新值,并把原来的值返回
                V oldValue = (V) e.value;
                e.value = value;
                return oldValue;
            }
        }
        addEntry(key, value, hash, index);
        return null;
    }

    private void addEntry(K key, V value, int hash, int index) {
        // 判断是否需要扩容
        if (size >= threshold) {
            if (table.length == MAX_ARRAY_SIZE) {
                // 破坏加载因子的限制
                threshold = Integer.MAX_VALUE;
            } else {
                // 扩容
                grow(table.length << 1);
                // 重新计算索引值
                index = indexFor(hash, table.length);
            }
        }
        // 添加结点(头插法)
        Entry e = new Entry(key, value, hash, table[index]);
        table[index] = e;
        size++;
    }

    private void grow(int newCapacity) {
        Entry[] newTable = new Entry[newCapacity];
        // 重新散列
        for (Entry e : table) {
            // 遍历链表,重新散列
            while (e != null) {
                // 保存e的next结点
                Entry next = e.next;
                // 计算在新数组中索引
                int i = indexFor(e.hash, newCapacity);
                // 头插法
                e.next = newTable[i];
                newTable[i] = e;
                // e指向原链表的下一个结点
                e = next;
            }
        }
        table = newTable;
        // 更新阈值
        threshold = (int) (newCapacity * loadFactor);
    }

    /**
     * 通过键获取值
     *
     * @param key 键
     * @return 键关联的值,如果键不存在返回null
     */
    @SuppressWarnings("unchecked")
    public V get(K key) {
        if (key == null) throw new IllegalArgumentException("Key cannot be null.");
        int hash = hash(key);
        int index = indexFor(hash, table.length);
        // 遍历链表, 找到key关联值
        for (Entry e = table[index]; e != null; e = e.next) {
            if (hash == e.hash && (key == e.key || key.equals(e.key))) {
                // 找到该结点
                return (V) e.value;
            }
        }
        // 没有这样的key
        return null;
    }

    private int indexFor(int hash, int length) {
        return hash & (length - 1);
    }

    private int hash(K key) {
        int h = key.hashCode();
        return (h << 16) ^ (h >> 16);
    }

    /**
     * 判断key是否在哈希表中存在
     *
     * @param key 键
     * @return 如果存在返回true, 否则返回false
     */
    public boolean contains(K key) {
        return get(key) != null;
    }

    /**
     * 删除键值对
     *
     * @param key 键
     * @return 被删除的值, 如果不存在则返回null
     */
    @SuppressWarnings("unchecked")
    public V delete(K key) {
        if (key == null) {
            throw new IllegalArgumentException("Key cannot be null.");
        }
        int hash = hash(key);
        int index = indexFor(hash, table.length);
        // 遍历链表, 找到key关联值
        for (Entry e = table[index], p = null; e != null; p = e, e = e.next) {
            if (hash == e.hash && (key == e.key || key.equals(e.key))) {
                // 删除结点
                V deleteValue = (V) e.value;
                if (p == null) table[index] = e.next;
                else p.next = e.next;
                size--;
                return deleteValue;
            }
        }
        return null;
    }

    /**
     * 清空所有键值对
     */
    public void clear() {
        for(int i = 0; i < table.length; i++) {
            table[i] = null;
        }
        size = 0;
    }

    /**
     * 获取链表中键值对的个数
     *
     * @return 链表中键值对的个数
     */
    public int size() {
        return size;
    }

    /**
     * 判断哈希表是否为空
     *
     * @return 如果哈希表为空返回true, 否则返回false
     */
    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * 获取键的集合
     *
     * @return 键的集合
     */
    @SuppressWarnings("unchecked")
    public Set<K> keys() {
        Set<K> set = new LinkedHashSet<>();
        // 遍历哈希表
        for (Entry e : table) {
            while (e != null) {
                set.add((K) e.key);
                e = e.next;
            }
        }
        return set;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("{");
        for (Entry e : table) {
            while (e != null) {
                sb.append(e).append(", ");
                e = e.next;
            }
        }
        if (!isEmpty()) sb.delete(sb.length() - 2, sb.length());
        return sb.append("}").toString();
    }

    public static void main(String[] args) {
        // V put(K key, V value)
        MyHashMap<Character, String> map = new MyHashMap<>();
        // System.out.println(map);
        map.put('A', "Allen");
        map.put('B', "Beyonce");
        map.put('C', "Catalina");
        map.put('D', "Diana");
        // System.out.println(map);

        /*System.out.println(map.put('A', "Adele"));
        System.out.println(map);*/

        // boolean contains(K key), V get(K key)
        /*System.out.println(map.get('B'));
        System.out.println(map.get('X'));
        System.out.println(map.contains('B'));
        System.out.println(map.contains('X'));*/

        // V delete(K key)
        /*System.out.println(map.delete('C'));
        System.out.println(map);
        System.out.println(map.size());
        System.out.println(map.delete('X'));
        System.out.println(map);
        System.out.println(map.size());*/

        // int size(), void clear(), boolean isEmpty()
        /*System.out.println(map);
        System.out.println(map.size());
        System.out.println(map.isEmpty());
        map.clear();
        System.out.println(map);
        System.out.println(map.size());
        System.out.println(map.isEmpty());*/

        // Set<K> keys()
        Set<Character> keys = map.keys();
        for(char key : keys) {
            String value = map.get(key);
            System.out.println(key + "=" + value);
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java 中常用的 Hash 算法有以下几种: 1. MD5(Message Digest Algorithm 5):MD5 是一种单向加密算法,不可逆,常用于验证数据的完整性和一致性。 ```java import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class HashAlgorithms { public static void main(String[] args) throws NoSuchAlgorithmException { String input = "hello world"; MessageDigest md = MessageDigest.getInstance("MD5"); byte[] mdBytes = md.digest(input.getBytes()); StringBuilder hexString = new StringBuilder(); for (byte b : mdBytes) { hexString.append(String.format("%02x", b)); } System.out.println(hexString.toString()); } } ``` 2. SHA(Secure Hash Algorithm):SHA 也是一种单向加密算法,主要用于数字签名和验证数据的完整性。 ```java import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class HashAlgorithms { public static void main(String[] args) throws NoSuchAlgorithmException { String input = "hello world"; MessageDigest md = MessageDigest.getInstance("SHA-256"); byte[] mdBytes = md.digest(input.getBytes()); StringBuilder hexString = new StringBuilder(); for (byte b : mdBytes) { hexString.append(String.format("%02x", b)); } System.out.println(hexString.toString()); } } ``` 3. MurmurHash:MurmurHash 是一种高性能 Hash 算法,适用于大规模数据集的 Hash 计算。 ```java import com.google.common.hash.HashCode; import com.google.common.hash.HashFunction; import com.google.common.hash.Hashing; public class HashAlgorithms { public static void main(String[] args) { String input = "hello world"; HashFunction hf = Hashing.murmur3_128(); HashCode hc = hf.hashBytes(input.getBytes()); System.out.println(hc.toString()); } } ``` 4. CRC32(Cyclic Redundancy Check):CRC32 是一种循环冗余校验算法,常用于数据传输或存储时的错误检测。 ```java import java.util.zip.CRC32; public class HashAlgorithms { public static void main(String[] args) { String input = "hello world"; CRC32 crc32 = new CRC32(); crc32.update(input.getBytes()); System.out.println(crc32.getValue()); } } ``` 以上 Hash 算法都有其特定的应用场景,具体选择哪种算法需要根据具体的需求来决定。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值