一.什么是集合

1.0特殊的容器--数组

      数组也是一种集合,可以装基本数据类型,也可以用来装对象。在实际开发中,如果是一组对象,优先使用集合而不是数组当容器,而不是集合,因为集合的长度是可以伸缩的。

1.1什么是容器

      集合是很多容器的总称,专门用来装Java对象的。如果基本数据类型的值,放到集合中,会自动装箱位对应的包装类对象。

1.2容器的存储结构

      数组的元素是相邻的,连续的,内存中开辟一整块完整的存储空间。而集合的类型很丰富,底层可能是数组,可能是链表,也可能是树结构等。有的集合是有序的,有的是无序的,有点是允许元素重复的,有的是不允许元素重复的。

1.3分类

1.3.1Collection

用途:用于存储一组对象

1.3.2Map

用途:用于存储一组(key,value)键值对/映射关系

1.4关注点

(1)增删查改,遍历等操作

(2)不同集合的特点

(3)底层的实现原理

二.Set

2.1知识点

    /**
     * 1. HashSet:追求极致性能的去重选择
     *
     * - 底层结构:哈希表 (Hash Table)
     * - 存储规律:无序(不保证插入顺序,也不保证自然顺序)。
     * - 核心特点:
     *   1. 查询、插入、删除效率极高,平均时间复杂度 O(1)。
     *   2. 允许存储一个 null 元素。
     *   3. 内存占用相对较小。
     * - 迭代顺序:不可预测,随扩容可能改变。
     *
     * 适用场景:仅需去重,对顺序无任何要求时的默认首选。
     */

/**
 * 2. LinkedHashSet:兼顾性能与插入顺序
 *
 * - 底层结构:哈希表 + 双向链表 (Hash Table + Doubly LinkedList)
 * - 存储规律:严格按插入顺序存储。
 * - 核心特点:
 *   1. 查询效率接近 HashSet (O(1)),但略慢。
 *   2. 额外维护链表指针,内存开销略高于 HashSet。
 *   3. 允许存储一个 null 元素。
 *
 * 适用场景:需要去重,且必须按插入顺序遍历时。
 */

/**
 * 3. TreeSet:需要排序与范围查询的选择
 *
 * - 底层结构:红黑树 (Red-Black Tree,一种自平衡二叉搜索树)
 * - 存储规律:按元素的自然顺序(升序)或自定义比较器排序。
 * - 核心特点:
 *   1. 支持排序、获取最值(first/last)、范围查询(subSet)等操作。
 *   2. 查询、插入、删除效率为 O(log n)。
 *   3. 默认不允许 null 元素(会抛出 NullPointerException)。
 *      *注:若使用自定义 Comparator 且显式处理 null,则可存入 null。
 *
 * 适用场景:需要自动排序、查找最值或范围数据时。
 */

/**
 * 3.1 HashSet 与 LinkedHashSet 的去重原理
 *
 * 依赖于元素对象的两个方法:hashCode() 和 equals()。
 *
 * 1. 哈希定位:首先调用元素的 hashCode() 方法。
 *    - 如果哈希值不同,直接判定元素不重复,放入集合。
 *    - 如果哈希值相同,进入下一步(可能存在哈希冲突)。
 * 2. 内容比对:调用 equals() 方法比较内容。
 *    - 如果 equals() 返回 true,判定为重复元素,添加失败。
 *    - 如果 equals() 返回 false,判定为不同元素,放入集合。
 *
 * 注意:重写 equals() 时,必须重写 hashCode(),以保证逻辑一致。
 */

/**
 * 3.2 TreeSet 的去重原理
 *
 * 依赖于元素的比较结果。
 *
 * 1. 判定标准:当比较结果返回 0 时,判定元素重复。
 * 2. 优先策略:元素类实现 Comparable 接口,重写 compareTo() 方法。
 * 3. 灵活策略:创建 TreeSet 时传入 Comparator 接口实现,自定义 compare() 方法。
 *
 * 注意:如果两个对象通过比较器判断为相等(返回0),TreeSet 视为同一元素。
 */

