哈希表的原理

这篇具有很好参考价值的文章主要介绍了哈希表的原理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

哈希概念

线性表、树结构的查找方式都是以关键字的比较为基础,查找效率比较低,顺序表的时间复杂度是O(n),平衡树中为树的高度,即O(logn),搜素的效率取决于搜索过程的元素比较次数。

理想的搜素方法:可以用不经过比较,一次直接从表中得到要搜素的元素。如果构造一种存储结构,通过某种函数(hashFunc)使元素的存储位置与他的关键字之间能够建立一一映射的关系,那么在查找元素的时候,就可以很快寻找到该元素,这就是哈希的思想.

哈希函数

插入元素

                根据待插入的元素的关键字码,以此函数计算出该元素的存储位置并且按照此位置进行存放

搜素元素

        对元素的关键字码进行同样的计算,把求得函数值当做元素的存储位置,在结构中按此位置取元素比较,若关键字码相同,则搜素成功。 

此方法即为哈希(散列)方法,哈希(散列)方法中使用的转换函数称之为哈希(散列)函数,构造出来的结构就是哈希表(hashTable)(或者散列表)。

例如:数据集合{1,7,6,4,5,9};

哈希函数设置为:hash(key)= key%capacity;(capacity代表的是底层空间总大小可以理解成元素个数)

哈希表的原理,哈希算法,散列表,算法,java

 用该方法进行搜素的时候不必多次进行比较可以直接找到想找的关键字,但是我们就会出现一个问题:如果再次插入一个44怎么办呢?这就会引出下面的部分,哈希冲突。

哈希冲突:

概念:

对于两个关键字ki,kj(i != j)有ki != kj,但是有:Hash(ki)== Hash(kj)即:不同的关键字通过哈希函数计算出相同的哈希地址,这种现象称之为哈希冲突。

冲突的避免

首先我们要明确疑点,由于我们哈希表底层数组容量往往小于实际要存储的数量,这就导致了一个问题,冲突是必然的,但是我们可以降低冲突率。

哈希函数的设计

1、直接定制法

取关键字的某个线性函数为散列地址:Hash(key)=A*key+B (即是一个y=ax+b的函数,如计数排序数字91存储在(91-90)的下标上)优点:简单、均匀 缺点需要事先知道关键字的分布情况 使用场景:适合查找比较小且连续的情况。

2、除留余数法

这个就是我们上面所介绍的方法,标准的官方说法是设散列表中允许的地址数为m(如果10个数据m的范围就是0-9),取一个不大于m的数,但是最接近或者等于m的质数p作为除数,按照哈希函数Hash(key)= key%p(p<=m),将关键字码转换为哈希地址。

还有很多的方法,但是使用的很少,所以这里不过多介绍。

负载因子调节

散列表的载荷因子定义为:=填入表格的元素/散列表的长度

在java系统库中限制载荷因子为0.75如果大于这个数字就需要,降低载荷因子。

哈希冲突的解决

哈希冲突的常见的两种解决方案就是:闭散列和开散列。

闭散列:也叫开放定址法,当哈希表没有被填满,说明哈希表还有空位置,那么可以把key存放到冲突位置的下一个空位置去。那么如何寻找下一个空位置呢?

1、线性探测

比如上面的场景,现在需要插入元素44,先通过哈希函数计算哈希地址,下标是4,所以理论上应该插入到4的位置,但是该位置已经存放了元素4,即发生了哈希冲突。

线性探测:从发生冲突的位置开始,一次向后探测,直到寻找到下一个空位置为止。

哈希表的原理,哈希算法,散列表,算法,java

 采用闭散列处理哈希冲突的时候,不能随便物理删除哈希表已经有的元素,若直接删除元素会影响其他元素的搜索。比如删除4,如果直接删除4,那么在查找44的时候就会受到影响。因此线性探测采用标记的伪元素来删除一个元素。

2、二次探测

线性探测的缺陷是产生冲突的元素堆积到一块,这与其找下一个元素位置有关系,因为找空位置的方式就是挨着往后逐个去找,因此二次探测为了避免这样的问题,找下一个空位置的方法为:Hi=(H0+i²)%m或者Hi=(H0-i²)%m其中:i=1,2,3....H0是通过哈希函数计算出元素所在位置,m是表的大小。

因此:闭散列表的最大缺陷就是空间利用率低,这也是哈希的缺陷。

开散列/哈希桶(重点)

开散列:开散列又叫链地址法(开链法),首先对关键码集合用哈希函数计算出哈希地址,具有相同的地址的关键码归于同一子集合,每一个子集称作一个桶,各个桶中的元素通过一个单链表连接器起来,各链表的头节点都存储在哈希表中。

哈希表的原理,哈希算法,散列表,算法,java

 

开散列,可以认为把一个大集合中的搜素问题转化到小集合中进行。

代码实现:

public class Hashbucket {
    static class Node{
        private int key;
        private int value;
        private Node next;

        public Node(int key, int value) {
            this.key = key;
            this.value = value;
        }
    }
    public Node[] array;
    public int useSize;
    private static final float DEFAULT_LOAD_FACTOR = 0.75f;
    public Hashbucket() {
        array=new Node[10];
    }
    public void put(int key,int value){
        Node node=new Node(key,value);
        int index= node.key%array.length;
        Node cur=array[index];
        //java1.8之后采用的是尾插法 这里采用头插法
        while(cur!=null){
            if(cur.key==key){
                cur.value=value;
                return;
            }
            cur=cur.next;
        }
        node.next=array[index];
        array[index]=node;
        useSize++;
        if(loadFactor()>DEFAULT_LOAD_FACTOR){
            resize();
        }
    }
    public void resize(){
        //二倍扩容
        Node[] tmpArray=new Node[array.length*2];
        for (Node node : array) {
            Node cur = node;
            while (cur != null) {
                Node curNext = cur.next;
                int index = cur.key % tmpArray.length;
                //头插法
                cur.next = tmpArray[index];
                tmpArray[index] = cur;
                cur = curNext;
            }
        }
        array=tmpArray;
    }
    public float loadFactor(){
        return array.length*1.0f/useSize;
    }
    public int get(int key){
        int index=key%array.length;
        Node cur=array[index];
        while(cur!=null){
            if(cur.key==key){
                return cur.value;
            }
            cur=cur.next;
        }
        return -1;
    }
}

