Java哈希表的原理

1、引入:

首先我们要了解一下哈希表究竟是一个怎样的数据结构,简而言之,就是一个可通过所提供的索引(Key)快速找到对应数据的数据结构,原理是该索引将通过hash函数取得能让我们知道数据存储地址的hash值。最基础的hash表可以由一个链表数组实现。哈希表常用于数据较多且对查找的需求较大的情况。要实现一个哈希表有两点是重中之重,一个是设计出一个优秀的取得hash值的函数,既要求不让hash值分散太开导致数组必须开很大(尽量让计算的结果可以取到空间内的任意一块地址),又不能让多数据的hash值都相等,导致查找效率的极大降低。另一点就是要妥善处理哈希值相同的数据,是赋予他们新的hash值,还是直接把他们接在对应hash值的链表的后面?

2、hash函数:

  常用的hash函数:

    1:直接定制,如:hash = key * 7 + 13;

    2:除留取余,如:hash = key % 数组长度;

3:MD5 (Message Digest Algorithm 5):它产生一个128位的哈希值,通常以32位的十六进制数字表示。

4:SHA-1 (Secure Hash Algorithm 1):它产生一个160位的哈希值,通常以40位的十六进制数字表示。

在我的示例代码中,采取的就是第二种方法,优点是数据分布的会较为均匀,且数组的所有空间都被利用。

    public int hash(Key key){

        String str = key.toString();

        byte[] bytes = str.getBytes();

        int sum = 0;

        for(int i = 0; i < bytes.length; i++){

            sum += bytes[i];

        }

        return sum % length;

    }

3、冲突处理:

    首先要知道的是key值本身是要保留的,因为hash值可以对应多个数据,要用key来判断我们要取出的是哪个数据。Hash冲突主有两种处理方法:开散列与闭散列。开散列是将每块地址都设置成一个链表,当发生冲突时,将其进行 头插或者尾插 用来解决冲突问题。闭散列则是将冲突的元素放在其解析地址的后一个地址,或者通过一个函数去进行二次计算。如果一个劲地将元素插入链表,最终哈希的效率还是会变的很低,因此我们要在链表达到一定长度后对数组进行扩容,以减少冲突的数量。Java自带的hashMap采用的就是闭散列的方法。

4、哈希表的实现。

    在了解哈希表的各种特性后,再将其以代码的形式写出,然后只要实现了基础的增删改查功能,我们就成功实现了哈希表的创建。

public class MyHashMap<Key, Value> {
    LinkedList[] lists = new LinkedList[17];
    public int max = 15;
    public static Node temp;

    public int hash(Key key){
        String str = key.toString();
        byte[] bytes = str.getBytes();
        int sum = 0;
        for(int i = 0; i < bytes.length; i++){
            sum += bytes[i];
        }
        return sum % lists.length;
    }

    public void add(Key key, Value value){
        if(lists[hash(key)] == null){
            lists[hash(key)] = new LinkedList();
        }
        if(find(key) == null) lists[hash(key)].add(key,value);
        else {
            temp.value = value;
        }
        if(lists[hash(key)].Size() >= max)renew();
    }

    public void renew(){
        max = max * 2;
        LinkedList[] newlists = new LinkedList[lists.length * 2];
        for (int i = 0; i < lists.length; i++){
            Node node = null;
            if(lists[i] != null)node = lists[i].head;
            while (lists[i] != null){
                newlists[hash((Key)node.key)].add(node);
                node = node.next;
            }
        }
        lists = newlists;
    }

    public void delete(Key key){
        Node node = lists[hash(key)].head;
        if(node != null){
            if(node.key == key)lists[hash(key)].remove_by_key(key);
        }
    }

    public Value find(Key key){
        Node node = lists[hash(key)].head;
        while(node != null){
            if(node.key == key){
                temp = node;
                return (Value)node.value;
            }else node = node.next;
        }
        return null;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

专心神游

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值