/**
 * 自定义对象用于测试去重
 */

    /**
     * 总结:如何选择?
     *
     * 1. 需要排序 / 范围查询? -> 选 TreeSet
     * 2. 需要保持插入顺序? -> 选 LinkedHashSet
     * 3. 什么都不需要,只要最快的去重? -> 选 HashSet (默认首选)
     *
     * 线程安全提示:以上三种 Set 实现均非线程安全。
     * 多线程环境下需使用 Collections.synchronizedSet() 或并发包下的类。
     */

2.2 coding

package Collection.Set;

import Collection.Student;
import Collection.Teacher;
import org.junit.jupiter.api.Test;

import java.util.Comparator;
import java.util.HashSet;

public class  HashSet_ {
    /**
     * 1. HashSet:追求极致性能的去重选择
     *
     * - 底层结构:哈希表 (Hash Table)
     * - 存储规律:无序(不保证插入顺序,也不保证自然顺序)。
     * - 核心特点:
     *   1. 查询、插入、删除效率极高,平均时间复杂度 O(1)。
     *   2. 允许存储一个 null 元素。
     *   3. 内存占用相对较小。
     * - 迭代顺序:不可预测,随扩容可能改变。
     *
     * 适用场景:仅需去重,对顺序无任何要求时的默认首选。
     */

/**
 * 2. LinkedHashSet:兼顾性能与插入顺序
 *
 * - 底层结构:哈希表 + 双向链表 (Hash Table + Doubly LinkedList)
 * - 存储规律:严格按插入顺序存储。
 * - 核心特点:
 *   1. 查询效率接近 HashSet (O(1)),但略慢。
 *   2. 额外维护链表指针,内存开销略高于 HashSet。
 *   3. 允许存储一个 null 元素。
 *
 * 适用场景:需要去重,且必须按插入顺序遍历时。
 */

/**
 * 3. TreeSet:需要排序与范围查询的选择
 *
 * - 底层结构:红黑树 (Red-Black Tree,一种自平衡二叉搜索树)
 * - 存储规律:按元素的自然顺序(升序)或自定义比较器排序。
 * - 核心特点:
 *   1. 支持排序、获取最值(first/last)、范围查询(subSet)等操作。
 *   2. 查询、插入、删除效率为 O(log n)。
 *   3. 默认不允许 null 元素(会抛出 NullPointerException)。
 *      *注:若使用自定义 Comparator 且显式处理 null,则可存入 null。
 *
 * 适用场景:需要自动排序、查找最值或范围数据时。
 */

/**
 * 3.1 HashSet 与 LinkedHashSet 的去重原理
 *
 * 依赖于元素对象的两个方法:hashCode() 和 equals()。
 *
 * 1. 哈希定位:首先调用元素的 hashCode() 方法。
 *    - 如果哈希值不同,直接判定元素不重复,放入集合。
 *    - 如果哈希值相同,进入下一步(可能存在哈希冲突)。
 * 2. 内容比对:调用 equals() 方法比较内容。
 *    - 如果 equals() 返回 true,判定为重复元素,添加失败。
 *    - 如果 equals() 返回 false,判定为不同元素,放入集合。
 *
 * 注意:重写 equals() 时,必须重写 hashCode(),以保证逻辑一致。
 */

/**
 * 3.2 TreeSet 的去重原理
 *
 * 依赖于元素的比较结果。
 *
 * 1. 判定标准:当比较结果返回 0 时,判定元素重复。
 * 2. 优先策略:元素类实现 Comparable 接口,重写 compareTo() 方法。
 * 3. 灵活策略:创建 TreeSet 时传入 Comparator 接口实现,自定义 compare() 方法。
 *
 * 注意:如果两个对象通过比较器判断为相等(返回0),TreeSet 视为同一元素。
 */

/**
 * 自定义对象用于测试去重
 */

    /**
     * 总结:如何选择?
     *
     * 1. 需要排序 / 范围查询? -> 选 TreeSet
     * 2. 需要保持插入顺序? -> 选 LinkedHashSet
     * 3. 什么都不需要,只要最快的去重? -> 选 HashSet (默认首选)
     *
     * 线程安全提示:以上三种 Set 实现均非线程安全。
     * 多线程环境下需使用 Collections.synchronizedSet() 或并发包下的类。
     */

