数据结构:
互相之间存在一种或多种特定关系的数据的集合。
栈(Stack):也叫做“堆栈”。特点:先进后出。
队列(Queue):先进来的先出去,后进来的后进去。先进先出。
数组(Array):内存空间是连续的。特点:查找快,增删慢(会创建一个新数组接收增删后的元素)。
链表(Linked List):内存空间不连续的。特点:增删快,查找慢。
单项链表:每个元素都知道下一个元素的地址。
双向链表:前一个元素知道下一个元素的地址,后一元素也知道前一个元素的地址。
树:
二叉树:
排序树:在二叉树的基础上,左边都小于右边。
平衡树:左右两边对称
红黑树的数学约束:
1、结点可以是红色或者是黑色。
2、根节点是黑色。
3、叶子结点(特指空节点)是黑色。
4、每个红色节点的子节点必须是黑色。
5、任何一个节点到其每一个叶子节点的所有路径上黑色节点数量相同。
红黑树的特点:速度特别快。
查找速度特别快,趋近于平衡排序儿二叉查找树。
查找叶子节点的步骤,最多和最少不超过二倍的关系。
List
java.util.List是Collection接口的子接口,特点:
1、可以存储重复元素。
2、有先后顺序。
3、有索引值。
常用的实现类有:
1、ArrayList:底层使用的是数组。查找快,增删慢。
2、LinkedList:底层使用的是链表。增删快,查找慢。
3、Vector:底层使用的也是数组,和ArrayList基本一样,不过线程安全。
Collection接口的方法,List都有。
List特有方法:
public void add(int index , E element): 添加一个元素到指定的索引位置。
public E remove(int index):根据指定索引值删除一个元素,返回被删除的元素。
public E set(int index, E replacemrnt):根据指定索引值替换一个元素,返回被替换的元素。
public E remove(int index):根据指定索引值删除一个元素,返回被删除的元素。
public E get(int index):根据指定索引值获取一个元素。
增删改查:CRUD Create Read Update Delete
List<String> list = new ArrayList<>();
list.add("张小凡");
list.add("张无忌");
list.add("张三丰");
list.add("宋青书");
System.out.println(list); // 有顺序 [张小凡, 张无忌, 张三丰, 宋青书]
list.remove("张三丰"); // 删除张三丰
System.out.println(list); // [张小凡, 张无忌, 宋青书]
// list.remove(3); //
// IndexOutOfBoundsException: 由于删除张三丰后,只剩下三个值,索引最大为2,删除3不存在
// System.out.println(list);
list.set(1,"赵敏"); // 修改索引1
System.out.println(list); // [张小凡, 赵敏, 宋青书]
list.remove(0); // 删除索引值为0的对象
System.out.println(list); // [赵敏, 宋青书]
// 获取索引值为0的对象
System.out.println(list.get(0)); // 赵敏
LinkedList当中特有的方法:
public void addFirst(E e):在开头添加一个元素。
public void addLast(E e):在末尾添加一个元素。
public E getFirst(): 获取开头的元素。
public E getLast(): 获取末尾的元素。
public E removeFirst(): 删除开头元素。
public E removeLast(): 删除末尾的元素。
LinkedList<String> list = new LinkedList<>();
list.add("张小凡");
list.add("张无忌");
list.add("张三丰");
list.add("宋青书");
System.out.println(list); // [张小凡, 张无忌, 张三丰, 宋青书]
list.addFirst("赵敏"); // // 新加入的元素加在原来集合的最前
System.out.println(list); // [赵敏, 张小凡, 张无忌, 张三丰, 宋青书]
list.addLast("李白"); // 新加入的元素加在原来集合的最后
System.out.println(list); // [赵敏, 张小凡, 张无忌, 张三丰, 宋青书, 李白]
list.removeFirst(); // 删除开头元素
System.out.println(list); // [张小凡, 张无忌, 张三丰, 宋青书, 李白]
list.removeLast(); // 删除最后一个元素
System.out.println(list); // [张小凡, 张无忌, 张三丰, 宋青书]
// 获取开头元素
System.out.println(list.getFirst()); // 张小凡
// 获取末尾元素
System.out.println(list.getLast()); // 宋青书
注意:
如果集合中没有元素了,接着删除,会报没有元素异常错误。
LinkedList当中有两个与栈相关的方法:
public void push(E e): 压栈、进栈,在左边添加一个元素。相当于addFirst方法。
public E pop(): 弹栈、出栈,在左边删除并去除一个元素。相当于removeFirst方法。
对于这两个方法来说,数据元素的出入口全都是左边。
LinkedList<String> list = new LinkedList<>();
list.add("张小凡");
list.add("张无忌");
list.add("张三丰");
list.add("宋青书");
System.out.println(list); // [张小凡, 张无忌, 张三丰, 宋青书]
list.push("范冰冰"); // 把范冰冰压进栈,在最左端加入一个新元素,相当于addFirst
System.out.println(list); // [范冰冰, 张小凡, 张无忌, 张三丰, 宋青书]
list.pop(); // 出栈,把最左端的元素删除,相当于removeFirst
System.out.println(list); // [张小凡, 张无忌, 张三丰, 宋青书]
Set
java.util.Set是Collection的子接口。特点:
1、不允许重复元素
2、不保证先后顺序
3、没有索引值
常用子类:
1、HashSet:速度特别快,不保证顺序
2、LinkedHashSet:速度也很快,但是还能额外保证顺序。
3、TreeSet:有大小排序功能
注意:先后顺序和大小排序是不一样的。
HashSet集合是最常用的Set集合,特点:
因为底层使用了一种名叫“哈希表”的数据结构,所有查找元素的速度特别快。
底层原理其实是在复用HashMap。
重点:
HashSet是如何判断元素是否重复的?如何得知集合当中是否已经存在了重复的元素?
两个对象是否相同,由equlas和hashCode两个方法共同决定。
public int hashCode():根据当前对象那个,产生一个“哈希值”(对象的特征码)。
如果没有覆盖重写hashCode方法,那么Object当中的hashCode将会在JVM当中:
默认使用对象的内存地址值参与运算,然后得到一个与地址相关的int数字:哈希值。
只要内存够用,可以创建很多个对象,无数个不同的地址值。
默认的哈希值只是使用了地址值参与运算而已,并不直接等于地址值。
无数种地址–> 哈希运算hashCode()–>42亿种int哈希值。
意味着: 可能有不一样的对象,哈希值是相同的。
哈希原理:先分类,再查找。
哈希表: 本身就是一个数组,默认长度为16。
桶(Bucket):就是哈希表数组当中的一个小格。
哈希冲突:不一样的对象被放在了同一个桶当中。
加载因子: 就是一个百分比,默认0.75,一旦哈希表当中已经被占用的桶,占用了总桶的个数超过了加载因子的比例,那么哈希表将会自动扩容。
再哈希(rehash):达到加载因子之后,哈希表进行重新更加细致地分类。
在java7之前,就是单纯的链表。
在java8以及之后,将会在长度达到8之后,自动从链表变身成为红黑树。
红黑树的特点:快。
HsahSet是如何确定元素是否重复?(这就是一个对象查找的过程)
1、如果hashCode不一样,那么两个对象肯定不一样。(姓张的和姓李的,肯定不是一个人。)
2、如果hashCode一样,但是equals不一样,那么两个对象就不一样。
3、如果hashCode一样,并且equals也一样,那么两个对象才一样。
hashCode方法的三条原则:
1、运行期一致性。
2、对象相同,那么哈希值必须相同。
3、对象不同,那么哈希值不一定相同。
equals方法的五条原则:
1、自反性:自己和自己比较,一定相同。
2、对称性:A比较B,B比较A,效果一样。
3、传递性:如果AB一样,并且BC一样,那么AC也一样。
4、一致性:只要对象的内容不变,比较的结果就不能变。
5、无非空:任何对象和null值比较,一定是false。
如果在哈希结构当中存储自定义的类型,那么必须覆盖重写equals和hashCode方法。
Set<String> list = new HashSet<>();
list.add("AAA");
list.add("BBB");
list.add("CCC");
list.add("DDD");
// 打印出来的元素,1、没有顺序,2、没有索引值,3、不允许重复元素
System.out.println(list); // [张小凡, 宋青书, 张三丰, 张无忌]
// 添加一个集合中已经存在的元素
boolean b = list.add("张小凡");
System.out.println(b); // false
Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
System.out.println(iter.next()); // 无序
}
System.out.println("====================");
Set<String> linkSet = new LinkedHashSet<>();
linkSet.add("AAA");
linkSet.add("BBB");
linkSet.add("CCC");
linkSet.add("DDD");
for (String s : linkSet) {
System.out.println(s); // 升序排列
}
LinkedHashSet是HashSet的子类:
额外添加了一层双向链表,咱们用来维护顺序。
可变参数就是参数的类型统一,但是个数随意。java5添加的特性之一
格式:
修饰符 返回值类型 方法名称(参数类型... 参数名称){
//方法体
}
注意事项:
1、可变参数只是一个语法糖,底层其实就是普通的数组。
2、方法的可变参数只能有一个。
3、方法的可变参数只能是最后一个。
public static void main(String[] args) {
long result = push(10, 20, 30);
System.out.println(result); // 60
}
private static int push(int... nums) {
int num = 0;
for (int i = 0; i < nums.length; i++) {
num += nums[i];
}
return num;
}
Collections
是与集合相关的工具类,其中有常用的静态方法:
public static void shuffle(List<?> list):打乱集合当中的顺序。
public static boolean addAll(Collection c,T... elements):第一个参数代表加到那个集合中,第二个可变参数代表需要添加的元素都有谁。
public static void sort(List list): 按照自然顺序进行大小排序。
public static void sort(List list, Comparator comp): 第二个参数代表排序的规则。
List<String> list = new ArrayList<>();
list.add("AAA");
list.add("BBB");
list.add("CCC");
list.add("DDD");
System.out.println(list);
Collections.shuffle(list); // 将list设置成随机顺序
System.out.println(list); // [CCC, DDD, AAA, BBB]
Collections.addAll(list,"FFF","GGG");
System.out.println(list); // [BBB, CCC, AAA, DDD, FFF, GGG]
1、对Comparable来说:升序就是我减他。
2、对Comparator来说:升序就是1-2。
// 测试类
List<Person> p = new ArrayList<>();
p.add(new Person("鹿晗",30));
p.add(new Person("吴亦凡",40));
p.add(new Person("张艺兴",20));
// 对象类必须去实现Comparable才能使用
Collections.sort(p);
// [Person{name='张艺兴', age=20}, Person{name='鹿晗', age=30}, Person{name='吴亦凡', age=40}]
System.out.println(p);
// Person类:
public class Person implements Comparable<Person> {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int compareTo(Person o) {
// 升序就是我减他
return age - o.age;
}
....
public static void main(String[] args) {
List<Person> p = new ArrayList<>();
p.add(new Person("鹿晗", 30));
p.add(new Person("吴亦凡", 40));
p.add(new Person("张艺兴", 20));
// 采用匿名内部类的方法调用Comparator
Collections.sort(p, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.getAge() - o2.getAge(); // 年龄升序
}
});
// [Person{name='张艺兴', age=20}, Person{name='鹿晗', age=30}, Person{name='吴亦凡', age=40}]
System.out.println(p); // 年龄升序排列
// 扩展一丢丢:
Collections.sort(p, (a, b) -> a.getAge() - b.getAge()); // day07学习的Lambda表达式
Collections.sort(p, Comparator.comparingInt(Person::getAge)); // day13学习之后扩展的第五种方法引用
}
}
栈图
队列
数组
链表
红黑树
哈希表存储原理
HashSet查找元素的过程