1.数组 线性表
定义的方式
int[] a=new int[10]
为什么查询快?
1.可以借助O(1)时间复杂度访问某一元素,
2.地址连续,逻辑连续
3.数组长度一旦确定就不可以被修改
当需要扩容的时候需要将老数组的内容复制过来
在Java中数组是一个对象
ArrayList 数组列表
ArrayList的添加(自动扩容)
对应的源码
值得一看的是ensureCapacityInternal方法
Ctrl+鼠标右键点进去
看这个231行的这个方法,modCount这个不用关注,是并发下的一个计数,重点看234行的代码,minCapacity是新加入的值的位置,如果比数组的长度大就会执行grow(),数组扩容的方法
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;//取到老的容量
int newCapacity = oldCapacity + (oldCapacity >> 1);//构建新的容量,新的容量是老的容量的+老的容量右移一位(1.5倍)
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);//把老数组的值赋值给新的数组
}
底层就是构建了一个新的数组,并且把老的数组内容复制过来,从而就实现了自动扩容。
总结:初始容量是多少 10
扩容机制: 当elementData已经满了,才会扩容
扩容的方式:原容量加原容量右移一位
优点:随机访问,
缺点:需要连续的空间
2.链表
1.可以不断的扩容
2.由node结点组成,每个node由data和next组成
3.两种插入方式,头插法和尾插法
链表的构建,以及两种插入方法(头插法和尾插法)
class MySingleLinkedList{
public Node head;
class Node{
public int value;
public Node next;
public Node(int value, Node next) {
this.value = value;
this.next = next;
}
}
//头插法
public void addFirst(int value){
Node node =new Node(value, null);
if (head==null){
head=node;
}else {
node.next=head;
head=node;
}
}
//尾插法
public void addEnd(int value){
Node node=new Node(value,null);
Node temp=head;
if (head==null){
head=node;
}else {
while (temp.next!=null){
temp=temp.next;
}
temp.next=node;
}
}
//循环输出
public void loop(){
Node temp=head;
while (temp!=null){
System.out.println(temp.value);
temp=temp.next;
}
}
}
Java中提供的LinkedList是一个双端的队列
练习:
leetcode中
单链表的反转
链表成环的判断、环的长度
两个有序链表的合并
3.二叉树
二叉树的三种遍历代码实现
前序遍历
中序遍历
后序遍历
3.1 搜索二叉树
左边的节点比根小,右边的节点比根大(不保证平衡)
时间复杂度最好O(log(n)),最坏O(n)
3.2 平衡二叉树:
搜索二叉树基础上,任一节点的左右子树高度差不超过1.
LL旋转,RR旋转,LR旋转,RL旋转
3.3 红黑树:
红黑树是一棵近似平衡的二叉树,是一种高效的查找树。
所有的结点要么红色要么黑色,非黑即红
根结点是黑色的,叶节点是不存储数据的黑色 空结点
不能连续两棵红色相连
从任意结点到其所有的叶子结点所经过的黑色叶子结点数是一样的
推导出来,从红黑树的叶子结点到另一最近结点上的与到另一最远结点上,不超过一倍(任一结点的左右子树的高度差不超过两倍)
AVL树(平衡树)和红黑树的对比
AVL严格的平衡树,红黑树近似的平衡树
AVL在查询上更高效,红黑树在插入和删除上更高效
红黑树插入的时候默认结点是红色的,因为只是有可能会违反根叶黑或者不红红的规则
如果插入破坏了规则分以下三种情况:
1)插入结点是根节点
直接把根结点变黑
2)插入结点的叔叔是红色结点
父亲层和爷爷层同时变色,黑色变红色,红色变黑色,再看是否破坏红黑树的规则。
3)插入结点的叔叔是黑色
(LL,RR,LR,RL)旋转,然后变色,变色规则是旋转中心点,旋转点进行变色
LL:右旋,向右旋转,冲突的右孩变左孩
RR:左旋,向左旋转,冲突的左孩子变右孩子
LR: 左旋左孩子,然后右旋
RL:右旋右孩子,然后左旋
4.B树
红黑树虽然是近似平衡的,而且插入,删除上很高效,但是如果插入数据非常的多,也会出现树的深度过深,导致内存和磁盘间的I/O次数过多的情况,这时候就可以使用多叉树。
对于一个m叉树
(1)树中每个结点至多有m个孩子结点(m-1个关键字)
(2)每个结点的结构
(3)除根结点外,其他结点至少有m/2个孩子结点
(4)若根节点不是叶子结点,则根结点至少有两个孩子结点
(5)所有的叶子结点都在同一层上,即B树是所有结点的平衡因子等于0的多路查找树
B树的查找
首先我们要了解一个概念,我们读取磁盘中的数据时,是按照块或者页读取的,比如,一个word文档大小3.5K,它存储的时候会按照一个页的大小的整数倍去存储,存储占用4K,读取的时候也是一样的。
B树的访问结点是在硬盘上解决的,但是B树对结点内的数据的操作是在内存中使用的。
B树就是一次性去磁盘中读取一个块,数据,指针都在这个块里了
B+树
B+树就是在B树的基础上非叶子结点只存储记录和指针,叶子结点存储数据,B+树的元素个数和分支树是相同的,也就是一个元素值对应一个子树。
B+树的非叶子结点是为了快速定位到叶子结点上的关键字,就相当于给叶子结点层建立了索引。
整个B+树就是一个多级索引结构,目的就是为了加速查询的速度,查询的速度是log(n)级别的
B+树被广泛用作数据库的索引结构
B+树可以用于:顺序查找,随机查找,范围查找
B树和B+树的对比