    @Test
    public void testHashSetAdd() {
        HashSet hashSet = new HashSet();
        hashSet.add("Hello");
        hashSet.add("World");
        hashSet.add("Hello");// 重复元素,自动去重,即添加失败
        System.out.println(hashSet);
    }

    @Test
    public void testHashSetAddStudentAndCheckEqual() {
        HashSet set = new HashSet();
        set.add(new Student("张三",89));
        set.add(new Student("张三",89));
        set.add(new Student("李四",78));
        set.add(new Student("王五",91));
        for(Object o:set){
            System.out.println(o);
        }

        Student s1 = new Student("张三",89);
        Student s2 = new Student("张三",89);
        System.out.println(s1 == s2);//false
        System.out.println(s1.equals(s2));//true
    }


}

三.List

3.1List接口的方法

package Collection.List;

import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.function.Predicate;

public class List_ {
    /*
    * List接口:继承自Collection接口
    * 1.List特点和子类:
    * - 所有List接口的实现类有共同点:有序、元素可重复
      - 所有List接口的实现类有相同的API:在List接口中定义
         * List接口的实现类有:ArrayList、LinkedList、Vector,Stack继承自Vector
            ArrayList:jdk1.2开始出现的,底层是数组实现
            LinkedList:jdk1.2开始出现的,底层是链表实现
            Vector:jdk1.0开始出现的,底层是数组实现
            * Stack:jdk1.0开始出现的,底层是数组实现
      2.List的方法:
      * 2.1 增
      *     2.1.1 boolean add(ElementType e) : 添加一个元素
      *     2.1.2 void add(int index, ElementType e) : 添加一个元素,指定位置
      *     2.1.3 boolean addAll(Collection<? extends ElementType> c) : 添加一个集合
      *     2.1.4 boolean addAll(int index, Collection<? extends ElementType> c) : 添加一个集合,指定位置
      * 2.2 删
      *     2.2.1 ElementType remove(int index) : 删除指定位置的元素
      *     2.2.2 boolean remove(Object o) : 删除一个元素
      *     2.2.3 void clear() : 删除所有元素
      *     2.2.4 boolean removeAll(Collection<?> c) : 删除一个集合
      *     2.2.5 boolean retainAll(Collection<?> c) : 保留一个集合
      *     2.2.6 removeIf(Predicate<? super ElementType> filter) : 删除满足条件的元素
      * 2.3 查
      *     2.3.1 ElementType get(int index) : 获取指定位置的元素
      *     2.3.2 int indexOf(Object o) : 获取指定元素的索引
      *     2.3.3 int lastIndexOf(Object o) : 获取指定元素的索引,从后往前找
      *     2.3.4 List<ElementType> subList(int fromIndex, int toIndex) : 获取指定范围的子列表
      * 2.4 改
      *     2.4.1 ElementType set(int index, ElementType element) : 修改指定位置的元素
      *     2.4.2 void replaceAll(UnaryOperator<ElementType> operator) : 替换所有元素
      * 2.5 遍历
      *     2.5.1 forEach(Consumer<? super ElementType> action) : 遍历
      *     2.5.2 Iterator<ElementType> iterator() : 获取迭代器
      *     2.5.3 for循环 + size() + get(index)
      *     2.5.4 ListIterator<ElementType> listIterator() : 获取列表迭代器
      *               *boolean hasNext() : 判断是否还有下一个元素
      *               *boolean hasPrevious() : 判断是否还有上一个元素
      *               *ElementType next() : 获取下一个元素
      *               *int nextIndex() : 获取下一个元素的索引
      *               *ElementType previous() : 获取上一个元素
      *               *int previousIndex() : 获取上一个元素的索引
    * */
    @Test
    public void testListCreateAndAdd() {
        /*2.1 增
      *     2.1.1 boolean add(ElementType e) : 添加一个元素
      *     2.1.2 void add(int index, ElementType e) : 添加一个元素,指定位置
      *     2.1.3 boolean addAll(Collection<? extends ElementType> c) : 添加一个集合
      *     2.1.4 boolean addAll(int index, Collection<? extends ElementType> c) : 添加一个集合,指定位置*/
        ArrayList<String> list = new ArrayList<>();
        list.add("Apple");
        list.add("Orange");
        list.add("Pear");
        //System.out.println(list);
        ListIterator<String> iterator = list.listIterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }

