集合数据结构记录
1.数组结构
2.链表结构
每个节点由此节点数据和前一个节点地址和后一个节点数据组成,有头循环双链表结构如图所示,链表创建时会新增一个head节点,节点数据自定义,head节点的前一个(pre)数据地址指向最后一个节点地址,最后一个节点的下一个(next)的数据地址指向head
为什么要这么做?
如果不加上一个head的节点,那么需要在删节点和新增节点的时候判断此节点是不是为第一个节点,增加少许数据提交了性能
3.散列表结构
散列表由数组+链表组成,主要代表数据类型为HashTable
诞生时间: jdk1.0的时候
线程情况: 线程安全结构
数据结构: 数组+链表
缺点: 由于链表的分类由hashCode返回值来确定.如果不重写hashcode方法基本每个数组的链表就一个与数组结构无异,重写hashcode方法又很难有一个很完美的方法去实现,所以诞生了后面的二叉树结构
过程:
在jdk1.2期间为了满足性能的需求,诞生了hashmap,与hashtable相比提高了性能牺牲了线程安全;
在jdk1.5期间为了满足并发要求.诞生了concurrentHashMap,数据结构为Segments数组 + HashEntry数组 + 链表, JDK1.5之后新出一个在并发包里面类,包名叫 java.util.current;简称JUC,既然叫并发包,那肯定就意味着它是线程安全的,里面有一个概念:分而治之,这是ConcurrentHashMap的核心思想,并且在jdk7里面用到一个非常新颖且时髦的技术 :分段锁;
在jdk1.8时,官方改写了hashmap和concurrentHashMap的数据结构,由之前的数组+链表改为数据+链表+红黑树,但数组长度>=64,链表长度>=8时结构变为数据+红黑树
4.二叉树结构
二叉树结构如图所示,一个节点下有两个子节点,一般遵循左小右大原则,但是如果只是遵循此原则的话,从1到10按顺序开始插入的话,只会一直插到右边,这个时候二叉树就形于一个链表结构,所以说二叉树的最差的情况下就是一个链表结构;
由于二叉树的结构如果不加以控制就和链表无异,此时就诞生了平衡二叉树
平衡二叉树的性质:
- 左子树和右子树的高度之差的绝对值小于等于1
- 左子树和右子树也是平衡二叉树
5.三叉树结构
三叉搜索树的基本性质可以归纳为:
(1)根节点不包含字符,除根节点外的每个节点只包含一个字符。
(2)从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串。
(3)每个节点的所有子节点包含的字符串不相同。
(4)节点采用“树中有树”的建立方法,避免多余的内存占用。
6.四叉树结构
7.红黑树结构
有了平衡二叉树,为什么还需要红黑树?
- AVL的左右子树高度差不能超过1,每次进行插入/删除操作时,几乎都需要通过旋转操作保持平衡
- 在频繁进行插入/删除的场景中,频繁的旋转操作使得AVL的性能大打折扣
- 红黑树通过牺牲严格的平衡,换取插入/删除时少量的旋转操作,整体性能优于AVL
- 红黑树插入时的不平衡,不超过两次旋转就可以解决;删除时的不平衡,不超过三次旋转就能解决
- 红黑树的红黑规则,保证最坏的情况下,也能在O ( l o g 2 N ) O(log_2N)O(log 2 N)时间内完成查找操作。
红黑规则
- 节点不是黑色,就是红色(非黑即红)
- 根节点为黑色
- 叶节点为黑色(叶节点是指末梢的空节点
Nil
或Null
) - 一个节点为红色,则其两个子节点必须是黑色的(根到叶子的所有路径,不可能存在两个连续的红色节点)
- 每个节点到叶子节点的所有路径,都包含相同数目的黑色节点(相同的黑色高度)
个人理解:
红节点为黑节点的附属节点,我们可以看作是假的节点,如上图所示8.15为11的附属节点,12为38的附属节点,这个时候真的节点就只有黑色节点了,红黑树也就可以简化为由多个二叉树,多个三叉树,多个四叉树组成,当红色节点的与黑色的组成树大于3个数据的时候,需要将中间的节点数据顶上去,去父节点组成三叉树或者四叉树,这时另外的两个数据将变为黑色的字节;