精华内容
下载资源
问答
  • 字符串哈希和哈希表的本质

    千次阅读 2017-09-23 00:25:15
    很多人听到哈希, 是从md5开始的, 比如每一个字符串都有它的md5, 且两个不同... 在数据结构中, 又有哈希表, 这个是什么玩意儿呢? 对于非计算机专业的我来说, 开始是不太好理解的, 其实思路非常非常简单。 我们来

         说明: 后来发现, 本文的逻辑有点问题, 实际上,在计算ht[...]时候, 可能涉及到查找(以C++ STL为例)

       

         很多人听到哈希, 是从md5开始的,  比如每一个字符串都有它的md5, 且两个不同字符串的md5值不一样, 而且根据md5值, 是无法求出原来的字符串的。 这就是字符串的哈希。 说白了, 哈希就是满足一定条件的变换, 本质就是变换, 思路简单得很。

           在数据结构中, 又有哈希表, 这个是什么玩意儿呢? 对于非计算机专业的我来说, 开始是不太好理解的, 其实思路非常非常简单。 我们来看个场景: 有系列字符串"beibei", "jingjing", "huanhuan", "yingying", "nini",  怎么判断给定的字符串"xxx"是否在其中呢? 这个简单, 一个一个比较嘛, 更高级点就是排序后二分查找嘛, 或者装逼地搞个二叉排序树嘛, 逼格更高可以搞个红黑树嘛, 然而, 这些方法在哈希表面前, 简直弱爆了。 下面, 我们直接用代码来辅助理解(PHP中有md5函数, 所以用PHP搞起):

    <?php
        $ht[md5("beibei")] = "beibei";
        $ht[md5("jingjing")] = "jingjing";
        $ht[md5("huanhuan")] = "huanhuan";
        $ht[md5("yingying")] = "yingying";
        $ht[md5("nini")] = "nini";
        
        $x = "xxx";
        if($ht[md5($x)] == $x)
        {
            echo $x . " ok\n";
        }
        
        $x = "jingjing";
        if($ht[md5($x)] == $x)
        {
            echo $x . " ok\n";
        }
    ?>
    
          结果是:jingjing ok

          可见, 可以快速判断$x是否在一直的字符串集中中, 不需要轮询比较判断。 注意, 上述程序可以继续化简! 程序中的ht就是hash table

       

          上面的程序还可以继续优化, ht的值可以用0,1来标识。

      

          其实, 这么简单的东西, 真的不需要再多说。



    展开全文
  • 数据结构---哈希表

    2020-10-18 16:26:44
    前面讲到,哈希表就是利用数组和链表进行存储数据,那什么样的数组+链表可以被称作哈希表呢? 哈希表 = hash函数 + 数组(+链表) so,什么是hash函数(也可以成为hash算法)? 如果想要专业的解释,请查看百度百科...

    哈希表简述,不包含代码实现

    哈希表所需基础知识

    1. 数组
    2. 指针
    3. 链表
    4. 模运算(%)

    哈希表的数据存储结构

    使用哈希表进行数据存储,本质上是使用数组+链表的方式进行存储。可以这么理解,数组中存储的是一个个链表的头指针。

    详细情况会在后面介绍哈希表构造方式时介绍。

    哈希表是什么

    前面讲到,哈希表就是利用数组和链表进行存储数据,那什么样的数组+链表可以被称作哈希表呢?

    哈希表 = hash函数 + 数组(+链表)

    so,什么是hash函数(也可以成为hash算法)?

    如果想要专业的解释,请查看百度百科。在这里我就讲一点我的理解。

    hash函数的形式

    举一个简单的例子,h(key) = key%7,这个函数很容易看懂,就是对输入的变量取关于7的模。而hash函数就是一系列取模的函数。

    hash函数的作用

    hash的意译是散列,音译是哈希,作用就是对数据进行分类,比如上面的h(key) = key%7 这个函数,就把所有输入的key分成了7组。

    那你可能会想到,如果一组数据中,有两个数据取模之后的值一样怎么办?这就是我们下面要讲的,哈希值冲突

    哈希值冲突

    什么是哈希值冲突?

    前面说过了,就不再赘述。

    怎么解决哈希值冲突?

    1. 链表法
      所谓链表法,就是在数组中存储一条条链表的头指针,产生哈希值冲突的时候,就直接添加到链表的末尾就好了。
    2. 开放地址法
      a. 线性探测法
      产生冲突之后,去数组下一个位置,看看是不是空的。比如在下标为4的地方冲突了,看看5是不是空的,如果不是,再去看6,直到找到一个空的位置。
      b. 平方探测法
      产生冲突之后,第一次去下一个位置,第二次去向后数22的地方看看是不是空的。还是以 h(key) = key%7 这个函数为例,如果在1产生了冲突,先去2看看,不为空就去5看看,还不为空就去3看看(数组循环)……
      c. 双哈希
      h1(key) = key%7
      h2(key) = 5 - (key%5)
      h2是只在产生冲突的时候使用,比如一个数据块的key是2,存储这个数据的时候在2这里产生了冲突,那么向下找5 - (key%5) = 3个位置,在5这里看看是不是可以存储,如果不行,就向下找2*3 = 6个位置,去1这里……

    注意,h2的模要比h1,并且选的***取模数字一定是质数***

    本文参考

    参考了B站的两个视频,下面附上链接
    视频一
    视频二

    展开全文
  • 数据结构---散列表(Hash table, 哈希表)

    千次阅读 2018-06-03 12:42:41
     上大学时数据结构肯定学过 哈希,不过很多细节都忘了,惭愧, 最近看 “算法图解”,阅读了一下。还是梳理一下以前所学知识。    如果用专业术语来表达的话, 散列函数就是“将输入映射到数字”。你可能认为...

    2018.6.2

               上大学时数据结构肯定学过  哈希,不过很多细节都忘了,惭愧, 最近看    “算法图解”,阅读了一下。还是梳理一下以前所学知识。

     

                    如果用专业术语来表达的话, 散列函数就是“将输入映射到数字”。你可能认为散列函数输出的数字没什么规律,但其实散列函数必须满足一些要求。

     它必须是一致的。例如,假设你输入apple时得到的是4,那么每次输入apple时,得到的都必须为4。如果不是这样,散列表将毫无用处。

     它应将不同的输入映射到不同的数字。例如,如果一个散列函数不管输入是什么都返回1,它就不是好的散列函数。最理想的情况是,将不同的输入映射到不同的数字。

     

             散列表是 一种包含额外逻辑的数据结构。数组和链表都被直接映射到内存,但散列表更复杂,它使用散列函数来确定元素的存储位置。

                散列表的速度很快!关于数组和链表 你可以立即获取数组中的元素,而散列表也使用数组来存储数据,因此其获取元素的速度与数组一样快。

             你可能根本不需要自己去实现散列表,任一优秀的语言都提供了散列表实现。Python/Java/C#等提供的散列表实现为字典 。 C#也还有 Hashtable 类(可以简单理解 泛型和非泛型版本),   Hashtable and Dictionary Collection Types  官方有介绍两者区别。 但是没有看到有序无序的问题。  Difference between Hashtable and Dictionary    这里也有详细介绍 。    当我们在“Dictionary”中添加多个条目时,条目的添加顺序将保持不变(有序就是添加顺序)。 当我们从Dictionary中检索所有项时,我们将按照我们插入它们的相同顺序获取记录。 如果我们在Hashtable中添加相同的记录,但是这个顺序不会保留。  可以测试一下。

     

     

    散列表用途广泛,介绍几个应用案例:

    1 将散列表用于查找

    2 防止重复

    3 将散列表用作缓存(redis/memcache数据库都是作为缓存的!)

     

    冲突

           大多数语言都提供了散列表实现,你不用知道如何实现它们。 但你依然需要考虑性能!要明白散列表的性能,你得先搞清楚
    什么是冲突。 

    冲突(collision):给两个键分配的位置相同(映射到同一个数字上了)。 

     

    处理冲突的方式很多,最简单的办法如下:如果两个键映射到了同一个位置,就在这个位置存储一个链表。 所谓的  拉链法

        下面的两个key :apples, Avocados 都映射到 同一个位置了

     

                  apple和avocado映射到了同一个位置,因此在这个位置存储一个链表。在需要查询香蕉的价格时,速度依然很快。但在需要查询苹果的价格时,速度要慢些:你必须在相应的链表中找到apple。如果这个链表很短,也没什么大不了——只需搜索三四个元素。但是,假设你工作的杂货店只销售名称以字母A打头的商品。

               等等!除第一个位置外,整个散列表都是空的,而第一个位置包含一个很长的列表!换言之,这个散列表中的所有元素都在这个链表中,这与一开始就将所有元素存储到一个链表中一样糟糕:散列表的速度会很慢。

     

               听我们服务器Java程序同事说, 他们Java字典中的数据结构是  哈希表 + 红黑树,如果冲突的链表的长度超过8个的时候会转为红黑树(它的查询,插入删除操作都是logn).

     

    这里的经验教训有两个。

    散列函数很重要。前面的散列函数将所有的键都映射到一个位置,而最理想的情况是,散列函数将键均匀地映射到散列表的不同位置。 

    如果散列表存储的链表很长,散列表的速度将急剧下降。然而,如果使用的散列函数很好,这些链表就不会很长!散列函数很重要,好的散列函数很少导致冲突。那么,如何选择好的散列函数呢? 

     

    要避免冲突,需要有:

     较低的填装因子;

     良好的散列函数。

     

    1 填装因子

             散列表的填装因子很容易计算。散列表使用数组来存储数据,因此你需要计算数组中被占用的位置数。例如,下述散列表的填装因子为2/5,即0.4。

    下面这个散列表的填装因子为多少呢?

    如果你的答案为1/3,那就对了。填装因子度量的是散列表中有多少位置是空的。

                假设你要在散列表中存储100种商品的价格,而该散列表包含100个位置。那么在最佳情况下,每个商品都将有自己的位置。

     

              这个散列表的填装因子为1。如果这个散列表只有50个位置呢?填充因子将为2。不可能让每种商品都有自己的位置,因为没有足够的位置!填装因子大于1意味着商品数量超过了数组的位置数。一旦填装因子开始增大,你就需要在散列表中添加位置,这被称为调整长度(resizing)。例如,假设有一个像下面这样相当满的散列表。

    你就需要调整它的长度。为此,你首先创建一个更长的新数组:通常将数组增长一倍。

                   接下来,你需要使用函数hash将所有的元素都插入到这个新的散列表中。

            这个新散列表的填装因子为3/8,比原来低多了!填装因子越低,发生冲突的可能性越小,散列表的性能越高。一个不错的经验规则是:一旦填装因子大于0.7,就调整散列表的长度。你可能在想,调整散列表长度的工作需要很长时间!你说得没错,调整长度的开销很大,因此你不会希望频繁地这样做。但平均而言,即便考虑到调整长度所需的时间,散列表操作所需的时间也为O(1)。

     

     

    2 良好的散列函数

                良好的散列函数让数组中的值呈均匀分布。

    糟糕的散列函数让值扎堆,导致大量的冲突。

            什么样的散列函数是良好的呢?   如果你好奇,可研究一下SHA函数 。你可将它用作散列函数。 

                  比如在版本控制git中就用到了hash:在git中,文件内容为键值,并用SHA算法作为hash function,将文件内容对应为固定长度的字符串(hash值)。如果文件内容发生变化,那么所对应的字符串就会发生变化。git通过比较较短的hash值,就可以知道文件内容是否发生变动。

                再比如计算机的登陆密码,一般是一串字符。然而,为了安全起见,计算机不会直接保存该字符串,而是保存该字符串的hash值(使用MD5、SHA或者其他算法作为hash函数)。当用户下次登陆的时候,输入密码字符串。如果该密码字符串的hash值与保存的hash值一致,那么就认为用户输入了正确的密码。这样,就算黑客闯入了数据库中的密码记录,他能看到的也只是密码的hash值。上面所使用的hash函数有很好的单向性:很难从hash值去推测键值。因此,黑客无法获知用户的密码。

     

     

    还有两种解决冲突的方法:

              a)开放地址法
    开放地执法有一个公式:Hi=(H(key)+di) MOD m i=1,2,...,k(k<=m-1)
    其中,m为哈希表的表长。di 是产生冲突的时候的增量序列。如果di值可能为1,2,3,...m-1,称线性探测再散列
    如果di取1,则每次冲突之后,向后移动1个位置.如果di取值可能为1,-1,2,-2,4,-4,9,-9,16,-16,...k*k,-k*k(k<=m/2) 
    二次探测再散列。如果di取值可能为伪随机数列。称伪随机探测再散列。仍然以学生排号作为例子,
    现有两名同学,李四,吴用。李四与吴用事先已排好序,现新来一名同学,名字叫王五,对它进行编制

     

    10.. .... 22 .. .. 25
    李四.. .... 吴用 .. .. 25

       赵刚未来之前

     

    10.. .. 22 23 25
    李四..   吴用 王五  

       (a)线性探测再散列对赵刚进行编址,且di=1

     

     

    10... 20 22 .. 25
    李四.. 王五 吴用    

       (b)二次探测再散列,且di=-2 

     

     

    1... 10... 22 .. 25
    王五.. 李四.. 吴用    

       (c)伪随机探测再散列,伪随机序列为:5,3,2 

               b)再哈希法 
    当发生冲突时,使用第二个、第三个、哈希函数计算地址,直到无冲突时。缺点:计算时间增加。
    比如上面第一次按照姓首字母进行哈希,如果产生冲突可以按照姓字母首字母第二位进行哈希,再冲突,第三位,直到不冲突为止

     

    就这三种方法!

     

     

    哈希散列方法

    1)除留取余法 
    2)平方散列法 
    3)Fibonacci散列法

     

    展开全文
  • 哈希的故事(一)

    2020-08-27 19:27:18
    HashTable的简单实现引言什么是HashTable哈希冲突的解决 引言 咳咳,前两天面试的某公司...本着在哪里跌倒就哪里爬起来的精神,我来实现一个简单的哈希表什么是HashTable 严的书中是这样解释的: 将关键码映

    引言

    在哪里跌倒就哪里爬起来的。

    什么是HashTable

    严的书中是这样解释的:

    将关键码映射到表中某个位置上来存储数据,然后根据关键码来对数据访问。

    即:

    index=Hash(key);
    int Hash(int key){
    	return (key%p);//为了保证均等的映射概率,p应该为距离空间容量最近的素数
    }
    

    使用哈希函数得到地址,然后

    void insert(Type &x){
    	//新建节点并使用头插插入哈希表中
    }
    

    通常来说哈希表的使用是来解决大量的数据的搜索的,一般数据量越大,哈希能提高的效率就越高。

    哈希冲突的解决

    哈希表的特点是空间少而数据多,无论p设计的多完美,哈希冲突是必然存在的。所以说哈希表其实就干两件事:映射(产生冲突)、处理冲突。
    哈希冲突的解决方法有很多,可分为开散列法和闭散列法两大类,最常用的还是除留余数法+链地址法。

    HashTable的简单实现(头插)

    废话不多说:

    //hashtable
    #include<iostream>
    #include<vector>
    #include<memory>
    #include<cstring>
    using namespace std;
    
    
    template<class Type>
    class HashNode{
    	//friend class HashTable<Type,_N>; //这里_N报错,GG,于是把私有改为public了,暂时还没想到好的解决办法
    public:
    	HashNode(Type d=Type()):data(d),link(nullptr)
    	{}
    public:
    	Type data;
    	HashNode* link;
    };
    //默认7
    template<class Type,size_t _N=7> 
    class HashTable{
    public:
    	HashTable(){
    		memset(ht,0,sizeof(HashTable<Type>*)*_N);
    	}
    	void insert(Type &x){
    		int index=HashFun(x);//下标计算
    		//头插
    		HashNode<Type>* s=new HashNode<Type>(x);
    		s->link=ht[index];
    		ht[index]=s;
    	}
    protected:
    	int HashFun(Type &key){
    		return key%_N; //哈希函数
    	}
    private:
    	HashNode<Type>* ht[_N];
    };
    int main(){
    	HashTable<int> ht;
    	//测试用例
    	vector<int> iv={1,2,8,15,20};
    	for(auto &e:iv)
    		ht.insert(e);
    	return 0;
    }
    

    在可以看到是ok的

    写到这里我不禁流下辛酸的泪水。

    展开全文
  • 数据结构,不说要彻底给面试官手推各种数据结构的均摊复杂度,也不要求你手写红黑树,至少AVL 哈希表 堆这些简单的数据结构得自己实现过;链表、线性表必须熟悉到不能再熟悉,比如vector为什么要用加倍扩容而不是...
  • //定义一个数组存放前十名在哈希表的下标 for (int i = 0; i ; i++) a[i] = -1; for (int i = 0; i ; i++)//遍历哈希表 { if (stu[i].name[0] != '\0') { int k = 9; for (; k >= 0; k--)//利用插入法...
  • 今天要分享的是工作当中最常用的一种数据结构:散列表也称哈希表。大家都用过字典,我们知道一个汉语一定会对应着一个英文单词,这种对应关系,在程序中有时也是非常需要的。因此,在程序世界里往往也会在内存中存放...
  • HashMap和Hashtable理解与对比

    万次阅读 多人点赞 2018-08-22 23:48:58
    一、概述 HashMap和Hashtable的区别在面试的时候经常会被问到,那么...为了简明描述哈希表(数组+链表),我画了一个图(不专业,轻喷)。 2、对应HashMap采用哈希表存储键值对元素的方式, 配合着上图做一些...
  • 路由表的结构与算法分析--trie查找

    千次阅读 2010-02-09 17:16:00
    linux中的路由查找算法一点也不比那些大型的专业路由器的查找算法差,所谓的专业路由器就是在...linux 的路由表具有高度的可扩展性,内置了256张路由表,对于策略路有的实现相当方便,缺省使用哈希表查找算法,那种方法
  • HashMap可以将这个单词 拆分为两部分理解 Hash 和 Map Hash 指的是哈希表 Map 指的是 Map接口 顾名思义 HashMap 哈希映射 就是 Java 基于哈希表的 Map 接口的实现 允许使用 NULL 键 和 NULL 值 HashMap 是 非线程...
  • A:一段连续的存储空间,类比数组的索引访问方式,哈希表的索引是根据哈希函数计算得来的;链地址法和开放地址法,开放地址法细节忘了。 Q:喜欢什么语言? A:c++(可能是希望我答java吧。。。) Q:map的底层实现...
  • 什么哈希函数,一个哈希函数必须具备哪些基本性质,它能应用在哪些场景 试简要说明 SHA-512 的执行过程 什么是消息验证码(MAC),对比它和哈希算法在安全性能上的不同 Feistel 模型是分组密码的经典模型;它的...
  • B站一面

    2020-10-19 22:39:28
    B站一面 面试总结: 1,问我看过什么书,对什么比较了解,数据结构,操作系统这种 为什么不是这个专业选这个工作 2,对安卓的那一块比较...9,arrayList和linkList的区别,哈希表 10,android UI渲染的过程,以及比如
  • 玩转数据结构

    2019-09-04 21:21:25
    什么要学习数据结构 数据结构是所有计算机专业的同学必学的课程 数据结构研究的是数据如何在计算机进行组织和存储,使得我们可以高效的获取数据或修改数据。...哈希表… 堆;Trie;线段树;K-D树; 并查树;...
  • 第1章 欢迎学习玩转数据结构为什么要学习数据结构在计算机的世界里,数据结构无处不在注意事项 为什么要学习数据结构 ...数组、栈、队列、链表、哈希表… 二叉树、二分搜索树、AVL、红黑树、Treap、Splay、堆、Tri...
  • java面试3

    2020-04-23 04:08:09
    学过什么专业课/技术 链表,数组的优缺点,应用场景,查找元素的复杂度 二叉树怎么实现的 Java中都有哪些锁 https://www.cnblogs.com/qifengshi/p/6831055.html 可重入锁的设计思路是什么 乐观锁和悲观锁 ...
  • MD5加密及’解密‘ 验签详解

    千次阅读 2017-08-29 15:00:37
    什么MD5不能解密? MD5 是不可逆的 也就是没有对应的算法,能从生产的md5值逆向得到原始数据。 md5作为数据库中的主键可行吗?这就涉及到一个问题,md5值...计算机专业学的数据结构就有哈希表这一知识点。 比如10除
  • md5加密后不能解密

    2019-06-01 13:50:00
    计算机专业学的数据结构就有哈希表这一知识点。比如10除以3余数为一,4除以3余数也为一,但余数为一的就不知道这个数是哪个了。所以md5不能解密。就算是设计这个加密算法的人都不知道。但是你的密码是怎么验证的呢?...
  • MD5加密

    2018-03-29 23:27:39
    计算机专业学的数据结构就有哈希表这一知识点。 比如10除以3余数为一,4除以3余数也为一,但余数为一的就不知道这个数是哪个了。 所以md5不能解密。 就算是设计这个加密算法的人都不知道。 但是你的密码是怎么验证的...
  • MD5加密解密

    2017-04-25 11:20:32
    计算机专业学的数据结构就有哈希表这一知识点。 比如10除以3余数为一,4除以3余数也为一,但余数为一的就不知道这个数是哪个了。 所以md5不能解密。 就算是设计这个加密算法的人都不知道。 但是你的密码是怎么验证的...
  • [导入]到底该怪谁?

    2019-10-09 03:58:02
    今天下午面试了一个应届毕业生,信息安全专业。我问他:“对什么课程最有...那你给我讲讲哈希表是怎么回事吧。”他:“哈希...?”停顿10秒钟,一脸茫然。我:“是不是学的时间久了,忘了?这样吧,你刚刚做的毕业设...
  • - 趋势科技–3.5线上面试–C++工程师 ...哈希表和哈希函数 动态库链接? 程序编译的具体过程 虚函数,虚基类? C++类/多态 到后来面试官已经让我知道什么什么了,确实太紧张了,大脑一片空白。最后让我问了几

空空如也

空空如也

1 2 3 4 5
收藏数 91
精华内容 36
关键字:

哈希表什么专业