    @Test
    public void testListRemove() {
        /*2.2 删
      *     2.2.1 ElementType remove(int index) : 删除指定位置的元素
      *     2.2.2 boolean remove(Object o) : 删除一个元素
      *     2.2.3 void clear() : 删除所有元素
      *     2.2.4 boolean removeAll(Collection<?> c) : 删除一个集合
      *     2.2.5 boolean retainAll(Collection<?> c) : 保留一个集合
      *     2.2.6 removeIf()*/
        ArrayList<String> list = new ArrayList<>();
        list.add("Apple");
        list.add("Orange");
        list.add("Pear");
        System.out.println("原始列表为 : " + list);
        ListIterator<String> iterator = list.listIterator();
        /*while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }*/
        list.remove("Pear");
        System.out.println("删除后的列表为 : " + list);
        list.remove(1);
        System.out.println("删除后的列表为 : " + list);

        list.add("Apple");
        list.add("Orange");
        list.add("Pear");
        System.out.println("添加后的列表为 : " + list);
        Predicate<String> predicate = new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.startsWith("A");
            }
        };
        list.removeIf(predicate);
        System.out.println("removeIf删除后的列表为 : " + list);
    }

    @Test
    public void testQuery(){
/*  2.3 查
*    2.3.1 ElementType get(int index) : 获取指定位置的元素
*    2.3.2 int indexOf(Object o) : 获取指定元素的索引
*    2.3.3 int lastIndexOf(Object o) : 获取指定元素的索引,从后往前找
*    2.3.4 List<ElementType> subList(int fromIndex, int toIndex) : 获取指定范围的子列表*/
        ArrayList<String> list = new ArrayList<>();
        list.add("Apple");
        list.add("Orange");
        list.add("Pear");
        list.add("Watermaloon");
        list.add("Banana");
        list.add("Apple");
        list.add("Apple");
        list.add("Banana");

        System.out.println("原始列表为 : " + list);
        System.out.println("Apple的索引为 : " + list.indexOf("Apple"));
        System.out.println("索引1的元素为 : " + list.get(1));
        System.out.println("最后一个Apple的索引为 : " + list.lastIndexOf("Apple"));
        System.out.println("子列表为 : " + list.subList(2,5));
    }

    @Test
    public void testTraverse(){
        /*2.5 遍历
*     2.5.1 forEach(Consumer<? super ElementType> action) : 遍历
*     2.5.2 Iterator<ElementType> iterator() : 获取迭代器
*     2.5.3 for循环 + size() + get(index)
*     2.5.4 ListIterator<ElementType> listIterator() : 获取列表迭代器
*       *boolean hasNext() : 判断是否还有下一个元素
*       *boolean hasPrevious() : 判断是否还有上一个元素*/

        ArrayList<String> list = new ArrayList<>();
        list.add("Apple");
        list.add("Orange");
        list.add("Pear");
        list.add("Watermaloon");
        list.add("Banana");
        list.add("Apple");
        list.add("Apple");
        list.add("Banana");

        System.out.println("遍历方法1 : ");
        for(String s:list){
            System.out.println(s);
        }

        System.out.println("遍历方法2 : ");
        for(int i = 0; i < list.size(); i++){
            System.out.println(list.get(i));
        }

        System.out.println("遍历方法3 : ");
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

3.2ArrayList和Verctor

3.2.1ArrayList和Vector的区别

/*
* 各种数组的区别 :
* 1.List接口的子类
* Vector : 古老的动态数组
* Stack : 古老的栈结构容器
* ArrayList : jdk1.2开始出现的较新的动态数组
* LinkedList : jdk1.2开始出现的较新的链表(同时可以当栈节后,队列使用)
* 2.动态数组ArrayList和Vector的区别 :
* - ArrayList :
*     1.线程不安全,速度更快
*     2.new ArrayList()的底层的数组长度默认是0,首次添加元素时,会自动扩容为10
*     3.扩容机制 : 数组扩容为原来的1.5倍
*     4.优点 : 空间利用率高
*     5.缺点 : 扩容频率高,搬家次数多,无法手动指定扩容的数量
*
* - Vector :
*     1.线程安全,速度更慢
*     2.new Vector()的底层的数组长度默认是10
*     3.优点 : 扩容频率少,搬家次数少
*     4.缺点 : 空间浪费的可能性大
*     5.Vector考虑到自己扩容太快,一次变为原来的2倍长度,就提供了另一种扩容的方式,你可以手动指定扩容多少空间。
*
* */

3.2.2ArrayList最初容量为0,首次添加后长度变为10,扩容机制为原来的1.5倍

创建伊始:

添加10个元素


package Collection.List;

import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.Vector;

public class ArrayList_ {
    /*
    * 各种数组的区别 :
    * 1.List接口的子类
    * Vector : 古老的动态数组
    * Stack : 古老的栈结构容器
    * ArrayList : jdk1.2开始出现的较新的动态数组
    * LinkedList : jdk1.2开始出现的较新的链表(同时可以当栈节后,队列使用)
    * 2.动态数组ArrayList和Vector的区别 :
    * - ArrayList :
    *     1.线程不安全,速度更快
    *     2.new ArrayList()的底层的数组长度默认是0,首次添加元素时,会自动扩容为10
    *     3.扩容机制 : 数组扩容为原来的1.5倍
    *     4.优点 : 空间利用率高
    *     5.缺点 : 扩容频率高,搬家次数多,无法手动指定扩容的数量
    *
    * - Vector :
    *     1.线程安全,速度更慢
    *     2.new Vector()的底层的数组长度默认是10
    *     3.优点 : 扩容频率少,搬家次数少
    *     4.缺点 : 空间浪费的可能性大
    *     5.Vector考虑到自己扩容太快,一次变为原来的2倍长度,就提供了另一种扩容的方式,你可以手动指定扩容多少空间。
    *
    * */
    @Test
    public void testArrayList() {
        ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            list.add("hello" + i);
            System.out.println("第" + i + "次添加元素");
        }
    }
    @Test
    public void testVector() {
        Vector<String> v = new Vector<>(10,2);//创建一个容量为10,每次扩容2倍
        for(int i = 0; i < 10; i++){
            v.add("hello" + i);
        }
        System.out.println(v);
        v.add("hello10李");
        System.out.println(v.size());
    }
}

