一、数据结构
基于数组、链表、红黑树实现
- 数组作为基础的数据存储结构
- 链表为了解决hash碰撞(理解:不同关键字通过相同哈希函数(余数法)计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞。由于我们哈希表底层数组的容量往往是小于实际要存储的关键字的数量的,这就导致一个问题,冲突的发生是必然的,但我们能做的应该是尽量的降低冲突率)
- 红黑树是为了解决链表中的数据较多(满足
链表长度 >8且数组长度>64
,才会将链表替换成红黑树才会树化,而当链表长度为6时树又会退化为链表)时查询效率下降的问题。
1.1 二叉树
又称二叉搜索树、二叉排序树、二叉查找树。
1.左子树上所有结点的值均小于或等于它的根结点的值。
2.右子树上所有结点的值均大于或等于它的根结点的值。
3.左、右子树也分别为二叉排序树。
4.没有键值相等的节点
二分查找的思想
1.2 平衡二叉树
在二叉树的基础上多了2个重要的特点:
- 左右子树高度差绝对值不超过1
- 左右子树也是一颗平衡二叉树
1.3 红黑树
背景:为了解决二叉树插入节点不平衡的问题,如下:
定义:红黑树是自平衡的二叉树,需满足以下5个条件。
1.节点是红色或黑色。
2.根节点是黑色。
3.每个叶子节点都是黑色的空节点(NIL节点)。
4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
5.从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
变色
:插入新节点21时,为了满足条件4,将节点22变色,又为了满足条件5,继续将25变色,又为了满足条件4,将27变色。
旋转
:保证旋转后二叉树大小分布保持不变
1.4 B树(B-树)
平衡的多叉树,称为B树(或B-树、B_树)。
- 根结点至少有两个子女;
- 每个非根节点所包含的关键字个数 j 满足:
┌m/2┐ - 1 <= j <= m - 1 (┐代表向上取整:大于或等于x的最小整数,2.8取3)- 除根结点以外的所有结点(不包括叶子结点)的度数正好是关键字总数加1,故内部子树个数 k 满足:┌m/2┐ <= k <= m ;
- 所有的叶子结点都位于同一层。
- 每个结点中关键字从小到大排列,并且当该结点的孩子是非叶子结点时,该k-1个关键字正好是k个孩子包含的关键字的值域的分划。
- 因为叶子结点不包含关键字,所以可以把叶子结点看成在树里实际上并不存在外部结点,指向这些外部结点的指针为空,叶子结点的数目正好等于树中所包含的关键字总个数加1。
1.5 B+树
1.有n棵子树的结点中含有n个关键字,每个关键字不保存数据,只用来索引,
所有数据都保存在叶子节点
。
2.所有的叶子结点中包含了全部关键字的信息,及指向含这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接。
3.所有的非终端结点可以看成是索引部分,结点中仅含其子树(根结点)中的最大(或最小)关键字。
4.通常在b+树上有两个头指针,一个指向根节点,一个指向关键字最小的叶子结点
5.同一个数字会在不同节点中重复出现,根节点的最大元素就是b+树的最大元素
B+树相对于B树的查询优势
B+树的中间节点不保存数据
,所以磁盘页能容纳更多节点元素,更矮胖- B+树查询必须查找到叶子节点,B树只要匹配到即可不用管元素位置,因此
B+树查找更稳定
(并不慢) - B+树
只需遍历叶子结点链表
,B树却需要重复地中序遍历
1.6 B*树
二、扩容机制
HashMap的参数:
- 初始容量:创建时给数组分配的容量大小,默认值为16
- 加载因子:0.75
扩容:当元素的总个数>当前数组的长度 * 加载因子时扩容为原来的2倍
弊端:性能消耗严重
扩容时会生成一个新的数组,原来的所有数据需要重新计算哈希码值重新分配到新的数组
- 设置扩容后的数组大小newCap和扩容后新的阈值newThr,都是扩大2倍;
- 扩容后原来数组数据的迁移,只有2种情况,要么原位置,要么原位置+ oldCap
为什么数组容量必须是2^n
减少hash碰撞
只有数组长度为2^n,才能保证n-1的低位的值全为1,这样元素就可以更均匀的分散在数组上。
//put(),计算存储的元素的下标
//n是数组长度,默认16
i = hash & (n - 1)//&运算算法:2个都是1,结果才为1,否则为0。