hash哈希是一种算法
MD5(Message Digest Algorithm 5)信息摘要算法5,输出是128位。运算速度叫SHA-1快
SHA(Secure Hash Algorithm)安全散列算法,包含一个系列算法,分别是SHA-1、SHA-224、SHA-256、SHA-384,和SHA-512。
package main
import (
"crypto/sha256"
"fmt"
)
func main() {
h := sha256.New()
h.Write([]byte("abc"))// 提供字节流
r := h.Sum(nil)
s := fmt.Sprintf("%x", r) // 把字节序列的每个字节以16进制显示
fmt.Printf("%T %s %d \n", r, s, len(s))
}
[]uint8 e4b0cf398b77ac6efb797544d268782dc7d082e59c4d1aff15f3ae661588f0eb 64
映射Map,也有语言称为字典
长度可变
存储的元素是key-value对(键值对),value可变
key无序不重复
不可索引,需要通过key来访问
不支持零值可用,也就是说,必须要用make或字面常量构造
引用类型
哈希表
map采用哈希表实现。Go的map类型也是引用类型,有一个标头值hmap,指向一个底层的哈希表。
存储kv对,一个kv对称为一个元素,键值对entry、item
len表示元素的个数,即 kv对的个数,cap不能用
key 不能重复,无序
引用类型
不支持零值可用
开辟一块内存空间,分割出一个个“房间”,这个房间称为bucket桶,按照y值为“房间”编号
使用给出的x计算出对应的y值,可以按照某种关系计算出数据将被存储到的“房间号码”,将数据存
入该房间
即使是hash函数设计的好,数据分布均匀,但是存储的数据很多(超过负载因子),则需要扩容,
否则再加入数据后,冲突太多,引起效率低下
理解:有key hash后的key value 三种
1、如果key相同 则hash后的key一定相同
2、key不相同但是存在hash后的key是相同的,也就是房间号是相同
我们可以理解hash后的key为房间号,hash冲突就是hash后的key是相同的,若hash就的key是相同的可以存放在一个房间里面,在这个房间里面可以放几个key-value对,若是查找这个key-value,先找到这个房间,在这个房间内在查找key
func main() {
var m1 map[string]int // nil,很危险。map不是零值可用
fmt.Println(m1, m1 == nil)
m1["t"] = 200 // panic,不可以
}
//结论:零值不可用,用var a map[int]int 零值是nil但是后面无法增加kv对
// 1 字面量
//字面量定义map[string]int{k1:v1} ,花括号表示字面量
func main() {
var m0 = map[string]int{} // 安全,没有一个键值对而已
fmt.Println(m0)
}
map[]
func main() {
var m1 = map[string]int{
"a": 11,
"b": 22,
"c": 33,
}
fmt.Println(m1)
}
map[a:11 b:22 c:33]
//make
func main() {
m2 := make(map[int]string) // 一个较小的起始空间大小
//make(map[string]int) // 没有告诉未来容纳多少元素,先开辟较小空间,如果未来kv对较多,可能频繁扩容
m2[100] = "abc"
m3 := make(map[int]string, 100) // 分配足够容量来容纳100个元素,长度为0。为了减少扩容,可以提前给出元素个数
fmt.Println(m2, m3)
}
map[100:abc] map[]
//结论:
make(map[string]int, 100) 表示为100个元素自动生成足够(内部按照算法生成)的空间 make(map[string]int, 100) 告诉未来容纳多少元素,先开辟合适的空间来存储这些kv对,注意一般空间大小别元素个数大一些
var m0 map[string]int 这不是赋值语句,go语言零值可用,但是这是引用类型,所以是nil
func main() {
var m = make(map[string]int)
m["a"] = 11 // key不存在,则创建新的key和value对
m["a"] = 22 // key已经存在,则覆盖value
fmt.Println(m)
}
map[a:22]
使用map一般需要使用key来查找,时间复杂度为O(1)
func main() {
var m = make(map[string]int)
m["a"] = 11
m["a"] = 22
if _, ok := m["b"]; ok {
fmt.Println("存在")
} else {
fmt.Println("不存在")
}
}
key访问map最高效的方式
// 返回kv对的个数
func main() {
var m = make(map[string]int)
m["a"] = 11
m["a"] = 22
fmt.Println(len(m))
}
1
注意:由于map的特殊构造,不能使用cap。
func main() {
var m = make(map[string]int)
m["a"] = 11
m["b"] = 22
fmt.Println(m)
delete(m, "a")// 存在,删除kv对
fmt.Println(m)
}
map[a:11 b:22]
map[b:22]
即便不存在删除也不会panic
func main() {
var m = map[string]int{
"a": 11,
"b": 22,
"c": 33,
}
for k, v := range m {
fmt.Println(k, v)
}
}
a 11
b 22
c 33
注意:map的key是无序的,千万不要从遍历结果来推测其内部顺序,因为key在内存中是乱序
Go的标准库提供了sort库,用来给线性数据结构排序、二分查找。
// 切片排序
// 针对int、string有快捷方法Ints、Strings
func main() {
var a = []int{-1, 23, 5, 7, 4, 9}
sort.Ints(a)// 就地修改原切片的底层数组
// sort.Sort(sort.IntSlice(a)) // sort.IntSlice(a)强制类型转换以施加接口方法
fmt.Println(a)// 默认升序
}
[-1 4 5 7 9 23]
func main() {
b := []string{"xyz", "a", "abc", "Ab", "X"}
sort.Strings(b)
fmt.Println(b)
}
[Ab X a abc xyz] //根据ascill码排序
降序和升序不同 升序在go中已经定义好了 只需要调用 但是降序不行
func main() {
b := []string{"xyz", "a", "abc", "Ab", "X"}
sort.Sort(sort.Reverse(sort.StringSlice(b))) //Reverse取反
fmt.Println(b)
}
[xyz abc a X Ab]
前提:必须先排序,并且是升序
func main() {
// 二分查找
a := []int{-1, 23, 5, 9, 7}
sort.Ints(a)
// 二分查找,必须是升序
// 二分查找的前提是 有序
i := sort.SearchInts(a, 1)
fmt.Println(i)
}
1