3.3Stack

3.3.1Stack功能

 Stack是栈结构的容器,它遵循 先进后出 的原则。
    注意:Stack同时也是List接口的实现类,所以List之前的方法,它也有。
    Stack提供了几个特殊的方法,来满足 先进后出的操作原则:
    (1)push(元素):入栈
    (2)pop():弹出栈顶元素,然后返回
    (3)peek():查看栈顶元素
    (4)search(元素):从栈顶数这个元素是第几个

3.3.2code

package Collection.List;

import org.junit.jupiter.api.Test;

import java.util.Stack;

public class Stack_ {
/*
* Stack是栈结构的容器,它遵循 先进后出 的原则。
    注意:Stack同时也是List接口的实现类,所以List之前的方法,它也有。
    Stack提供了几个特殊的方法,来满足 先进后出的操作原则:
    (1)push(元素):入栈
    (2)pop():弹出栈顶元素,然后返回
    (3)peek():查看栈顶元素
    (4)search(元素):从栈顶数这个元素是第几个
* */
    @Test
    public void testStackCreateAndAdd() {
        Stack<String> s = new Stack<>();
        s.push("Apple");
        s.push("Orange");
        s.push("Pear");
        System.out.println(s);
    }

    @Test
    public void testStackRemove() {
        Stack<String> s = new Stack<>();
        s.push("Apple");
        s.push("Orange");
        s.push("Pear");
        System.out.println("原始栈为 : " + s);
        System.out.println("弹出的栈顶元素为 : " + s.pop());
        System.out.println("弹出的栈顶元素为 : " + s.pop());
    }

    @Test
    public void testStackQuery() {
        Stack<String> s = new Stack<>();
        s.push("Apple");
        s.push("Orange");
        s.push("Pear");
        System.out.println("原始栈为 : " + s);
        System.out.println(s.search("Apple"));
    }

    @Test
    public void testPeek(){
        Stack<String> s = new Stack<>();
        s.push("Apple");
        s.push("Orange");
        s.push("Pear");
        System.out.println("原始栈为 : " + s);
        System.out.println("栈顶元素为 : " + s.peek());
    }

