哈希查找

数据结构之哈希、哈希函数、哈希表

被刻印的时光 ゝ 提交于 2020-01-16 01:46:36
什么是哈希? 哈希,也称散列。在某种程度上,散列是与排序相反的一种操作,排序是将集合中的元素按照某种方式比如大小顺序排列在一起,而散列通过计算哈希值,打破元素之间原有的关系,使集合中的元素按照散列函数的分类进行排列。 为什么用哈希? 我们通常使用数组或者链表来存储元素,一旦存储的内容数量特别多,需要占用很大的空间,而且在查找某个元素是否存在的过程中,数组和链表都需要挨个循环比较,而通过 哈希 计算,可以大大减少比较次数。下面举个例子! 现在有 4 个数 {2,5,9,13},需要查找 13 是否存在。 1.使用数组存储,需要新建个数组 new int[]{2,5,9,13},然后需要写个循环遍历查找,这样需要遍历 4 次才能找到,时间复杂度为 O(n)。 2.而假如存储时先使用哈希函数进行计算,这里我随便用个函数: H[key] = key % 3; 四个数 {2,5,9,13} 对应的哈希值为: H[2] = 2 % 3 = 2; H[5] = 5 % 3 = 2; H[9] = 9 % 3 = 0; H[13] = 13 % 3 = 1; 然后把它们存储到对应的位置。 当要查找 13 时,只要先使用哈希函数计算它的位置,然后去那个位置查看是否存在就好了,本例中只需查找一次,时间复杂度为 O(1)。 因此可以发现,哈希 其实是随机存储的一种优化,先进行分类

高维向量快速检索方法Locality Sensitive Hashing之一汉明空间和欧式空间实现

给你一囗甜甜゛ 提交于 2020-01-15 01:14:07
1 高维向量检索问题 高维向量检索主要解决由数据维数增加所引发检索速度急剧下降的的问题。高维空间中数据的特点主要包括以下三个方面: (1) 稀疏性。随着维度增长,数据在空间分布的稀疏性增强; (2) 空空间现象。对于服从正态分布的数据集,当维数大约增加到10时,只有不到1%的数据点分布在中心附近; (3) 维度效应。随着维数的增加,对索引的维护效率急剧下降,并且高维空间中数据点之间的距离接近于相等。 2 树索引方法在高维检索中的缺点 传统的树索引方法,如基于数据划分的索引R-tree、R-tree、SR-tree、k-d tree等和基于空间划分的索引quad-tree、kdb-tree等,在特征维度不高的情况下具有良好的性能,在特征维数足够高的情况下(超过几十维),它们的性能会退化到最原始的顺序查找,这就是所谓的“维度灾难”。树索引方法在高维情况下主要面临着三个困难: (1) 每次划分只使用了特征向量一个维度的信息,在高维情况下这种数据划分方法效率很低; (2) 需要某种形状的覆盖对象来表示某个区域,而固定形状的覆盖对象对区域的描述会有偏差。在高维情况下这个偏差会更明显; (3) 为了获得精确最近邻检索的结果,索引的性能退化到顺序查找的程度。 3 ANN和LSH 由于精确最近邻搜索计算代价高、算法效率低,人们采用近似最近邻搜索方法完成检索的任务。当前

哈希表相关

早过忘川 提交于 2020-01-13 00:20:16
由于哈希表的查找高效性,在平时的算法中用的也比较多。例如:字符串、单词个数统计、只出现一次字符或者数字的统计,两个集合相同元素的查找等等,还有插入删除的高效(链地址法)都可以用哈希表来解决。所以这里对其做一个小小的总结。缺点是可能需要占用额外的内存空间。 一、哈希函数的构造方法 下面介绍五种常用的哈希构造方法: 构造哈希函数的原则是: (1)函数本身便于计算; (2)计算出来的地址分布均匀,即对任一关键字k,f(k)对应不同地址的概率相等,目的是尽可能减少冲突。 1、除留余数法 取关键字被某个不大于哈希表长m的数p除后所得的余数为哈希地址。即: H(key)=key MODE p,p<=m(p的取值最好为素数)。 若冲突较多,可取较大的m和p值。 2、随机法 采用一个伪随机函数做哈希函数,即: H(key)= random(key)。其中random为随机函数。 通常,当关键字长度不等时采用此构造哈希函数比较恰当。 3、平方取中法 当无法确定关键字中那几位分布较均匀时,可以先求出关键字的平方值,然后按需要取平方值的中间几位作为哈希地址。 这是因为:平方后中间几位和关键字中每一位都相关,故不同关键字会以较高的概率产生不同的哈希地址。 例如对于关键key:123。123^2=1522756,H(K)关键字的哈希地址为:227 4、折叠法

