1.堆栈和队列
数据结构:计算机组织管理数据的方式。堆栈
指的是内存图中的栈
,不是堆。
2.数组和链表
如下查询慢:知道张三在哪,不能马上知道王五在哪,挨个查。如下增删虽然不用整个动(如删除李四,只需要将箭头指向王五就行),但是还是要先查找到再删除
,效率还是慢。但是直接删除张三或马六头尾元素快。
3.红黑树
二叉树
:每个节点最多两个子节点。查找树
:左小右大(二分法)。平衡树
:左右尽量相等(一边的节点层次不会超过另一边的两倍)。二查平1倍
:红黑树(数组和链表折中方案)。
二叉搜索树BST(二查)
:插入或查询一节点时,树的每一行只需要和这一行的一个节点
比较(因为左小右大),复杂度完全依赖树的深度。树的行数即高度=logn【n为节点总数,2的树行数次方为n】,BST读和写的复杂度都为logn。
有序数组
查找时用二分查找法,时间复杂度logn。有序数组查询最差情况logn,而当BST为单边时(最差情况),BST查询和插入都为o(n)。
问题:为什么很多情况下用BST,而不是有序数组二分查找?因为有序数组查找用二分查找logn,但是插入要移动,插入
时间复杂度为o(n)。
BST很少在语言内部数据结构存储里用(因为下面直线情况),自平衡二叉树AVL(二查平)
是BST(二查)
的继承优化:左子树和右子树都是平衡二叉树,而且左子树和右子树深度之差绝对值不会超过1(左旋和右旋),AVL 读和写的复杂度最差情况都为O(logn)。
AVL平衡左右子树相差1,这个条件很苛刻,导致很多情况下都不满足这个平衡条件,需要旋转变换,变换的话需要浪费时间。红黑树(二平查1倍)
平衡条件更加宽松些左右深度差一倍
【如下节点数相同是上界
,节点数差一倍是下界
(因为红节点子节点必须为黑)】,这样宽松条件导致我们在插入节点时候变化更少的,所以红黑树写的性能会高一些。
红黑树整体复杂度也是O(logn),树的搜索或插入复杂度完全依赖于树的深度,为什么深度差一倍还是O(logn)?如下左边3是3层,右边红黑树。
如下是红黑树的插入变色
流程,最上面根节点必须为黑,插入节点为红节点(看插入节点的父节点和父节点的兄弟节点即叔节点)。null算叶子节点即黑节点。当前插入的003是爷爷节点的右右。
如下左旋+变色
4.List子接口
如下是集合的框架图
package com.itheima01.list;
import java.util.ArrayList;
import java.util.List;
/*
Collection子接口:List
1. List的特点:重索序
1. 有先后顺序:元素存储的顺序和取出的顺序相同
2. 具有整数索引,就是下标
3. 允许重复元素
2. List的方法(带索引)(List特有的,共有的在Collection讲过)
1. add(int index, E element) :往索引位置添加一个元素
1. Java中的 三个越界异常
1. IndexOutOfBoundsException 集合
2. ArrayIndexOutOfBoundsException 数组
3. StringIndexOutOfBoundsException 字符串越界
2. get(int index):获取指定索引的元素
3. remove(int index):移除指定索引的元素
4. set(int index, E element) :修改指定索引的元素值
*/
public class ListDemo {
public static void main(String[] args) {
// add();
List<String> list = new ArrayList<>();
list.add("周楠");
list.add("王凤枝");
list.add("王凯");
String s = list.get(2);
System.out.println(s); //王凯
list.remove(2);
System.out.println(list); //[周楠, 王凤枝]
list.set(1,"昌老师");
System.out.println(list); //[周楠, 昌老师]
}
//11111111111111111111111111111111111111111111111111111111111111111111111111111
private static void add() {
List<String> list = new ArrayList<>();
list.add("周楠");
list.add("王凤枝");
list.add("王凯");
/*
add(int index, element)
往指定索引位添加元素
index = list.size()
IndexOutOfBoundsException: : 索引越界异常
*/
list.add(3,"田锁"); //不越界,4越界
System.out.println(list);
String[] array = {
};
//System.out.println(array[0]); //ArrayIndexOutOfBoundsException : 数组索引越界
String str = "abc"; // 字符串底层也是数组
// char c = str.charAt(3); //索引0,1,2
// System.out.println(c); //StringIndexOutOfBoundsException:字符串索引越界
}
}
5.ArrayList的扩容原理
Stringbuild默认length=16,扩容2倍。ArrayList底层是存Object数组,新建一个长度为原来1.5倍新数组(空)。
如下10进制的4就是2进制的0100(8421),3/2=1,ArrayList.java源码中出现左右移。
package com.itheima01.list;
import java.util.ArrayList;
/*
* ArrayList: 数组
* 1. 最常用: 适合 查询需求比较多的场景
* 2. 原理: ArrayList扩容原理
* ArrayList底层是数组,数组长度不可变,为什么ArrayList又可变呢? 因为数据迁移
*/
public class ArrayListDemo {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("xx");
System.out.println(3 >> 1); // 1 //除2取整
System.out.println(4 >> 1); // 2
System.out.println(10 >> 1); // 5
System.out.println(3 << 2); //12 //3*2*2,左移2位
}
}
6.LinkedList
package com.itheima01.list;
import java.util.LinkedList;
/*
LinkedList特点
1. 底层数据结构: 双向链表
2. 查询速度慢,增删快(增删需求多而且增删首尾用LinkedList)
3. 特有方法(不能使用多态,父类不能调子类特有方法)
1. addFirst 元素添加在链表开头
2. addLast(add相同) 元素添加在链表结尾
3. getFirst 获取链表开头
4. getLast 获取链表结尾
5. removeFirst 移除并返回链表开头
6. removeLast 移除并返回链表结尾
//下面两个不需要掌握
7. pop 从此列表所表示的堆栈处弹出一个元素(最顶部元素弹出,removeFirst)
8. push 将元素推入此列表所表示的堆栈(元素存储到集合顶部,addFirst)
*/
public class LinkedListDemo {
public static void main(String[] args) {
// method01();
LinkedList<String> list = new LinkedList<>();
list.add("张三"); // 是链表,不是按堆栈结构添加元素
list.add("李四");
list.add("王五");
// 链表 -> 堆栈 ,张三在栈顶
// String pop = list.pop(); // 弹栈: 栈顶元素()
// String removeFirst = list.removeFirst();//效果同上
// System.out.println(pop);
list.push("王二"); //栈顶添加,效果等同于add
System.out.println(list);
}
private static void method01() {
LinkedList<String> list = new LinkedList<>();
list.add("张三");
list.add("李四");
list.add("王五");
list.addFirst("王二");
list.addLast("马六");
System.out.println(list);
String first = list.getFirst();
String last = list.getLast();
System.out.println(first + "," + last);
System.out.println(list);
list.removeFirst();
list.removeLast();
System.out.println(list);
}
}
7.set子接口
package com.itheima02.set;
import java.util.HashSet;
import java.util.Set;
public class SetDemo {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("张三");
set.add("李四");
boolean result = set.add("王五");
System.out.println(result); //true
boolean result2 = set.add("王五");
System.out.println(result2); //false //元素不可重复
System.out.println(set);//[李四,张三,王五] //存取不保证顺序
}
}
B站/知乎/微信公众号:码农编程录