    @Test
    public void testStackTraverse() {
        Stack<String> s = new Stack<>();
        s.push("Apple");
        s.push("Orange");
        s.push("Pear");
        System.out.println("原始栈为 : " + s);
        while (!s.empty()) {
            System.out.println(s.pop());
        }
    }
}

3.4LinkList

3.4.1创建顺序

调用 LinkedList 对象的核心内存流程:先加载类(方法区)→ 执行 main 方法(虚拟机栈)→ 在堆中创建 LinkedList 对象 → 虚拟机栈中存储对象引用

3.4.2LinkList方法

package Collection.List;

import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.LinkedList;

public class LinkedList_ {
    /*
    1 LinkedList 的核心特性
        1.1 底层结构:双向链表,每个节点包含前驱、后继指针,无固定容量,无需扩容
        1.2 核心优势:首尾元素增删效率高(O (1)),支持双端操作
        1.3 核心劣势:随机访问效率低(O (n)),需遍历链表
    2 List 接口通用方法(LinkedList 实现)
        这类方法是所有 List 集合的通用方法,LinkedList 完全支持,核心用于 “通用的增删改查”。
        2.1 新增元素
            2.1.1 boolean add (E e):将元素添加到链表末尾,返回是否成功(始终返回 true)
            2.1.2 void add (int index, E element):在指定索引位置插入元素(需遍历到指定位置,效率低)
            2.1.3 boolean addAll (Collection<? extends E> c):将集合中所有元素添加到链表末尾
            2.1.4 boolean addAll (int index, Collection<? extends E> c):从指定索引开始插入集合中所有元素
        2.2 删除元素
            2.2.1 E remove (int index):删除指定索引位置的元素,返回被删除的元素
            2.2.2 boolean remove (Object o):删除第一个匹配的指定元素,返回是否删除成功
            2.2.3 void clear ():清空链表中所有元素
            2.3 修改元素
            2.3.1 E set (int index, E element):替换指定索引位置的元素,返回原元素
        2.4 查询元素
            2.4.1 E get (int index):获取指定索引位置的元素(需遍历链表,随机访问效率低)
            2.4.2 int size ():返回链表中元素的个数
            2.4.3 boolean isEmpty ():判断链表是否为空
            2.4.4 boolean contains (Object o):判断链表是否包含指定元素
            2.4.5 int indexOf (Object o):返回第一个匹配元素的索引,无则返回 - 1
            2.4.6 int lastIndexOf (Object o):返回最后一个匹配元素的索引,无则返回 - 1
        2.5 遍历相关
            2.5.1 Iterator<E> iterator ():获取普通迭代器,正向遍历
            2.5.2 ListIterator<E> listIterator ():获取 List 迭代器,支持双向遍历
            2.5.3 ListIterator<E> listIterator (int index):从指定索引开始的 List 迭代器
    3 LinkedList 特有方法(双端队列 / 链表专属)
        这类方法是 LinkedList 作为双端队列(Deque)的特有方法,专门优化 “首尾操作”,效率为 O (1),是 LinkedList 的核心优势。
        3.1 首尾新增元素(队列 / 栈操作)
            3.1.1 void addFirst (E e):将元素添加到链表头部
                3.1.2 void addLast (E e):将元素添加到链表尾部(等同于 add (E e))
                3.1.3 boolean offerFirst (E e):添加元素到头部,返回是否成功(始终返回 true)
                3.1.4 boolean offerLast (E e):添加元素到尾部,返回是否成功(始终返回 true)
                3.1.5 void push (E e):将元素压入栈顶(等同于 addFirst (E e),栈操作)
        3.2 首尾删除元素
            3.2.1 E removeFirst ():删除并返回头部元素,链表为空时抛 NoSuchElementException
            3.2.2 E removeLast ():删除并返回尾部元素,链表为空时抛 NoSuchElementException
            3.2.3 E pollFirst ():删除并返回头部元素,链表为空时返回 null(更安全)
            3.2.4 E pollLast ():删除并返回尾部元素,链表为空时返回 null(更安全)
            3.2.5 E pop ():弹出栈顶元素(等同于 removeFirst (),栈操作)
        3.3 首尾查询元素(不删除)
            3.3.1 E getFirst ():获取头部元素,链表为空时抛 NoSuchElementException
            3.3.2 E getLast ():获取尾部元素,链表为空时抛 NoSuchElementException
            3.3.3 E peekFirst ():获取头部元素,链表为空时返回 null(更安全)
            3.3.4 E peekLast ():获取尾部元素,链表为空时返回 null(更安全)
     */
    /*
    *Vector和ArrayList的区别:
     1.ArrayList底层是一个数组。
            数组的元素是连续存储的,开辟一整块连续的存储空间,如果通过下标访问元素,效率非常高,时间复杂度是O(1)。
        O(1)是一个固定值,代表无论数组长度是多长,根据下标查找元素的效率是一样的,都是一步到位。
        比喻:大家出去住酒店,房间号是连续的,你告诉我房间号,我直接奔这个房间就可以了。
            数组的长度是固定的,不过存了就要扩容。需要频繁的搬家。
        数组如果中间插入或删除元素,后面的元素需要移动,因为要保证连续性。

     2.LinkedList:它的底层是一个双向链表。
            链表的元素不一定是连续的,需要前后元素记录对方的地址。比喻:大家出去住酒店,房间号不是连续的,甚至不在一个酒店。每个人需要记前后同学住在哪里。
        如果要找第5个人,需要从第1个开始,陆续拿到下一个同学的地址,找到第5个。如果通过下标访问元素,效率较低,时间复杂度是O(n)。
        链表不需要扩容,不需要搬家。

     问:动态数组效率高,还是链表效率高?
      (1)如果根据下标访问元素,动态数组高。
      (2)如果是非末尾位置插入和删除,理论上是链表高,因为不需要扩容移动元素,也不需要扩容。

     如果是在Java中,双向链表的效率不见得高,因为双向链表需要结点对象,而创建结点,回收结点也是一个麻烦的事情。
    * */
    @Test
    public void testLinkedListCreateAndAdd() {
        LinkedList<String> list = new LinkedList<>();
        list.add("hello1");
        list.add("hello2");
        list.add("hello3");
        list.add("hello4");
        System.out.println("添加后的列表为 : " + list);
        LinkedList<String> list2 = new LinkedList<>(Arrays.asList("hello5", "hello6", "hello7"));
        System.out.println("添加后的列表为 : " + list2);
    }
    @Test
    public void testAddAsInsert(){
        LinkedList<String> list = new LinkedList<>();
        list.add("hello1");
        list.add("hello2");
        list.add("hello3");
        list.add(1,"hello4");
        System.out.println("修改后的列表为 : " + list);
    }
    @Test
    public void testAddFirst() {
        LinkedList<String> list = new LinkedList<>();
        list.addFirst("hello1");
        list.addFirst("hello2");
        list.addFirst("hello3");
        System.out.println("添加后的列表为 : " + list);
    }

