数据结构笔记
2-3树&红黑树
哈希表
哈希函数的设计
例如26个字符 new一个int[26]。可以用来做哈希
整型值
小范围正整数,直接使用正整数。
大整数 通常做法 取模 比如取后四位 mod 1000 模一个素数分布效果更好
如果对日期这种取模,只能在01-31,会造成分布不均匀。
要具体分析。
浮点型
32位或64位机器,浮点型会有特殊表示。
32位前8位
64位是前11位
使用整数的方式来解析
Java的hashCode
haseSet存数据,会先计算hashCode,有冲突则通过equals判断是否是同一个对象。
哈希冲突
链地址法
- 数组,长度M
- 元素对M取模
- (hashCode(k1) & 0x7fffffff) % M
- 前面是31位的0做与,去掉第一位的符号位。
- 算完模后,例如4,索引为4的位置,就存上就好了。
- 有冲突时
- 在链表尾部加冲突的节点。
- 也可以用平衡树存
扩容 hashMap 默认 数组长度*0.75 即 16*0.75=12 12个长度就扩容。
开放地址法
所有索引都有机会存不同的hash值。
正常先存储,遇到hash冲突,就把冲突的元素,向后去找空的空间。
比如对10取hash值。
占满了,就会一直探测。
改进:
平方探测法
每次向下找平方,不是+1
二次hash法
对于开放地址法,扩容合适,也是O(1)复杂度
再Hash法 Rehashing
Coalesced Hashing
结合seperate Chaining 和 Open Addressing
SQRT O(sqrt(n)) 根号N时间复杂度
代码实现更方便,虽然时间复杂度会比线段树O(logn)高一些。
分块分组的思想,解决区间问题。
链表
class Node{
E e;
Node next;
}
不能随机从一个索引拿出元素,next连接的。
数组在尾部添加方便;链表在头部head添加方便。
数据量大的时候,链表更损耗性能,因为每个节点都要New,而数组虽然resize,但是每次都是翻倍的,对内存的消耗会小。
那么链表和数组的核心区别是什么?答案是:链表是一种动态的数据结构。
什么叫动态的数据结构?就是我需要存多少数据,就去 new 多少空间。而不像数组,我们需要一次性 new 够所有需要的空间。这就产生了空间的浪费。虽然课程中我们之前介绍的“动态数组”也有动态两个字,但其实只是把这个一次性 new 很多空间的操作隐藏了而已,其内部本质依然是静态数组,依然会有空间的浪费。依然会有存了 101 个数据,但是有 200 个空间的问题。
动态数据结构是非常重要的一个概念。单纯从链表的角度看,或许“动态”的意义还不明显,但是等学到树结构,你就会看到,“动态”的意义是巨大的。
链表与递归
树和递归比较方便,链表也是可以。
todo