集合和数组的对比小结

  1. 数组的长度是不可变的,集合的长度是可变的。
  2. 数组可以存基本数据类型和引用数据类型,集合只能存引用数据类型,如果要存基本数据类型,需要存对应的包装类。

    集合类体系结构

    集合类的体系结构.png

    Collection集合常用方法

    | 方法名 | 说明 | | —- | —- | | boolean add(E e) | 添加元素 | | boolean remove(Object o) | 从集合中移除指定元素 | | boolean removeIf(Lambda表达式) | 根据条件进行删除 | | void clear() | 清空集合 | | boolean contains(Object o) | 判断集合中是否存在指定的元素 | | boolean isEmpty() | 判断集合是否为空 | | int size() | 集合的长度,也就是集合中元素的个数 |

Collection集合的遍历

Iterator:迭代器,集合的专用遍历方式

  • Iterator<E> iterator():返回集合中的迭代器对象,该迭代器对象默认指向当前集合的0索引

Iterator中的常用方法

  • boolean hasNext():判断当前位置是有有元素可以被取出
  • E next():获取当前位置的元素,将迭代器对象移向下一个索引位置

    增强for循环

    增强for:简化数组和Collection集合的遍历

  • 它是JDK5之后出现的,其内部原理是一个Iterator迭代器

  • 实现Iterator接口的类才可以使用迭代器和增强for

增强for的格式

  1. for(元素数据类型 变量名 : 数组或者Collection集合){
  2. //在此处使用变量即可,该变量就是元素
  3. }

注意事项:修改第三方变量的值不会影响到集合中的元素
快捷生成方式:需要遍历的数组和集合.for

三种循环的使用场景

  • 如果需要操作索引,使用普通for循环
  • 如果在遍历的过程中需要删除元素,请使用迭代器
  • 如果仅仅想遍历,那么使用增强for

    List集合

    List集合概述

  • 有序集合,这里的有序指的是存取顺序

  • 用户可以精确控制列表中每个元素的插入位置,用户可以通过整数索引访问元素,并搜索列表中的元素
  • 与Set集合不同,列表通常运行重复的元素

List集合特点

  • 有序:存储和去除的元素顺序一致
  • 有索引:可以通过索引操作元素
  • 可重复:存储的元素可以重复

    List集合特有方法

    | 方法名 | 说明 | | —- | —- | | void add(int index,E element) | 在此集合中的指定位置插入指定的元素 | | E remove(int index) | 删除指定索引处的元素,返回被删除的元素 | | E set(int index,E element) | 修改指定索引处的元素,返回被修改的元素 | | E get(int index) | 返回指定索引处的元素 |

数据结构

数据结构是计算机存储,组织数据的方式。是指相互之间存在的一种或多种特定关系的数据元素的集合。
通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率

  • 队列
  • 数组
  • 列表

栈:
数据进入栈模型的过程称为:压/进栈。
数据离开栈模型的过程称为:弹/出栈。
先进后出
队列:
数据从后端进入队列模型的过程称为:入队列
数据从前段离开队列模型的过程称为:出队列
先进先出
数组:
查询数据通过地址值和索引定位,查询任意数据耗时相同,查询速度快
删除数据时,要将原始数据删除,同时后面每个数据前移,删除效率低
添加数据时,添加位置后的每个数据后移,再添加元素,添加效率极低
链表
链表节点.png
链表是一种增删快的模型(对比数组)
链表是一种查询慢的模型(对比数组)
单向链表和双向链表
单向链表和双向链表.png

List集合常用实现类

List集合常用子类:ArrayList,LinkedList

  • ArrayList:底层数据结构是数组,查询快,增删慢
  • LinkedList:底层数据结构是链表,查询慢,增删快

    LinkedList集合的特有功能

    | 方法名 | 说明 | | —- | —- | | public void addFirst(E e) | 在该列表开头插入指定的元素 | | public void addLast(E e) | 将指定的元素追加到此列表的末尾 | | public E getFirst() | 返回此列表中的第一个元素 | | public E getLast() | 返回此列表中的最后一个元素 | | public E removeFirst() | 从此列表中删除并返回第一个元素 | | public E removeLast() | 从此列表中删除并返回最后一个元素 |

Set集合