    @Test
    public void testAddLast() {
        LinkedList<String> list = new LinkedList<>();
        list.addLast("hello1");
        list.addLast("hello2");
        list.addLast("hello3");
        System.out.println("添加后的列表为 : " + list);
    }

    @Test
    public void testRemoveFirst() {
        LinkedList<String> list = new LinkedList<>();
        list.add("hello1");
        list.add("hello2");
        list.add("hello3");
        System.out.println("删除前的列表为 : " + list);
        list.removeFirst();
        System.out.println("删除后的列表为 : " + list);
    }

    @Test
    public void testRemoveLast() {
        LinkedList<String> list = new LinkedList<>();
        list.add("hello1");
        list.add("hello2");
        list.add("hello3");
        System.out.println("删除前的列表为 : " + list);
        list.removeLast();
        System.out.println("删除后的列表为 : " + list);
    }
    @Test
    public void testRemoveMediumElem(){
        LinkedList<String> list = new LinkedList<>();
        list.add("hello1");
        list.add("hello2");
        list.add("hello3");
        list.add("hello4");
        list.remove("hello2");
        list.remove(2);
        System.out.println("删除后的列表为 : " + list);
    }
    @Test
    public void testGetFirst() {
        LinkedList<String> list = new LinkedList<>();
        list.add("hello1");
        list.add("hello2");
        list.add("hello3");
        System.out.println("获取的元素为 : " + list.getFirst());
    }