数据结构---->哈希表

馋奶兔 提交于 2020-01-12 04:39:53
一、哈希表 哈希表又称散列表。 哈希表存储的基本思想是:以数据表中的每个记录的关键字k为自变量,通过一种函数H(k)计算出函数值。把这个值解释为一块连续存储空间(即数组空间)的单元地址(即下标),将该记录存储到这个单元中。 在此称该函数H为哈希函数或散列函数。按这种方法建立的表称为哈希表或散列表。 例如,要将关键字值序列(3,15,22,24),存储到编号为0到4的表长为5的哈希表中。 计算存储地址的哈希函数可取除5的取余数算法H(k)=k% 5。则构造好的哈希表如图所示。 理想情况下,哈希函数在关键字和地址之间建立了一个一一对应关系,从而使得查找只需一次计算即可完成。由于关键字值的某种随机性,使得这种一一对应关系难以发现或构造。因而可能会出现不同的关键字对应一个存储地址。即 k1≠k2 , 但 H(k1)=H(k2 ), 这种现象称为 冲突 。 把这种具有不同关键字值而具有相同哈希地址的对象称 “ 同义词 ” 。 在大多数情况下,冲突是不能完全避免的。这是因为所有可能的关键字的集合可能比较大,而对应的地址数则可能比较少。 对于哈希技术,主要研究两个问题: (1)如何设计哈希函数以使冲突尽可能少地发生。 (2)发生冲突后如何解决 。 二、哈希函数 构造好的 哈希函数 的方法,应能使冲突尽可能地少,因而应具有较好的随机性。这样可使一组关键字的散列地址均匀地分布在整个地址空间

LeetCode 1 两数之和(哈希map)

