前面给大家讲了哈希表(散列)这种数据结构,那么使用哈希表来解决实际问题,那就是Hash算法了,我们一起来看看。
Hash算法(Hash Algorithm),简称散列算法,也成哈希算法(英译),是将一个大文件映射成一个小串字符。与指纹一样,就是以较短的信息来保证文件的唯一性的标志,这种标志与文件的每一个字节都相关,而且难以找到逆向规律。
举个列子:
服务器存了10个文本文件,你现在想判断一个新的文本文件和那10个文件有没有一个是一样的。你不可能去比对每个文本里面的每个字节,很有可能,两个文本文件都是5000个字节,但是只有最后一位有所不同,但这样的,你前面4999位的比较就是毫无意义。那一个解决办法,就是在存储那10个文本文件的时候,都将每个文件映射成一个hash字符串。服务器只需要存储10个hash字符串,在判断的时候,只需要判断新的这个文本文件的hash值是否和那10个文件的hash值一致,那就可以解决这个问题了。
由于文件是无限的,而映射后的字符串能表示的位数是有限的。因此可能会存在不同的key对应相同的Hash值。这就存在碰撞的可能。
java的数据结构中,很多类都有用到hash算法,比如String,HashMap。
public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; }
可以看到,这里使用了31来作为乘级因子,这是为什么呢?
存在的目的是加速键值对的查找,key的作用是为了将元素适当的放在各个桶里,对于抗碰撞的要求没那么高。
static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }
对key的hash计算,就是计算出key的hash值,并移动到低位,完成高低位的融合。
hash算法在密码学中主要是用于消息摘要和签名。换句话说,主要是对整个消息的完整性进行校验。
安全散列算法(英语:Secure Hash Algorithm,缩写为SHA),SHA家族的五个算法,分别是SHA-1、SHA-224、SHA-256、SHA-384,和SHA-512,由美国国家安全局(NSA)所设计,并由美国国家标准与技术研究院(NIST)发布;是美国的政府标准。后四者有时并称为SHA-2。
PS:尺取法:顾名思义,像尺子一样取一段,尺取法通常是对数组保存一对下标,即所选取的区间的左右端点,然后根据实际情况不断地推进区间左右端点以得出答案。
给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url?
腾讯面试题:A.txt和B.txt两个文件,A有1亿个qq号,B有100万个,用代码实现交、并、差...
可以估计每个文件安的大小为5G×64=320G,远远大于内存限制的4G。所以不可能将其完全加载到内存中处理。考虑采取分而治之的方法。
参考自两个上亿行的大文件取交集
TODO:Java实现版本还未写
PS:如果允许小误差,也可以采用如下的布隆算法实现
import java.util.ArrayList; import java.util.BitSet; import java.util.List; /** * BloomFilter算法 * * @author JYC506 * */ public class BloomFilter { /*哈希函数*/ private List<IHashFunction> hashFuctionList; /*构造方法*/ public BloomFilter() { this.hashFuctionList = new ArrayList<IHashFunction>(); } /*添加哈希函数类*/ public void addHashFunction(IHashFunction hashFunction) { this.hashFuctionList.add(hashFunction); } /*删除hash函数*/ public void removeHashFunction(IHashFunction hashFunction) { this.hashFuctionList.remove(hashFunction); } /*判断是否被包含*/ public boolean contain(BitSet bitSet, String str) { for (IHashFunction hash : hashFuctionList) { int hashCode = hash.toHashCode(str); if(hashCode<0){ hashCode=-hashCode; } if (bitSet.get(hashCode) == false) { return false; } } return true; } /*添加到bitSet*/ public void toBitSet(BitSet bitSet, String str) { for (IHashFunction hash : hashFuctionList) { int hashCode = hash.toHashCode(str); if(hashCode<0){ hashCode=-hashCode; } bitSet.set(hashCode, true); } } public static void main(String[] args) { BloomFilter bloomFilter=new BloomFilter(); /*添加3个哈希函数*/ bloomFilter.addHashFunction(new JavaHash()); bloomFilter.addHashFunction(new RSHash()); bloomFilter.addHashFunction(new SDBMHash()); /*长度为2的24次方*/ BitSet bitSet=new BitSet(1<<25); /*判断test1很test2重复的字符串*/ String[] test1=new String[]{"哈哈","我","大家","逗比","有钱人性","小米","Iphone","helloWorld"}; for (String str1 : test1) { bloomFilter.toBitSet(bitSet, str1); } String[] test2=new String[]{"哈哈","我的","大家","逗比","有钱的人性","小米","Iphone6s","helloWorld"}; for (String str2 : test2) { if(bloomFilter.contain(bitSet, str2)){ System.out.println("‘"+str2+"‘是重复的"); } } } } /*哈希函数接口*/ interface IHashFunction { int toHashCode(String str); } class JavaHash implements IHashFunction { @Override public int toHashCode(String str) { return str.hashCode(); } } class RSHash implements IHashFunction { @Override public int toHashCode(String str) { int b = 378551; int a = 63689; int hash = 0; for (int i = 0; i < str.length(); i++) { hash = hash * a + str.charAt(i); a = a * b; } return hash; } } class SDBMHash implements IHashFunction { @Override public int toHashCode(String str) { int hash = 0; for (int i = 0; i < str.length(); i++) hash = str.charAt(i) + (hash << 6) + (hash << 16) - hash; return hash; } }
现有海量日志数据保存在一个超级大的文件中,该文件无法直接读入内存,要求从中提取某天出访问百度次数最多的那个IP。
处理海量数据问题思路:
我的微信公众号:架构真经(id:gentoo666),分享Java干货,高并发编程,热门技术教程,微服务及分布式技术,架构设计,区块链技术,人工智能,大数据,Java面试题,以及前沿热门资讯等。每日更新哦!
参考资料:
原文:https://www.cnblogs.com/anymk/p/11521507.html