算法学习系列(7)——哈希表、布隆过滤器、一致性哈希、岛问题、并查集

1.认识哈希函数和哈希表

哈希函数及其重要,在大数据的题目中常考。下边介绍几个哈希函数相关的概念:

1.1什么是 Hash

Hash(哈希),又称“散列”。

散列(hash)英文原意是“混杂”、“拼凑”、“重新表述”的意思。

在某种程度上,散列是与排序相反的一种操作,排序是将集合中的元素按照某种方式比如字典顺序排列在一起,而散列通过计算哈希值,打破元素之间原有的关系,使集合中的元素按照散列函数的分类进行排列。

在介绍一些集合时,我们总强调需要重写某个类的 equlas() 方法和 hashCode() 方法,确保唯一性。这里的 hashCode() 表示的是对当前对象的唯一标示。计算 hashCode 的过程就称作 哈希。

1.2为什么要有 Hash

我们通常使用数组或者链表来存储元素,一旦存储的内容数量特别多,需要占用很大的空间,而且在查找某个元素是否存在的过程中,数组和链表都需要挨个循环比较,而通过 哈希 计算,可以大大减少比较次数。

在这里插入图片描述

1.3举个栗子:

现在有 4 个数 {2,5,9,13},需要查找 13 是否存在。

1.使用数组存储,需要新建个数组 new int[]{2,5,9,13},然后需要写个循环遍历查找:

int[] numbers = new int[]{2,5,9,13};
for (int i = 0; i < numbers.length; i++) {
    if (numbers[i] == 13){
        System.out.println("find it!");
        return;
    }
}

这样需要遍历 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)。

因此可以发现,哈希 其实是随机存储的一种优化,先进行分类,然后查找时按照这个对象的分类去找。
哈希通过一次计算大幅度缩小查找范围,自然比从全部数据里查找速度要快。
比如你和我一样是个剁手族买书狂,家里书一大堆,如果书存放时不分类直接摆到书架上(数组存储),找某本书时可能需要脑袋从左往右从上往下转好几圈才能发现;如果存放时按照类别分开放,技术书、小说、文学等等分开(按照某种哈希函数计算),找书时只要从它对应的分类里找,自然省事多了。

1.4哈希函数

哈希的过程中需要使用哈希函数进行计算。

哈希函数是一种映射关系,根据数据的关键词 key ,通过一定的函数关系,计算出该元素存储位置的函数。

表示为:

address = H [key]

哈希函数的实现等查看:哈希函数

1.5 哈希函数的特点:

  • 1)Hash可用于任意大小的数据块;
  • (2)hash可以接受任意长度的信息,并将其输出成固定长度的消息摘要;
  • (3)单向性。给定一个输入M,一定有一个h与其对应,满足H(M)=h,反之,则不行,算法操作是不可逆的。
  • (4)抗碰撞性。给定一个M,要找到一个M’满足是不可H(M)=H(M’)是不可能的。即不能同时找到两个不同的输入使其输出结果完全一致。
  • (5)低复杂性:算法具有运算的低复杂性。

1.6 哈希表常用的功能演示

代码:

//哈希表的增删改查的复杂度是近似于O(1),实际应该是O(log5N之类的形式)
public class Code_01_HashMap {
   

	public static void main(String[] args) {
   
		HashMap<String, String> map = new HashMap<>();
		map.put("wang", "31");

		System.out.println(map.containsKey("wang"));
		System.out.println(map.containsKey("laowu"));
		System.out.println("=========================");

		System.out.println(map.get("wang"));
		System.out.println(map.get("laowu"));
		System.out.println("=========================");

		System.out.println(map.isEmpty());
		System.out.println(map.size());
		System.out.println("=========================");

		System.out.println(map.remove("wang"));
		System.out.println(map.containsKey("wang"));
		System.out.println(map.get("wang"));
		System.out.println(map.isEmpty());
		System.out.println(map.size());
		System.out.println("=========================");

		map.put("wang", "31");
		System.out.println(map.get("wang"));
		map.put("wang", "32");
		System.out.println(map.get("wang"));
		System.out.println("=========================");

		map.put("wang", "31");
		map.put("lao", "32");
		map.put("wu", "33");

		for (String key : map.keySet()) {
   
			System.out.println(key);
		}
		System.out.println("=========================");

		for (String values : map.values()) {
   
			System.out.println(values);
		}
		System.out.println("========================="
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值