    @Test
    public void testGetLast() {
        LinkedList<String> list = new LinkedList<>();
        list.add("hello1");
        list.add("hello2");
        list.add("hello3");
        System.out.println("获取的元素为 : " + list.getLast());
    }

    @Test
    public void testSet() {
        LinkedList<String> list = new LinkedList<>();
        list.add("hello1");
        list.add("hello2");
        list.add("hello3");
        list.set(1, "hello4");
        System.out.println("修改后的列表为 : " + list);
    }

    @Test
    public void testContains() {
        LinkedList<String> list = new LinkedList<>();
        list.add("hello1");
        list.add("hello2");
        list.add("hello3");
        System.out.println("列表中是否包含hello2 : " + list.contains("hello4"));
    }
}

3.4Queue

package Collection.Queue;

import org.junit.jupiter.api.Test;

import java.util.LinkedList;
import java.util.Queue;

public class Queue_ {
    /*
    * 普通队列方法:
    * 1. 插入
    *   1.1 add(E e):将元素添加到队列末尾,返回是否成功(始终返回 true) 队列满时抛出异常
    *   1.2 offer(E e):将元素添加到队列末尾,返回是否成功(始终返回 true) 不抛出异常,返回特殊值
    *
    * 2. 删除
    *   2.1 remove():删除并返回队列头部元素,队列为空时抛 NoSuchElementException
    *   2.2 poll():删除并返回队列头部元素,队列为空时返回 null(更安全)
    *
    * 3.检查
    *   3.1 element():返回队列头部元素,队列为空时抛 NoSuchElementException
    *   3.2 peek():返回队列头部元素,队列为空时返回 null(更安全)
    *
    * 4. 查询
    *   4.1 size():返回队列元素个数
    *   4.2 isEmpty():判断队列是否为空
    *   4.3 contains(Object o):判断队列是否包含指定元素
    *   4.4 toArray():返回队列元素
    *
    * 5. 遍历
    *   5.1 迭代器:iterator()
    *   5.2 增强for:for (E e : queue)
    *   5.3 普通for:for (int i = 0; i < queue.size(); i++)
    * */
    @Test
    public void testQueueCreateAndOffer(){
        Queue<String> queue = new LinkedList<>();
        queue.offer("hello1");
        queue.offer("hello2");
        queue.offer("hello3");
        System.out.println("添加后的队列为 : " + queue);
    }

    @Test
    public void testQueueRemoveAndPoll(){
        Queue<String> queue = new LinkedList<>();
        queue.offer("hello1");
        queue.offer("hello2");
        queue.offer("hello3");
        System.out.println("删除前的队列为 : " + queue);
        queue.remove();
        System.out.println("删除后的队列为 : " + queue);
        queue.poll();
        System.out.println("删除后的队列为 : " + queue);
    }

    @Test
    public void testQueueElementAndPeek(){
        Queue<String> queue = new LinkedList<>();
        queue.offer("hello1");
        queue.offer("hello2");
        queue.offer("hello3");
        System.out.println("队首元素为 : " + queue.element());
        System.out.println("队首元素为 : " + queue.peek());
    }

    @Test
    public void testQueueSizeIsEmptyContains(){
        Queue<String> queue = new LinkedList<>();
        queue.offer("hello1");
        queue.offer("hello2");
        queue.offer("hello3");
        System.out.println("队列元素个数为 : " + queue.size());
        System.out.println("队列是否为空 : " + queue.isEmpty());
        System.out.println("队列是否包含 hello1 : " + queue.contains("hello1"));
        System.out.println("队列是否包含 hello4 : " + queue.contains("hello4"));
    }

    @Test
    public void testQueueToArray(){
        Queue<String> queue = new LinkedList<>();
        queue.offer("hello1");
        queue.offer("hello2");
        queue.offer("hello3");
        Object[] list = queue.toArray();
        for(Object o : list){
            System.out.println(o);
        }
    }

    @Test
    public void testQueueIterator(){
        Queue<String> queue = new LinkedList<>();
        queue.offer("hello1");
        queue.offer("hello2");
        queue.offer("hello3");
        for(String s : queue){
            System.out.println(s);
        }
    }
}

四.Map

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