这个代码中这个扩容部分我们要仔细的说一说,但负载因子大于0.75的时候,我们需要降低哈希冲突,因为我们的元素个数是一定的,所以我们就需要增大散列表的大小,但是当我们扩容的时候,我们会打乱原来的散列表,比如原来4和14都是在节点4的位置,当我们二倍扩容的时候我们就需要将14放到节点14的位置。文章来源地址https://www.toymoban.com/news/detail-563535.html

到了这里,关于哈希表的原理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构算法设计——哈希表(散列表)

            哈希表 又叫 散列表 ,他们两个是同一个东西,本文全文采用“散列表”的叫法。散列表的本质其实就是一个 数组 ,他的作用就像使用数组时一样,输入下标可以得到对应元素,散列表可以实现 输入一个的时候得到这个的地址信息 。 下面是百科给出

    2024年02月03日
    浏览(51)
  • 【数据结构与算法】04 哈希表 / 散列表 (哈希函数、哈希冲突、链地址法、开放地址法、SHA256)

    一种很好用,很高效,又一学就会的数据结构,你确定不看看? 莫慌,每个概念都很好理解。 哈希表( Hash Table ),也称为 散列表 ,是一种数据结构, 用于存储键值对(key-value pairs) 。 键值对是一种数据结构,用于将键(key)与对应的值(value)相关联。在键值对中,键

    2024年02月09日
    浏览(63)
  • 【JavaSE专栏53】Java集合类HashMap解析,基于哈希表的键值对存储结构

    作者主页 :Designer 小郑 作者简介 :3年JAVA全栈开发经验,专注JAVA技术、系统定制、远程指导,致力于企业数字化转型,CSDN学院、蓝桥云课认证讲师。 主打方向 :Vue、SpringBoot、微信小程序 本文讲解了 Java 中集合类 HashMap 的语法、使用说明和应用场景,并给出了样例代码。

    2024年02月15日
    浏览(27)
  • 【SM3哈希算法】算法原理

    参考: SM3算法是一种密码散列函数标准,由国家密码管理局发布。它的安全性和SHA-256相当,适用于商用密码应用中的数字签名和验证、消息认证码生成和验证、随机数生成等。 将输入的消息分成512位的分组,并对每个分组进行填充、分组、扩展、迭代压缩等操作,最后输出

    2024年02月08日
    浏览(30)
  • 算法每日一题: 删除排序列表中的重复元素2 | 循环 | 链表的删除 | 虚拟节点

    大家好,我是星恒 今天的题目是昨天题目的进化题,他对链表的删除加深了理解。最重要的是学会了对循环中的特殊部分的处理,还有设置虚拟节点的情况 好了,话不多说,我们直接开始 题目:leetcode 82 给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点

    2024年01月16日
    浏览(31)
  • Java学数据结构(4)——散列表Hash table & 散列函数 & 哈希冲突

    1.散列表,key,散列函数; 2.哈希冲突的解决; 3.string中的hashCode; 查找树ADT,它允许对元素的集合进行各种操作。本章讨论散列表(hash table)ADT,不过它只支持二叉查找树所允许的一部分操作。散列表的实现常常叫作散列(hashing)。散列是一种用于以常数平均时间执行插入、删除和

    2024年02月10日
    浏览(47)
  • HBase开发: Java API 管理表 第1关:JavaAPI获取表的列表

    本关我们来使用 JavaApi 对 HBase 中的表进行管理,第一关我们来学习如何列出所有的表。 获取表的列表 如何使用 Java 列出 HBase 中所有的表呢? 在HBase中我们要获取一张表的基本信息需要用到一个类: TableDescriptor ; 通过 TableDescriptor 我们可以获取表的名字,列族等信息; 好了

    2024年02月07日
    浏览(31)
  • OpenCV书签 #感知哈希算法的原理与相似图片搜索实验

    感知哈希算法(Perceptual Hash Algorithm,简称pHash) 是哈希算法的一种,主要可以用来做以图搜索/相似图片搜索工作。   感知哈希算法(pHash)首先将原图像缩小成一个固定大小的像素图像,然后将图像转换为灰度图像,通过使用离散余弦变换(DCT)来获取频域信息。然后,根

    2024年01月22日
    浏览(30)
  • OpenCV书签 #差值哈希算法的原理与相似图片搜索实验

    差值哈希算法(Difference Hash Algorithm,简称dHash) 是哈希算法的一种,主要可以用来做以图搜索/相似图片的搜索工作。   差值哈希算法通过计算相邻像素的差异来生成哈希,即通过缩小图像的每个像素与平均灰度值的比较,生成一组哈希值。最后,利用两组图像的哈希值的汉

    2024年01月23日
    浏览(35)
  • OpenCV #以图搜图:均值哈希算法(Average Hash Algorithm)原理与实验

    均值哈希算法(Average Hash Algorithm,简称aHash) 是哈希算法的一种,主要用来做相似图片的搜索工作。   均值哈希算法(aHash)首先将原图像缩小成一个固定大小的像素图像,然后将图像转换为灰度图像,通过缩小图像的每个像素与平均灰度值的比较,生成一组哈希值。最后,

    2024年02月08日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包