【ADT】第五章 散列

散列表ADT是一个包含一些项的具有固定大小的数组
散列是一种以常数平均时间O(1)执行插入、删除、查找的技术
JavaCollection中基于散列技术实现了HashSet、HashMap
不支持排序、findMin、findMax等操作
散列表一般是基于HashCode实现散列函数的,故散列表中存储的对象需要hashcode()和equals()方法



1 散列ADT

1.1 基本了解

散列表ADT是一个包含一些项的具有固定大小的数组
查找操作是通过项的某个部分进行的,这个部分叫做关键字

1.2 散列的基本想法

把散列表的大小记作TableSize
把每个关键字映射从0到TableSize-1这个范围的某个数,并放入数组中对应的单元中的技术叫做散列
其中映射到(0 ~ TableSize-1)的函数叫做散列函数(Hash Function)
这个散列函数在一般情况下就是Key mod TableSize,Key一般下就是对象的HashCode()了

1.3 散列的问题

但是散列ADT中存在一个很大的问题就是散列冲突:TableSize必然不能无限大,甚至不能过大,这样必然会有多个关键字映射到同一个值,这样如何存储冲突值就成了一个需要探讨的问题;另外如何能尽可能利用TableSize中的每一个单元,而不是将冲突集中到其中几个单元,剩下的单元利用不充分造成资源浪费

利用散列表需要考虑的问题:
1 如何存储冲突值
2 散列表的大小如何选择
3 散列函数如何计算才能尽可能减小冲突

我们先说明后两个问题:

散列表大小的选择:

散列表的大小选择要求尽可能平均分布,举例若散列表大小为10而关键字都以0为个位,那么所有的关键字都会在0位冲突,其他单元又严重浪费,比较好的办法就是:

保证表的大小是素数(素数:除了1和自己不能被整除)(一般取17以上的素数)

原因:

1 如果关键字是随机的,TableSize是多少其实并无所谓,然而在现实中关键字往往有某种规律,例如大量的等差数列,那么公差和模数不互质的时候发生碰撞的概率会变大,而用质数就可以很大程度上回避这个问题。

2 一般地说, 当模数非常大的时候, 取什么数关系不太大, 质数合数都有不错的结果,但是一般情况下模数不会 “足够大” , 这个时候, “所有” 17以上的素数都有不错的结果, 而很多合数也有不错的结果, 但是个别一些合数结果会非常非常差,冲突非常多.。因此为了稳妥起见, 取17以上的素数.

//是否为素数
    private boolean isPrime(int num) {
        if (num == 2 || num == 3) {
            return true;
        }
        if (num % 6 != 1 && num % 6 != 5) {
            return false;
        }
        for (int i = 5; i * i <= num; i += 6) {
            if (num % i == 0 || num % (i + 2) == 0) {
                return false;
            }
        }
        return true;
    }
    //n后面的下一个素数
    private int nextPrime(int n) {
        boolean state = isPrime(n);
        while (!state) {
            state = isPrime(++n);
        }
        return n;
    }

散列函数如何计算

一般情况下的散列函数=对象的Key mod TableSize(对象的Key = 对象的HashCode)

    public int myHash(T t) {
        int hashValue = t.hashCode() % list.length;
        if(hashValue < 0) { //考虑溢出为负数
            hashValue += list.length;
        }
        return hashValue;
    }
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值