你离开我真会死。 提交于 2020-01-10 13:13:14
1.给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 ****暴力解法:**** vector < int > twoSum ( vector < int > & nums , int target ) { int len = nums . size ( ) ; //vector的容器大小是size() vector < int > result ; //用来存放最后的结果 for ( int i = 0 ; i < len ; i ++ ) //遍历数组,固定一个位置找另一个位置 { int k = target - nums [ i ] ; for ( int j = i + 1 ; j < len ; j ++ ) { if ( nums [ j ] == k ) { result . push_back ( i ) ; result . push_back ( j ) ; } } } return result ; } 暴力法思路很简单,就是固定一个位置i,然后在数组中查找target-nums[i]的位置,找到返回即可 时间复杂度是O(n^2); **哈希解法:** 散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说

深度解密Go语言之map

自作多情 提交于 2020-01-08 08:51:52
目录 什么是 map 为什么要用 map map 的底层如何实现 map 内存模型 创建 map 哈希函数 key 定位过程 map 的两种 get 操作 如何进行扩容 map 的遍历 map 的赋值 map 的删除 map 进阶 可以边遍历边删除吗 key 可以是 float 型吗? 总结 参考资料 这篇文章主要讲 map 的赋值、删除、查询、扩容的具体执行过程,仍然是从底层的角度展开。结合源码,看完本文一定会彻底明白 map 底层原理。 我要说明的是,这里对 map 的基本用法涉及比较少,我相信可以通过阅读其他入门书籍了解。本文的内容比较深入,但是由于我画了各种图,我相信很容易看懂。 什么是 map 维基百科里这样定义 map: In computer science, an associative array, map, symbol table, or dictionary is an abstract data type composed of a collection of (key, value) pairs, such that each possible key appears at most once in the collection. 简单说明一下:在计算机科学里,被称为相关数组、map、符号表或者字典,是由一组 <key, value>

Bloom过滤器

喜你入骨 提交于 2019-12-27 00:20:56
提出一个问题 在我们细述Bloom过滤器之前,我们先抛出一个问题:给你一个巨大的数据集(百万级、亿级......),怎么判断一个元素是否在此数据集中?或者怎么判断一个元素不在此数据集中? 思考这个问题的时候,最先想到的可能是哈希表,在数据集规模较小的时候,这个方法是可行的,当然,数据集巨大的时候也可以采用分布式哈希表的方式。当数据集规模较大时,尤其是应用中只需要判断一个元素不在此数据集中的情况时,我们可以借鉴哈希表的思路,使用Bloom过滤器解决这个问题。既然我们只关心元素在不在,不关心元素值是什么,只要把元素映射为一个布尔值表示在不在就足够了。下面细述Bloom过滤器数据结构的设计。 Bloom过滤器数据结构 Bloom filter(布鲁姆过滤器)是用于测试元素成员资格的空间高效概率数据结构。数据结构以牺牲规定的假阳性率为代价实现了巨大的数据压缩。一个Bloom过滤器作为一个 m 位的数组全部设置为 0 。选择一组 k 个随机散列函数,在Bloom过滤器中添加元素时,元素将分别进行哈希散列,而对于每个 k 个输出,该索引处的相应的Bloom过滤器位将被设置为 1 。通过使用与之前相同的散列函数来完成Bloom过滤器的查询。如果在bloom过滤器中访问的所有 k 个比特被设置为 1 ,则这很可能表明该元素位于该集合中。删除元素只能通过废除Bloom过滤器并从头重新创建来完成

哈希结构及应用

拟墨画扇 提交于 2019-12-25 17:45:36
哈希 可以不经过任何比较,一次直接从表中得到搜索的元素,像那些 vecotor ,list ,AVL 呀,都是必须经过比较之后才能找到元素的,所以哈希在查找元素方面时间复杂度是O(1) 那它是怎么做到的呢?其实是通过某种函数使元素的存储位置与它的关键码之间建立一种映射关系 哈希表的实现主要是 构造哈希 和 处理哈希冲突 两方面 我们先讨论如何构造,最后讨论如何处理哈希冲突 对于构造哈希来说,常见的哈希函数包括 直接地址法 , 除留余数法 ,平方取中法,折叠法,随机数法… 那么选择什么样的哈希函数主要取决于关键字的特点 (1) 如果事先知道关键字的分布情况,并且发现这些关键字很小,而且连续,那么就可以采用 直接地址法或者除留余数法 直接地址法 :取关键字的某个线性函数为散列地址:Hash(Key)= A * key + B 除留余数法 :假如散列表中允许的地址数为 m ,取一个不大于 m 且最接近 m 的一个质数 p 作为除数 ,按照哈希函数 Hash(key) = key % p (p<=m),将关键码转换成哈希地址 (2) 如果不知道关键的分布,且这些关键字的位数也不大,就可以采用平方取中法。 平方取中法:对一个数平方后取出中间的数字作为哈希地址,这种方法适合于不知道关键字的分布且位数也不是很大的情况 (3) 如果不知道关键字的分布,且这些关键字的位数很大的情况,可以采用折叠法。

Java8 HashMap源码分析

与世无争的帅哥 提交于 2019-12-25 05:42:14
java.util.HashMap 是最常用的java容器类之一, 它是一个线程不安全的容器. 本文对JDK1.8.0中的HashMap实现源码进行分析. HashMap 使用位运算巧妙的进行散列并使用链地址法处理冲突. 自JDK1.8后, 若表中某个位置元素数超过阈值 则会将其自动转换为红黑树来提高检索效率. HashMap 中的迭代器同样采用 fail-fast 机制, 即若迭代过程中容器发生结构性改变, 则会终止迭代. HashMap 主要有三个视图接口 keySet() , values() , entrySet() . 它们都是基于迭代器实现的, 并不实际存储数据. 哈希表 自JDK1.8.0开始HashMap使用静态内部类 Node 来存储键值对结构, 不再使用 Map.Entry : static class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Node<K,V> next; Node(int hash, K key, V value, Node<K,V> next) {...} public final K getKey() { return key; } public final V getValue() { return value; }

如何正确对用户密码进行加密?转自https://blog.csdn.net/zhouyan8603/article/details/80473083

时间秒杀一切 提交于 2019-12-23 04:27:12
本文介绍了对密码哈希加密的基础知识,以及什么是正确的加密方式。还介绍了常见的密码破解方法,给出了如何避免密码被破解的思路。相信读者阅读本文后,就会对密码的加密有一个正确的认识,并对密码正确进行加密措施。 作为一名Web开发人员,我们经常需要与用户的帐号系统打交道,而这其中最大的挑战就是如何保护用户的密码。经常会看到用户账户数据库频繁被黑,所以我们必须采取一些措施来保护用户密码,以免导致不必要的数据泄露。 保护密码的最好办法是使用加盐密码哈希( salted password hashing)。 重要警告: 请放弃编写自己的密码哈希加密代码的念头 !因为这件事太容易搞砸了。就算你在大学学过密码学的知识,也应该遵循这个警告。所有人都要谨记这点:不要自己写哈希加密算法! 存储密码的相关问题已经有了成熟的解决方案,就是使用 phpass ,或者在 defuse/password-hashing 或 libsodium 上的 PHP 、 C# 、 Java 和 Ruby 的实现。在对密码进行哈希加密的问题上,人们有很多争论和误解,可能是由于网络上有大量错误信息的原因吧。对密码哈希加密是一件很简单的事,但很多人都犯了错。本文将会重点分享如何进行正确加密用户密码。 密码哈希是什么? hash("hello") =