特点

  • 可以去除重复
  • 存取顺序不一致
  • 没有带索引的方法,所以不能使用普通for循环遍历,也不能通过索引来获取,删除Set集合里面的元素

    TreeSet集合概述和特点

    TreeSet集合特点

  • 不包含重复元素的集合

  • 没有带索引的方法
  • 可以将元素按照规则进行排序

想要使用TreeSet,需要制定排序规则

自然排序Comparable的使用

  • 使用空参构造创建TreeSet集合
  • 自定义的Student类实现Comparable接口
  • 重写里面的compareTo方法

简单原理:

  • 如果返回值为负数,表示当前存入的元素是较小值,存左边
  • 如果返回值为0,表示当前存入的元素跟集合中元素重复了,不存
  • 如果返回值为正数,表示当前存入的元素是较大值,存右边

    比较器排序Comparator的使用

  • TreeSet的带参构造方法使用的是比较器排序对元素进行排序的

  • 比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(T o1, T o2)方法
  • 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

之间可以给TreeSet构造方法传入一个匿名内部类,或者Lambda表达式来实现Comparator。

两种比较方式小结

  • 自然排序:自定义类实现Comparable接口,重写compareTo方法,根据返回值进行排序。
  • 比较器排序:创建TreeSet对象的时候传递Comparator的实现类对象,重写compare方法,根据返回值进行排序。
  • 在使用的时候,默认使用自然排序,当自然排序不满足现在的需求时,使用比较器排序。

    数据结构-树

    二叉树

    数据结构-二叉树.png
    数据结构-二叉树1.png

    二叉查找树

    数据结构-二叉树2.png
    二叉查找树,又称为二叉排序树或者二叉搜索树
    特点:
  1. 每个节点上最多有两个子节点
  2. 每个节点的左子节点都是小于自己的
  3. 每个节点的右子节点都是大于自己的

二叉查找树添加节点规律:
小的存左边
大的存右边
一样的不存

平衡二叉树

二叉树左右两个子树的高度差不超过1
任意节点的左右两个子树都是一颗平衡二叉树

平衡二叉树-左旋-右旋

左旋:就是将根节点的右侧往左侧拉,原先的右子节点变成新的父节点,并把多余的左子节点出让,给已经降级的根节点当右子节点。
右旋:将根节点的左侧往右拉,左子节点变成了新的父节点,并把多余的右子节点出让,给已经降级根节点当左子节点。

小结

二叉查找树需要利用左旋和右旋机制保证树的平衡
注意点:

  • 判断添加元素与当前节点的关系
  • 成功添加之后,判断是否破坏了二叉树的平衡

旋转的四种情况
左左:当根节点左子树有节点插入,导致二叉树不平衡
数据结构-左左.png
左右:当根节点左子树的右子树有节点插入,导致二叉树不平衡
数据结构-左右.png
右右:当根节点右子树的右子树有节点插入,导致二叉树不平衡
数据结构-右右.png
右左:当根节点右子树的左子树有节点插入,导致二叉树不平衡
数据结构-右左.png

红黑树

  • 平衡二叉B树
  • 每一个节点可以是红或者黑
  • 红黑树不是高度平衡的,它的平衡是通过“自己的红黑规则”进行实现的

红黑规则

  1. 每一个节点或者是红色的,或者是黑色的
  2. 根节点必须是黑色
  3. 如果一个节点没有子节点或者父节点,则该节点相应的指针属性为Nil,这些Nil视为叶节点,每个叶节点(Nil)是黑色的
  4. 如果一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连的情况)
  5. 对每一个节点,从该节点到其他所有后代叶节点的简单路径上,均包含相同数目的黑色节点
    简单路径:只能向下,不能回头

添加节点

  • 添加的节点的颜色可以是红色的,也可以是黑色的

如果添加三个黑色节点,需要调整两次。
如果添加三个红色节点,需要调整一次。
所以,添加节点时,默认为红色,效率高。
红黑树在添加节点的时候:
添加的节点默认时红色的。
集合 - 图11

HashSet集合

HashSet集合特点

  • 底层数据结构是哈希表
  • 不能保证存储和取出的顺序完全一致
  • 没有带索引的方法,所以不能使用普通for循环遍历
  • 由于是Set集合,所以元素唯一

    哈希值

    哈希值(哈希码值):是JDK根据对象的地址或者属性值,算出来的int类型的整数
    Object类中有一个方法可以获取对象的哈希值

  • public int hashCode():根据对象的地址值计算出来的哈希值

