程序员scholar 程序员scholar
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
npm

(进入注册为作者充电)

  • 数据结构

    • 时间复杂度
    • 初识集合
    • List接口
      • Set接口
      • Queue接口
      • Map接口
      • Collections工具类
      • 模拟实现ArrayList
      • 单向链表的实现
      • 双向链表的实现
      • 树和二叉树的实现
      • 二叉搜索树的实现
    • Java数据结构
    • 数据结构
    scholar
    2024-03-21
    目录

    List接口

    在这里插入图片描述

    • List集合类中元素有序(即添加和取出顺序一致),且可重复
    • List集合中的每个元素都有其对应的顺序索引,即支持索引;
    • List容器中的元素都对应一个整数型的序号记其在容器中的位置,可以根据序号存取容器中的元素
    • List常用接口有 ArrayList、LinkedList、Vector
            // 创建 List 集合
            List<String> fruits = new ArrayList<>();
    
            // 添加元素
            fruits.add("苹果");
            fruits.add("香蕉");
            fruits.add("橘子");
            fruits.add("香蕉");  // 可重复添加元素
    
            // 显示 List 中的所有元素
            System.out.println("List中的元素(按添加顺序): " + fruits); // [苹果, 香蕉, 橘子, 香蕉]
    
            // 使用索引访问元素
            System.out.println("第一个元素是: " + fruits.get(0)); // 苹果
            System.out.println("第三个元素是: " + fruits.get(2)); // 橘子
    
            // 修改元素
            fruits.set(1, "葡萄");  // 将第二个元素(索引为1)修改为 "葡萄"
            System.out.println("修改后的List: " + fruits); // [苹果, 葡萄, 橘子, 香蕉]
    
            // 删除元素
            fruits.remove(3);  // 删除第四个元素(索引为3)
            System.out.println("删除元素后的List: " + fruits); // [苹果, 葡萄, 橘子]
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23

    # 1. List 接口的常用方法

    方法 描述
    add(int index, Object ele) 在索引 index 处添加元素 ele
    addAll(int index, Collection eles) 从索引 index 开始,添加 eles 集合的所有元素
    get(int index) 获取索引 index 处的元素
    indexOf(Object obj) 查找 obj 的首次出现位置
    lastIndexOf(Object obj) 查找 obj 的最后出现位置
    remove(int index) 移除索引 index 处的元素
    set(int index, Object ele) 将索引 index 处的元素替换为 ele
    subList(int fromIndex, int toIndex) 获取从 fromIndex 到 toIndex 的子列表

    更多方法可以自行JDK API在线查询 (opens new window) 或 下载中文版JavaAPI帮助文档【免费下载】 (opens new window)

    import java.util.ArrayList;
    import java.util.List;
    
    public class ListMethodsDemo {
        public static void main(String[] args) {
            // 创建一个ArrayList,并使用List接口引用它
            List<String> list = new ArrayList<>();
    
            // 1. 在列表末尾添加元素
            list.add("开心的你");
            // 在列表的开始位置(索引0)添加元素
            list.add(0, "帅气的我");
            System.out.println("添加元素后的列表: " + list);
            // 输出: [帅气的我, 开心的你]
    
            // 2. 从指定位置开始添加另一个集合中的所有元素
            List<String> list1 = new ArrayList<>();
            list1.add("Jack");
            list1.add("Tom");
            list1.add("Marry");
            list.addAll(1, list1);
            System.out.println("在索引1处添加另一个集合后的列表: " + list);
            // 输出: [帅气的我, Jack, Tom, Marry, 开心的你]
    
            // 3. 获取指定位置的元素
            System.out.println("列表中索引0处的元素: " + list.get(0));
            // 输出: 帅气的我
    
            // 4. 查找元素首次出现的位置
            System.out.println("‘开心的你’首次出现的位置: " + list.indexOf("开心的你"));
            // 输出: 4
    
            // 5. 查找元素最后一次出现的位置
            list.add("Jack"); // 添加一个重复元素
            System.out.println("‘Jack’最后一次出现的位置: " + list.lastIndexOf("Jack"));
            // 输出: 5
    
            // 6. 移除指定位置的元素
            System.out.println("移除索引5处的元素: " + list.remove(5));
            System.out.println("移除元素后的列表: " + list);
            // 输出: [帅气的我, Jack, Tom, Marry, 开心的你]
    
            // 7. 替换指定位置的元素
            list.set(1, "!!!");
            System.out.println("将索引1处的元素替换后的列表: " + list);
            // 输出: [帅气的我, !!!, Tom, Marry, 开心的你]
    
            // 8. 获取子列表
            System.out.println("索引2到4之间的子列表: " + list.subList(2, 4));
            // 输出: [Tom, Marry]
            // 注意: subList方法返回的范围是左闭右开,即包括fromIndex,不包括toIndex
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53

    # 2. List的五种遍历方式

    import java.util.*;
    
    public class ListFor {
        public static void main(String[] args) {
            // List的实现接口子类ArrayList,LinkedList,Vector
            List<String> list = new Vector<>();
            list.add("熊大");
            list.add("熊二");
            list.add("光头强");
    
            System.out.println("迭代器遍历:");
            // 迭代器iterator遍历
            Iterator<String> iterator = list.iterator();
            while(iterator.hasNext()){
                String next = iterator.next();
                System.out.println(next);
            }
    
            System.out.println("增强for遍历:");
            // 增强for遍历
            for (String o : list) {
                System.out.println(o);
            }
    
            System.out.println("普通for遍历:");
            // 普通for遍历
            for (int i = 0; i < list.size(); i++) {
                System.out.println(list.get(i));
            }
    
            System.out.println("Lambda表达式遍历:");
            // Lambda表达式遍历
            list.forEach(item -> System.out.println(item));
    
            // 或者使用方法引用
            System.out.println("Lambda方法引用遍历:");
            list.forEach(System.out::println);
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39

    # 3. List 排序练习

    import java.util.ArrayList;
    import java.util.List;
    
    public class BookSortDemo {
        public static void main(String[] args) {
            // 创建一个 List 来存储 Book 对象
            List<Book> books = new ArrayList<>();
            books.add(new Book("红楼梦", 36.4f, "曹雪芹"));
            books.add(new Book("水浒传", 19.9f, "施耐庵"));
            books.add(new Book("西游记", 28.8f, "吴承恩"));
    
            // 打印排序前的书籍列表
            System.out.println("排序前:");
            for(Book book : books){
                System.out.println(book);
            }
    
            // 对书籍列表进行排序(按价格从低到高)
            sortBooksByPrice(books);
    
            // 打印排序后的书籍列表
            System.out.println("---- 排序后 ----");
            for(Book book : books){
                System.out.println(book);
            }
        }
    
        // 通过冒泡排序算法对书籍列表按价格进行排序
        public static void sortBooksByPrice(List<Book> books){
            for (int i = 0; i < books.size(); i++) {
                for (int j = 0; j < books.size() - 1 - i; j++) {
                    Book currentBook = books.get(j);
                    Book nextBook = books.get(j + 1);
                    // 如果当前书籍的价格大于下一本书籍的价格,则交换位置
                    if(currentBook.getPrice() > nextBook.getPrice()){
                        books.set(j, nextBook);
                        books.set(j + 1, currentBook);
                    }
                }
            }
        }
    }
    
    // 定义 Book 类
    class Book{
        private String name;
        private float price;
        private String author;
    
        public Book(String name, float price, String author) {
            this.name = name;
            this.price = price;
            this.author = author;
        }
    
        public float getPrice() {
            return price;
        }
    
        @Override
        public String toString() {
            return "书名:" + name + "  价格:" + price + "  作者:" + author;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64

    # 4. ArrayList 使用注意事项

    image-20240102152423695

    • 允许存放任何元素,包括空元素null
    ArrayList list = new ArrayList();
    list.add(null);
    list.add("OK");
    list.add(null);
    System.out.println(list); //[null,OK,null]
    
    1
    2
    3
    4
    5
    • ArrayList 是由数组来实现数据存储的;
    • ArrayList基本等同于 Vector ,除了 ArrayList是线程不安全的,但执行效率高,在多线程的情况下不建议用ArrayList;

    # 5. ArrayList 底层结构

    ArrayList底层使用Object数组实现;当数组容量不够时,创建一个新数组,这个新数组的容量是原数组的1.5倍,然后将原数组中的元素复制到这个新数组中。建议使用时,直接在构造方法中指定数组大小。避免扩容,影响效率。

    • JDK7:当使用无参构造创建列表时,底层默认创建长度是10的Object数组。
    • JDK8:当是用无参构造创建列表时,底层并不会指定数组的容量,第一次添加容量时才默认创建长度为10的数组

    下载 (2)

    下载 (1)

    总结

    • 当使用无参的构造方法创建ArrayList,容量默认值10在第一次插入的时候才会初始化初始容量,而不是在创建的时候就初始化容量。
    • 在插入时,会检测是否真正需要扩容,如果需要,调用grow扩容。
    • 初步预估按照原容量的1.5倍扩容
      • 如果用户所需大小超过预估的1.5倍,则按照用户所需大小扩容。
      • 真正扩容之前检测是否能扩容成功,防止太大导致扩容失败。
    • 使用copyOf进行扩容 。

    # 6. ArrayList 在多线程环境中的线程安全问题

    ArrayLis 在 Java 中是非线程安全的,这意味着在多线程环境下,如果没有适当的同步措施,同时对 ArrayList 进行操作可能会导致不可预期的行为

    1. 并发修改异常(ConcurrentModificationException):
      • 当多个线程同时尝试修改 ArrayList 时,可能会抛出此异常。例如,一个线程正在遍历 ArrayList,而另一个线程同时修改了它(添加、删除或修改元素)。
    2. 数据不一致性:
      • 在没有适当同步的情况下,一个线程对 ArrayList 所做的修改可能不会立即(或根本不会)对其他线程可见。这可能导致不同线程看到 ArrayList 的不同状态。
    3. 数组扩容问题:
      • 当两个或更多线程同时添加元素,触发 ArrayList 扩容时,可能会出现数据丢失或覆盖的问题。因为内部数组的大小需要根据添加的数据量动态调整,而这个过程涉及到数组复制和数据迁移,如果同时发生,可能导致问题。
    4. 索引混乱:
      • 如果多个线程同时对 ArrayList 进行添加或删除操作,可能会导致元素的索引位置出现混乱,因为每个添加或删除操作都可能影响数组中元素的索引。

    为了在多线程环境中安全地使用类似 ArrayList 的数据结构,建议使用线程安全的替代品,如 Vector 或 Collections.synchronizedList(new ArrayList<...>())。另一个选择是使用 java.util.concurrent 包中的并发集合,例如 CopyOnWriteArrayList。在实践中,还可以通过在关键操作周围添加同步块来手动管理线程安全。

    # 7. Vector 底层结构

    image-20240102152315738

    Vector:线程安全的,里面的方法基本都加了synchornized,因此效率很慢;底层使用Object数组存储;当使用无参构造创建时,JDK7和JDK8都默认创建一个长度为10的数组;当容量不够时会按照原始容量的2倍进行扩容。

    image-20240102045421155

    • Vector 底层也是一个对象数组,protected Object[ ] elementData;
    • Vector 是线程同步的,即线程安全,Vector类的操作方法带有synchronized
    • 在开发中,需要线程同步安全时,考虑使用Vector

    # 8. Stack的使用

    什么是栈?(Stack)

    image-20240103023027960

    栈是一种数据结构,是操作受限制的线性表(先进后出),它只能在固定的一端进行插入和删除操作,进行数据插入和删除的一端为栈顶,另一端为栈底,按存储方式分为顺序栈(更好实现)和链式栈。

    压栈: 栈的插入操作叫做进栈/压栈/入栈。入数据在栈顶。

    出栈: 栈的删除操作叫做出栈。出数据也在栈顶。

    栈的使用 (参考博客 (opens new window))

    方法 功能说明
    Stack() 构造一个空栈
    E push(E e) 将e入栈并返回e
    E pop() 将栈顶元素出栈并返回
    E peek() 获取栈顶元素
    int size() 获取栈中有效元素的个数
    boolean empty() 检测栈是否为空

    栈的使用建议使用下面两种方式,不建议使用Stack

    ●顺序栈:Deque接口+实现类ArrayDeque

    // 如果您的栈操作主要是添加和移除元素,且元素数量相对固定或变化不大,那么 ArrayDeque 更合适。
    Deque<Integer> deque = new ArrayDeque<>();//顺序栈
    
    1
    2

    ●链式栈:Deque接口+实现类LinkedList

    // 如果您需要除了栈操作以外的其他链表操作,或者栈中元素数量非常大且频繁变化,LinkedList 更合适。
    Deque<Integer> deque1 = new LinkedList<>();//链式栈
    
    1
    2

    Deque 接口(双端队列)拥有 Stack(栈)中的方法,是因为 Deque 被设计为能够在两端进行元素的插入和移除操作,这使得它非常适合表现栈的行为。

    在栈结构中,元素按照后进先出(LIFO)的顺序被处理,这意味着只有最后一个被添加的元素可以被移除。这种行为可以通过 Deque 的以下方法来实现:

    1. push(E e): 在 Deque 中,这个方法将元素添加到队列的前端,与栈的 push 操作相同。
    2. pop(): 在 Deque 中,这个方法移除并返回队列前端的元素,模拟了栈的 pop 操作。
    3. peek(): 这个方法返回队列前端的元素,但不移除它,与栈的行为一致。

    因此,Deque 接口自然成为实现栈结构的理想选择,同时提供了比传统 Stack 类更丰富和灵活的操作。实际上,Java 官方文档中也推荐使用 Deque 来代替 Stack 类,因为 Stack 类是基于 Vector 实现的,而 Vector 在现代 Java 版本中通常不被推荐使用,主要是因为它是线程同步的,这会在非多线程环境下带来不必要的性能开销。而 ArrayDeque 和 LinkedList 实现了 Deque 接口,提供了更高效、更灵活的栈操作。

    # 9. LinkedList 的使用

    image-20240102152801818

    LinkedList 是一个实现了 List 和 Deque 接口的双向链表,因此它提供了列表的功能,也能作为栈或队列使用。这些方法使 LinkedList 成为一种灵活的数据结构,适合于各种不同的使用场景。

    方法名称 功能描述
    add(E e) 在链表尾部添加指定的元素
    add(int index, E element) 在链表的指定位置插入指定的元素
    addFirst(E e) 在链表头部插入指定的元素
    addLast(E e) 在链表尾部插入指定的元素(与 add(E e) 相同)
    remove() 移除并返回链表头部的元素
    remove(int index) 移除链表中指定位置的元素
    remove(Object o) 移除链表中首次出现的指定元素
    removeFirst() 移除并返回链表的第一个元素
    removeLast() 移除并返回链表的最后一个元素
    get(int index) 返回链表中指定位置的元素
    getFirst() 返回链表的第一个元素
    getLast() 返回链表的最后一个元素
    set(int index, E element) 替换链表中指定位置的元素
    size() 返回链表中的元素个数
    clear() 清空整个链表
    contains(Object o) 判断链表是否包含指定的元素
    isEmpty() 判断链表是否为空

    LinkedList的增删改查案例:

    import java.util.Iterator;
    import java.util.LinkedList;
    
    public class LinkListCRUD {
        public static void main(String[] args) {
            // 创建一个 LinkedList 实例
            LinkedList<Integer> linkedList = new LinkedList<>();
    
            // 增加元素
            linkedList.add(1); // 添加一个元素,此时它既是头节点也是尾节点
            linkedList.add(2); // 添加第二个元素,first 仍然指向第一个节点,但 last 更新为新节点
            linkedList.add(3); // 继续添加元素
            System.out.println("增加元素后: " + linkedList); // 显示列表中的元素
    
            // 删除元素
            linkedList.remove(); // 默认删除第一个元素
            System.out.println("删除元素后: " + linkedList); // 显示删除元素后的列表
    
            // 修改元素
            linkedList.set(1, 999); // 修改第二个元素为 999
            System.out.println("修改元素后: " + linkedList); // 显示修改元素后的列表
    
            // 查询元素
            int element = linkedList.get(1); // 获取链表中第二个位置的元素
            System.out.println("查询到的元素: " + element); // 输出查询到的元素
    
            // 遍历 LinkedList
            System.out.println("LinkedList 遍历:");
            // 使用迭代器遍历
            Iterator<Integer> iterator = linkedList.iterator();
            while (iterator.hasNext()) {
                int nextElement = iterator.next();
                System.out.println(nextElement);
            }
    
            // 使用增强 for 循环遍历
            System.out.println("使用增强 for 循环遍历:");
            for (Integer num : linkedList) {
                System.out.println(num);
            }
    
            // 使用普通 for 循环遍历
            System.out.println("使用普通 for 循环遍历:");
            for (int i = 0; i < linkedList.size(); i++) {
                System.out.println(linkedList.get(i));
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48

    可以自行debug看一下调用方法的实现

    # 10. LinkedList 底层结构

    在这里插入图片描述

    • LinkedList 实现了双向链表和双端队列的特点
    • 可以添加任意元素(元素可以重复),包括null;
    • 线程不安全,没有实现同步
    • LinkedList底层维护了一个双向链表;
    • LinkedList中维护了两个属性first和last分别指向 首节点 和 尾节点;
    • 每个节点(Node对象),里面又维护了prev、next、item三个属性,其中通过prev指向前一个,通过next指向后一个节点,最终完成双向链表;
    • 所以 LinkedList的元素的添加和删除不是通过数组完成的,相对来说效率较高;

    双向链表的模拟:(更多详情可点击此处 (opens new window))

    public class TestLinkedList {
        public static void main(String[] args) {
            // 创建链表的节点
            Node jack = new Node("Jack");
            Node tom = new Node("Tom");
            Node marry = new Node("Marry");
    
            // 将节点连接起来形成双向链表
            jack.next = tom; // Jack 的下一个是 Tom
            tom.prev = jack; // Tom 的前一个是 Jack
    
            tom.next = marry; // Tom 的下一个是 Marry
            marry.prev = tom; // Marry 的前一个是 Tom
    
            Node first = jack; // 双向链表的头节点是 Jack
            Node last = marry; // 双向链表的尾节点是 Marry
    
            // 从头到尾遍历链表
            System.out.println("---- 从头到尾遍历 ----");
            traverseFromHead(first);
    
            // 从尾到头遍历链表
            System.out.println("---- 从尾到头遍历 ----");
            traverseFromTail(last);
    
            // 在 Tom 和 Marry 之间插入一个新节点 Smith
            Node smith = new Node("Smith");
            insertNode(tom, smith); // 在 Tom 后面插入 Smith
    
            // 再次从头到尾遍历链表
            System.out.println("---- 插入 Smith 后从头到尾遍历 ----");
            traverseFromHead(first);
        }
    
        // 遍历链表:从头到尾
        public static void traverseFromHead(Node node) {
            while (node != null) {
                System.out.println(node);
                node = node.next; // 移动到下一个节点
            }
        }
    
        // 遍历链表:从尾到头
        public static void traverseFromTail(Node node) {
            while (node != null) {
                System.out.println(node);
                node = node.prev; // 移动到前一个节点
            }
        }
    
        // 在链表中插入新节点
        public static void insertNode(Node currentNode, Node newNode) {
            // 将新节点链接到当前节点和下一个节点
            newNode.next = currentNode.next;
            newNode.prev = currentNode;
    
            // 如果当前节点的下一个节点不为空,则设置其前一个节点为新节点
            if (currentNode.next != null) {
                currentNode.next.prev = newNode;
            }
            currentNode.next = newNode; // 将当前节点的下一个节点设置为新节点
        }
    }
    
    // 定义一个 Node 类,表示双向链表的节点
    class Node {
        public Object data; // 节点存储的数据
        public Node next;   // 指向下一个节点
        public Node prev;   // 指向前一个节点
    
        public Node(Object data) {
            this.data = data; // 初始化节点数据
        }
    
        @Override
        public String toString() {
            return "Node: " + data; // 输出节点信息
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79

    # 11. ArrayList 和 LinkedList 比较

    由于ArrayList在任意位置插入或删除元素的时候,需要将后续元素整体往前或者往后移动,时间复杂度为O(n),效率比较低,因此ArrayList不适合在插入删除较多的场景下使用,而这些问题链表都可以解决。

    不同点 ArrayList LinkedList
    存储空间上 物理上连续 逻辑上连续,物理上不一定连续
    随机访问 支持O(1) 不支持O(N)
    头插 需要移动元素,效率低O(N) 只需要修改引用的指向O(1)
    插入 空间不够时需要扩容 没有容量的概念
    应用场景 频繁访问+随机存取 任意位置插入+频繁删除

    如何选择 ArrayList 和 LinkedList :

    1. 如果改查的操作较多,选择 ArrayList;
    2. 如果增删的操作较多,选择 LinkedList;
    3. 一般程序中,80%-90%都是查询,因此大部分会使用ArrayList;
    4. 在项目中,灵活选择,可以一个模块用LinkedList,一个模块用ArrayList;

    多线程的情况还是考虑 Vector ,因为它是线程安全的

    编辑此页 (opens new window)
    上次更新: 2024/12/28, 18:32:08
    初识集合
    Set接口

    ← 初识集合 Set接口→

    Theme by Vdoing | Copyright © 2019-2025 程序员scholar
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式