跟着算法学GO(6)

933 阅读2分钟

「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战

生命不息,学习不止

题外话

大年初一啦,春节啦,新的一年在这里祝愿我和我的家人平安喜乐,虎虎生威;祝愿所有的人们开心快乐;祝愿世界没有疫情;祝愿掘金越办越好;祝愿祖国繁荣昌盛!

image.png

废话不多说,上货

在这里插入图片描述

LeetcCode-3

无重复字符的最长子串

题目如下:

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

还是这道题,因为还有知识点呢

go实现算法

func lengthOfLongestSubstring(s string) int {
	strmap := make(map[byte]int)

	count := 0
	for i, j := 0, 0; j < len(s); j++ {
		if val, ok := strmap[s[j]]; ok {
			i = max(val, i)
		}
		count = max(count, j-i+1)
		strmap[s[j]] = j + 1   //添加元素
	}
	return count
}

func max(x, y int) int {
	if x > y {
		return x
	} else {
		return y
	}
}

小问题回顾

小问题:为什么map是无序的?map的扩容机制是怎样的?底层实现又是怎样的?

Map的实现机制

上回说了map使用方式,和基础的存储机制,这次就来具体说说map的底层实现

go的map底层实现跟Java的hashmap有点相似,主要也是采用数组+链表,处理hash冲突时有所差异,java采用链表 转换红黑树的方式,go采用的是拉链的方式。

废话不多说,map的源码存放在go安装后src/runtime/map.go中,废话不多说,直接看源码(go1.17.3版本)

首先是定义了一个hamp,如下

image.png

挑几个重点属性说说

1.count 是元素的个数,也就是key键值的个数

2.B 是可以最多容纳 6.5 * 2 ^ B 个元素,6.5为装载因子

3.buckets 是桶的地址,oldbuckets 是旧桶地址,用于迁移

4.extra 是一个指针,指向一个包含了两个一维数组的对象,如下

image.png

这两个数组分别代表了两个溢出桶,为什么分为两个,主要是因为当多个相同key的hash值相同时,导致单个hash指向的桶会触发扩容,为了提高性能,减少全量搬运的情况,使用了增量搬运,overflow代表的是当前溢出桶的的集合。

同时,指向了下一个桶(bmap),如下

image.png

这里说一说这个tophash,英语好的兄弟们估计已经看明白了,其实就是一个状态显示位的数组

bucketCnt 在源码中也有声明,其实就是1 <<3,也就是8

image.png

说白了tophash存放了高8位的hash和他们对应的value,同时注解中也标记了 tophash[0] < minTopHash是一个迁移状态

minTopHash是已经定义好的状态值,其他的状态如下

image.png

这样,map核心的结构定义就清晰了

你以为结束了

小问题:元素存放的流程是怎样的?几个变量间如何关联? 下一篇就讲,敬请期待

在这里插入图片描述

大家看完发现有什么错误,写在下面吧!跟我黑虎阿福比划比划! 在这里插入图片描述