对象的哈希值特点

  • 如果没有重写hashCode方法,那么是根据对象的地址值计算出来的哈希值。
    同一个对象多次调用hashCode()方法返回的哈希值是相同的
    不同对象的哈希值是不一样的。
  • 如果重写了hashCode方法,一般都是通过对象的属性值计算出哈希值。
    如果不同的对象属性值是一样的,那么计算出来的哈希值也是一样的。

    HashSet1.7版本原理

    底层结构:哈希表(数组 + 链表)
    数据结构之哈希表.png
  1. 创建一个默认长度16,默认加载因数为0.75的数组,数组名table
  2. 根据元素的哈希值根数组的长度计算出应存入的位置
  3. 判断当前位置是否为null,如果是null直接存入
  4. 如果存入的位置不为null,表示有元素,则调用equals方法比较属性值
  5. 如果一样,则不存,如果不一样,则存入数组,老元素挂在新元素下面
  6. 当数组里面存了16*0.75=12个元素的时候,数组就会扩容为原先的两倍

    HashSet1.8版本

    底层结构:哈希表。(数组、链表、红黑树的结合体)。
    当挂在下面的元素过多,那么不利于添加,也不利于查询,所以在JDK8以后
    当链表长度超过8的时候,自动转换为红黑树
    数据结构之哈希表1.8.png
    如果HashSet集合要存储自定义对象,那么必须重写hashCode和equals方法。

    Set集合小结

    Set集合小结.png

    Map集合

  • Interface Map K:键的数据类型;V:值的数据类型
  • 键不能重复,值可以重复
  • 键和值是一一对应的,每一个键只能找到自己对应的值
  • (键 + 值)这个整体 我们称之为“键值对”或者“键值对对象”,在Java中叫做“Entry对象”

    Map集合的基本功能

    | 方法名 | 说明 | | —- | —- | | V put(K key,V value) | 添加元素 | | V remove(Object key) | 根据键删除键值对元素 | | void clear() | 移除所有的键值对元素 | | boolean containsKey(Object key) | 判断集合是否包含指定的键 | | boolean containsValue(Object value) | 判断集合是否包含指定的值 | | boolean isEmpty() | 判断集合是否为空 | | int size() | 集合的长度,也就是集合中键值对的个数 |

第一种遍历方式

  1. 获取到所有的键
  2. 遍历Set集合的到每一个键
  3. 通过每一个键key,来获取到对应的值 | 方法名 | 说明 | | —- | —- | | Set<K> keySet() | 获取所有的键的集合 | | V get(Object key) | 根据键获取值 |

第二种遍历方式

  1. 要获取到所有的键值对对象
  2. Set集合中装的是键值对对象(Entry对象)
  3. Entry里装的是键和值 | 方法名 | 说明 | | —- | —- | | Set<Map.Entry<K,V>> entrySet() | 获取所有的键值对对象的集合 | | K getKey() | 获得键 | | V getValue() | 获得值 |

第三种遍历方式
forEach(Lambda表达式)

map.forEach(
            (String key,String value) ->{
                    System.out.println(key + value + "");
            }
        );

HashMap小结

  • HashMap底层是哈希表结构的,以键值对的形式存储
  • 依赖hashCode方法和equals方法保证的唯一
  • 如果要存储的是自定义对象,需要重写hashCode和equals方法

    TreeMap小结

  • TreeMap底层是红黑树结构的

  • 依赖自然排序或者比较器排序,对键进行排序
  • 如果键存储的是自定义对象,需要实现Comparable接口或者在创建TreeMap对象时候给出比较器排序规则

    可变参数

    可变参数:就是形参的个数是可以变化的

  • 格式:修饰符 返回值类型 方法名(数据类型...变量名){}

  • 范例:public static int sum(int...a){}

注意事项:

  • 这里的变量其实是一个数组
  • 如果一个方法有多个参数,包含可变参数,可变参数要放在最后

    创建不可变集合

  • 在List、Set、Map接口中,都存在of方法,可以创建一个不可变的集合

  • 这个集合不能添加,不能删除,不能修改。
  • 但是可以结合集合的带参构造,实现集合的批量添加。

    List<String> list2 = List.of("A", "B", "C", "D");
    ArrayList<String> list1 = new ArrayList<>(list);
    
  • 在Map接口中,还有一个ofEntries方法可以提高代码的阅读性。

  • 首先会把键值对封装成一个Entry对象,再把这个Entry对象添加到集合当中。