数据结构
树
节点
度:每个节点的子节点数量
二叉树,任意节点的度<=2
树高:树的总层数
根节点,左子结点,右子节点
左子树,右子树
二叉查找树 二叉搜索树
二叉查找树,添加节点
二叉树遍历方式
前序遍历
当前,左子结点,右子节点
中序遍历
左子结点,当前节点,右子节点
遍历出来的数据是按从小到大的顺序排列的
后序遍历
左子结点,右子节点,当前节点
层序遍历
一层一层遍历
弊端
二叉查找树左右的高度不一样,查询效率降低
平衡二叉树
怎么保持平衡?
旋转机制
左旋
简单情况
先找到不平衡的点
10降级,10作为11的左子结点,12作为11的右子节点
复杂情况
先找到不平衡的点
10升为根节点,7降级,9作为7的右子节点
右旋
先找到不平衡的点
4降级,作为2的右子节点
复杂情况
7降级,4作为根节点,7为4的右子节点,5为7的左子节点
触发旋转机制的情况
添加了节点导致树不平衡
左左
需要一次右旋
左右
局部左旋,再一次右旋
右右
一次左旋
右左
局部右旋,再一次左旋
红黑树
特殊的二叉查找树,不是高度平衡的,满足红黑规则
节点 存多了颜色 nil叶节点是黑的 红的不能连
默认添加节点是红的,效率更高
添加节点规则
将祖父设置为当前节点再判断:意思是把祖父当成现在要添加的节点,重新走这个流程
如果需要旋转:则旋转的时候,不需要考虑nil叶节点
Set集合
无序,不重复,无索引
实现类:hashset,linkedhashset,treeset
遍历
添加元素add
如果添加相同的元素,则添加失败,add方法返回false
存和取的顺序可能不一样
Hashset集合
存不重复的元素
用哈希表存储数据
哈希值
对象的整数表现形式
Hashcode方法
存储自定义对象,要重写hashcode,idea自动生成,根据属性值计算哈希值
如果不重写,则计算的时候使用的是地址值,而不是内部的属性值
哈希表增删改查性能都很好
JDK8以前底层原理
新元素是存入数组的,老元素挂在新元素下面
默认加载因子0.75:当数组存了16 * 0.75 = 12 个元素时,数组就会扩容到原先的两倍到32
计算存入位置的公式
JDK8以后
新元素直接挂在老元素下面
当链表长度大于8而且数组长度大于等于64,链表就会转成红黑树,提高查找效率
为什么hashset存和取的顺序不一样?
因为hashset是按照数组table的0索引开始遍历的,而且他是根据哈希值和数组的长度来计算存入的位置,所以可能先遍历的不是先存储的元素。
Hashset为什么没有索引?
因为hashset底层是数组链表红黑树组合而成的,定义索引不够准确,如果出现链表,则无法给链表中的每一个元素定义索引。
Hashset是利用什么机制保证数据去重的?
Hashcode 和equals方法
Hashcode计算哈希值,确定元素添加到数组的位置
Equals比较元素内部的属性值是不是相同
如果存储的是自定义对象,一定要重写这两个方法
如果存的是string和integer等引用数据类型,不需要再重写这两方法了,java已经重写了
Linkedhashset
他是有序的。
保证存储和取出是一致的 多了条双链表
会记录头结点,尾节点,添加进的元素会互相记录前面添加的元素的地址值
Treeset
可以排序 基于红黑树
Treeset的两种比较方式
第一种默认排序
字符串是按照每一个字符一个个来比较的
如果元素是自定义对象,则需要在对象的类中添加comparable接口,重写compareto方法
比较出的大小,根据红黑树规则来存放
第一次会自己和自己比,然后存到根节点
重写compareto方法
第二种
比较器排序 comparator
还可以改成lambda表达式
两种方式同时存在,则会按照第二种方式比较器排序
以上集合使用场景
Hashset,linkedhashset,treeset在底层源码都是跟map集合有关,调用map的方法