[java数据结构] ArrayList和LinkedList介绍与使用

目录

(一) 线性表

(二) ArrayList

1. ArrayList的介绍

2. ArrayList的常见方法和使用

3. ArrayList的遍历

4. ArrayList的模拟实现

5. ArrayList的优缺点

(三) LinkedList

1. LinkedList的介绍

2. LinkedList的常见方法和使用

3. LinkedList的遍历

4. LinkedList的模拟实现

5. LinkedList的优缺点

(四) ArrayList和LinkedList的区别

总结


(一) 线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结 构,常见的线性表:顺序表、链表、栈、队列...

线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物 理上存储时,通常以数组和链式结构的形式存储。如下图:

(二) ArrayList

1. ArrayList的介绍

ArrayList是Java中的一个动态数组类, 即顺序表,可以动态地增加或减少数组的大小。它是一个可以动态改变大小的数组,可以根据需要自动地增加或减少数组的大小。ArrayList可以存储任意类型的对象,包括基本数据类型和引用类型, 它实现了List接口, 具体框架图如下:

[说明]

1. ArrayList实现了RandomAccess接口,表明ArrayList支持随机访问

2. ArrayList实现了Cloneable接口,表明ArrayList是可以clone的

3. ArrayList实现了Serializable接口,表明ArrayList是支持序列化的

4. 和Vector不同,ArrayList不是线程安全的,在单线程下可以使用,在多线程中可以选择Vector或者 CopyOnWriteArrayList

5. ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表

2. ArrayList的常见方法和使用

使用ArrayList可以方便地进行元素的添加、删除和查找操作,是Java中常用的集合类之一。

ArrayList类包含许多常用的方法,以下是一些常见的方法和它们的使用:

常见的方法

  • boolean add(E e):向ArrayList中尾插 一个元素e。
  • void add(int index, E element): 将 e 插入到 index 位置
  • E remove(int index):移除指定索引位置的元素。
  • E get(int index):获取指定索引位置的元素。
  • size():获取ArrayList的大小
  • E set(int index, E element): 将下标 index 位置元素设置为 element
  • void clear(): 清空
  • boolean contains(Object o):判断ArrayList是否包含指定的元素。
  • int indexOf(Object o):返回指定元素在ArrayList中第一次出现的索引。
  • int lastIndexOf(Object o): 返回指定元素在ArrayList中最后一次出现的索引。

  使用:

import java.util.ArrayList;

public class ArrayListExample {
   public static void main(String[] args) {
            // 创建一个ArrayList
            ArrayList<String> list = new ArrayList<>();

            // 向ArrayList中尾插元素
            list.add("apple");
            list.add("banana");
            list.add("orange");

            // 将元素插入到指定索引位置
            list.add(1, "grape");

            //遍历ArrayList
            System.out.print("打印1: ");
            for (String ret: list) {
                System.out.print(ret+" ");
            }
            System.out.println();

            // 移除指定索引位置的元素
            list.remove(2);

            //遍历ArrayList
            System.out.print("打印2: ");
            for (String ret: list) {
                System.out.print(ret+" ");
            }
            System.out.println();

            // 获取指定索引位置的元素
            String fruit = list.get(0);
            System.out.println("索引0处的水果: " + fruit);

            // 获取ArrayList的大小
            int size = list.size();
            System.out.println("ArrayList的大小: " + size);

            // 将指定索引位置的元素设置为新元素
            list.set(2, "cherry");

            // 判断ArrayList是否包含指定的元素
            boolean contains = list.contains("apple");
            System.out.println("是否包含'apple': " + contains);

            // 返回指定元素在ArrayList中第一次出现的索引
            int index = list.indexOf("banana");
            System.out.println("'banana'第一次出现的索引: " + index);

            // 返回指定元素在ArrayList中最后一次出现的索引
            int lastIndex = list.lastIndexOf("apple");
            System.out.println("'apple'最后一次出现的索引: " + lastIndex);

            // 清空ArrayList
            list.clear();

            //遍历ArrayList
            System.out.print("打印3: ");
            for (String ret: list) {
                System.out.print(ret+" ");
            }
            System.out.println();
        }
}

3. ArrayList的遍历

ArrayList可以使用三种方式遍历:for循环+下标、foreach、使用迭代器, 代码如下:

import java.util.ArrayList;

public class ArrayListExample {
    public static void main(String[] args) {
        // 创建一个ArrayList对象,它是List接口的实现类
        List<String> list = new ArrayList<>();

        // 将指定的元素添加到列表的末尾
        list.add("apple");
        list.add("banana");
        list.add("cherry");

        //for循环+下标
        System.out.print("for循环+下标: ");
        for (int i = 0; i < list.size(); i++) {
            System.out.print(list.get(i)+" ");
        }
        System.out.println();

        //foreach遍历
        System.out.print("foreach遍历: ");
        for (String ret : list) {
            System.out.print(ret+" ");
        }
        System.out.println();

        //使用迭代器
        System.out.print("迭代器遍历: ");
        Iterator<String> iter = list.iterator();
        while (iter.hasNext()){
            String ret = iter.next();
            System.out.print(ret+" ");
        }
        System.out.println();
    }
}

4. ArrayList的模拟实现
package List;

import java.util.Arrays;

// 自定义的ArrayList类
public class MyArrayList {
    public int[] arr; // 用于存储元素的数组
    public int size; // 记录当前数组中的元素个数
    public static final int Max = 10; // 默认最大容量

    // 构造方法,初始化数组
    public MyArrayList() {
        this.arr = new int[10];
    }

    // 打印元素
    public void display() {
        for (int i = 0; i < this.size; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
    }

    // 增加元素
    public void add(int data) {
        if (isFull()) {
            arr = Arrays.copyOf(arr, arr.length * 2); // 如果数组已满,扩容为原来的两倍
        }
        arr[size++] = data;
    }

    // 判断数组是否已满
    public boolean isFull() {
        if (size == Max) {
            return true;
        }
        return false;
    }

    // 检查插入位置是否合法
    private void checkAddPos(int pos) {
        if (pos < 0 || pos > size) {
            throw new PosIndexNotLegalException("pos位置不合法");
        }
    }

    // 在指定位置插入元素
    public void add(int pos, int data) {
        try {
            checkAddPos(pos);
            if (isFull()) {
                arr = Arrays.copyOf(arr, 2 * arr.length); // 如果数组已满,扩容为原来的两倍
            }
            for (int i = size - 1; i >= pos; i--) {
                arr[i + 1] = arr[i]; // 元素后移
            }
            arr[pos] = data; // 在指定位置插入新元素
            size++;
        } catch (PosIndexNotLegalException e) {
            e.printStackTrace();
        }
    }

    // 判断是否包含某个元素
    public boolean contains(int toFind) {
        for (int i = 0; i < size; i++) {
            if (arr[i] == toFind) {
                return true;
            }
        }
        return false;
    }

    // 查找某个元素对应的位置
    public int indexOf(int toFind) {
        for (int i = 0; i < size; i++) {
            if (arr[i] == toFind) {
                return i;
            }
        }
        return -1; // 如果找不到返回-1
    }

    // 获取指定位置的元素
    public int get(int pos) {
        checkAddPos(pos);
        return arr[pos];
    }

    // 给指定位置的元素赋值
    public void set(int pos, int value) {
        checkAddPos(pos);
        arr[pos] = value;
    }

    // 删除第一次出现的指定元素
    public void remove(int toRemove) {
        int index = indexOf(toRemove);
        if (index == -1) {
            System.out.println("没有你要删除的数字!");
            return;
        }
        for (int j = index; j < size; j++) {
            arr[j] = arr[j + 1]; // 元素前移
        }
        size--;
    }

    // 获取顺序表长度
    public int size() {
        int ret = size;
        return ret;
    }

    // 清空顺序表
    public void clear() {
        size = 0; // 将元素个数置为0,实现清空操作
    }
}
5. ArrayList的优缺点

优点:

  1. 随机访问:由于 ArrayList 使用数组来存储元素,可以通过索引快速访问元素,性能较好,时间复杂度为 O(1)。
  2. 灵活的大小:ArrayList 的大小可以动态调整,不需要预先指定数组大小,可以根据需求动态增加或减少元素。

缺点:

  1. 插入和删除效率低:在 ArrayList 中间或开头插入或删除元素时,需要移动后续元素,时间复杂度为 O(n),性能较差。
  2. 内存开销:ArrayList 在动态扩容时需要重新分配内存并拷贝元素,可能会产生额外的内存开销。

总结

ArrayList 适合需要频繁随机访问元素、对大小变化较为频繁的场景,但在大量插入和删除操作时性能较差。

(三) LinkedList

1. LinkedList的介绍

在前面ArrayList我们知道,当在ArrayList任意位置插入或者删除元素时,就需要将后序元素整体往前或者往后搬移,时间复杂度为O(n),效率比较低,因此ArrayList不适合做任意位置插入和删除比较多的场景。因此:java 集合中又引入了LinkedList,即链表结构。

LinkedList 是 Java 中的一个无头双向链表。实现,实现了 List 和 Deque 接口,LinkedList 内部是使用无头双向循环链表。表来存储元素,每个节点包含对前一个节点和后一个节点的引用。LinkedList 支持在任意位置进行高效的插入和删除操作,时间复杂度为 O(1)。无头双向链表结构图:

双向链表的每个节点都有 3 个属性:

  1. data : 实际存放的内容;

  2. prev : 指向前一节点的指针;

  3. next : 指向后一节点的指针。

实际中链表的结构非常多样,单向或者双向, 带头或者不带头, 循环或者非循环

虽然有这么多的链表的结构,但是我们重点掌握两种:

无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如 哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。

无头双向链表:在Java的集合框架库中LinkedList底层实现就是无头双向循环链表。

2. LinkedList的常见方法和使用

LinkedList 类实现了 List 接口,因此它包含了 List 接口定义的所有方法,例如 add、remove、get、set 等。此外,LinkedList 还包含了一些特有的方法,如 addFirst、addLast等,用于在链表的开头或结尾进行操作

常见方法

  • boolean add(E e): 在链表的末尾添加元素。
  • void addFirst(E e): 在链表的开头添加元素。
  • void addLast(E e): 在链表的末尾添加元素。
  • E get(int index): 获取指定位置的元素。
  • E set(int index, E element) 将下标 index 位置元素设置为 element
  • boolean remove(): 删除并返回链表的第一个元素。
  • String removeFirst(): 删除并返回链表的第一个元素。
  • String removeLast(): 删除并返回链表的最后一个元素。
  • int size(): 获取链表的大小。
  • boolean contains(Object o): 判断链表是否包含指定的元素。
  • int indexOf(Object o): 返回指定元素在链表中第一次出现的位置。
  • int lastIndexOf(Object o) 返回最后一个 o 的下标
  • void clear() 清空
import java.util.LinkedList;
class Main {
    public static void main(String[] args) {
        LinkedList<String> linkedList = new LinkedList<>();

        // 添加元素
        linkedList.add("A");
        System.out.println("添加 'A' 后的链表: " + linkedList);
        linkedList.addFirst("B");
        System.out.println("在链表开头添加 'B' 后的链表: " + linkedList);
        linkedList.addLast("C");
        System.out.println("在链表末尾添加 'C' 后的链表: " + linkedList);

        // 获取元素
        String elementAtIndex1 = linkedList.get(1);
        System.out.println("索引为 1 的元素: " + elementAtIndex1);

        // 设置元素
        linkedList.set(0, "D");
        System.out.println("将索引为 0 的元素设置为 'D' 后的链表: " + linkedList);

        // 删除元素
        String removedElement = linkedList.remove();
        System.out.println("删除的元素: " + removedElement);
        String removedFirst = linkedList.removeFirst();
        System.out.println("删除的第一个元素: " + removedFirst);
        String removedLast = linkedList.removeLast();
        System.out.println("删除的最后一个元素: " + removedLast);

        // 获取链表大小
        int size = linkedList.size();
        System.out.println("链表的大小: " + size);

        // 判断是否包含元素
        boolean contains = linkedList.contains("A");
        System.out.println("链表是否包含 'A': " + contains);

        // 获取元素的索引
        int index = linkedList.indexOf("B");
        System.out.println("'B' 在链表中的索引: " + index);

        // 清空链表
        linkedList.clear();
        System.out.println("清空链表后的结果: " + linkedList);
    }
}

3. LinkedList的遍历

可以使用foreach、迭代器来访问链表中的每个元素。 代码如下:

import java.util.LinkedList;
import java.util.Iterator;

public class Main {
    public static void main(String[] args) {
        LinkedList<String> linkedList = new LinkedList<>();
        linkedList.add("A");
        linkedList.add("B");
        linkedList.add("C");

        // 使用迭代器遍历
        Iterator<String> iterator = linkedList.iterator();
        while (iterator.hasNext()) {
            String element = iterator.next();
            System.out.println("Element: " + element);
        }
        
        // 使用foreach遍历
        for (String element : linkedList) {
            System.out.println("Element: " + element);
        }
    }
}

4. LinkedList的模拟实现

无头单向非循环链表代码如下:

public class SingleLinkedList {

    // 定义节点类
    static class Node {
        public int val;
        public Node next;

        public Node(int val) {
            this.val = val;
        }
    }

    public Node head; // 链表头节点

    // 头插法
    public void addFirst(int data) {
        Node node = new Node(data);
        if (head == null) {
            head = node;
        } else {
            node.next = head;
            head = node;
        }
    }

    // 尾插法
    public void addLast(int data) {
        Node node = new Node(data);
        if (head == null) {
            head = node;
            return;
        } else {
            Node cur = head;
            while (cur.next != null) {
                cur = cur.next;
            }
            cur.next = node;
        }
    }

    // 任意位置插入,第一个数据节点为0号下标
    public void addIndex(int index, int data) {
        checkIndex(index);
        if (index == 0) {
            addFirst(data);
            return;
        }
        if (index == size()) {
            addLast(data);
            return;
        }
        Node node = new Node(data);
        // 找到要插入的前一个位置
        Node cur = prevIndex(index - 1);
        node.next = cur.next;
        cur.next = node;
    }

    private void checkIndex(int index) {
        if (index < 0 || index > size()) {
            throw new IndexNotLegalException("index位置不合法!");
        }
    }

    private Node prevIndex(int index) {
        Node cur = head;
        while (index > 0) {
            cur = cur.next;
            index--;
        }
        return cur;
    }

    // 查找是否包含关键字key是否在单链表当中
    public boolean contains(int key) {
        if (head == null) return false;
        Node cur = head;
        while (cur != null) {
            if (cur.val == key) {
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

    // 删除第一次出现关键字为key的节点
    public void remove(int key) {
        if (head == null) return;
        if (head.val == key) {
            head = head.next;
            return;
        }
        Node cur = head.next;
        Node prev = head;
        while (cur != null) {
            if (cur.val == key) {
                prev.next = cur.next;
                return;
            } else {
                prev = cur;
                cur = cur.next;
            }
        }
    }

    // 删除所有值为key的节点
    public void removeAllKey(int key) {
        if (head == null) return;
        Node cur = head.next;
        Node prev = head;
        while (cur != null) {
            if (cur.val == key) {
                prev.next = cur.next;
                cur = cur.next;
            } else {
                prev = cur;
                cur = cur.next;
            }
        }
        if (head.val == key) {
            head = head.next;
        }
    }

    // 得到单链表的长度
    public int size() {
        Node cur = head;
        int count = 0;
        while (cur != null) {
            count++;
            cur = cur.next;
        }
        return count;
    }

    // 打印链表
    public void display() {
        Node cur = head;
        while (cur != null) {
            System.out.print(cur.val + " ");
            cur = cur.next;
        }
        System.out.println();
    }

    // 清空链表
    public void clear() {
        if (head == null) return;
        Node cur = head;
        while (cur != null) {
            Node curNext = cur.next;
            cur.next = null;
            cur = curNext;
        }
        head = null;
    }
    

    // 一道练习题  -- 单链表的逆置
    // 递归.单链表的逆置
    public Node reverseList(Node head) {
        if (head == null) {
            return head;
        }
        if (head.next == null) {
            return head;
        }
        Node newHead = reverseList(head.next);
        head.next.next = head;
        // 要注意的是的下一个节点必须指向∅。如果忽略了这一点,链表中会产生环,所以每反转一个,要把原来下个结点置null;
        head.next = null;

        return newHead;

    }

    // 非递归.单链表的逆置
    public Node reverseList1() {
        Node cur = head;
        Node prev = null;
        while (cur != null) {
            Node nextCur = cur.next;
            cur.next = prev;
            prev = cur;
            cur = nextCur;
        }
        return prev;
    }

}

无头双向循环链表的实现如下:

package MyLinkedList;

// 无头双向链表实现
public class MyTwoLinkedList {

    // 定义节点类
    static class ListNode {
        public int val;
        public ListNode next; //指向下一个节点
        public ListNode prev; //指向上一个节点

        public ListNode(int val) {
            this.val = val;
        }
    }

    public ListNode head; // 表示存储当前链表的头节点的引用
    public ListNode last; // 尾节点

    // 打印链表
    public void display() {
        ListNode cur = head;
        while (cur != null) {
            System.out.print(cur.val + " ");
            cur = cur.next;
        }
        System.out.println();
    }

    // 头插法
    public void addFirst(int data) {
        ListNode node = new ListNode(data);
        if (head == null) {
            head = node;
            last = node;
        } else {
            node.next = head;
            head.prev = node;
            head = node;
        }
    }

    // 尾插法
    public void addLast(int data) {
        ListNode node = new ListNode(data);
        if (head == null) {
            head = node;
            last = node;
            return;
        }
        last.next = node;
        node.prev = last;
        last = last.next;
    }

    // 根据索引查找节点
    private ListNode findIndex(int index) {
        ListNode cur = head;
        while (index > 0) {
            index--;
            cur = cur.next;
        }
        return cur;
    }

    // 任意位置插入,第一个数据节点为0号下标
    public void addIndex(int index, int data) {
        ListNode node = new ListNode(data);
        if (index < 0 || index > this.size()) {
            throw new IndexNotLegalException("双向链表index不合法!");
        }
        if (index == 0) {
            addFirst(data);
            return;
        }
        if (index == size()) {
            addLast(data);
            return;
        }
        // 获取到当前的index位置的节点的地址
        ListNode cur = findIndex(index);
        node.next = cur;
        cur.prev.next = node;
        node.prev = cur.prev;
        cur.prev = node;
    }

    // 查找是否包含关键字key是否在单链表当中
    public boolean contains(int key) {
        ListNode cur = head;
        while (cur != null) {
            if (cur.val == key) {
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

    // 删除第一次出现关键字为key的节点
    public void remove(int key) {
        ListNode cur = head;
        while (cur != null) {
            if (cur.val == key) {
                if (cur == head) {
                    head = head.next;
                    if (head != null) { // 防止只有一个节点
                        head.prev = null;
                    }
                } else {
                    cur.prev.next = cur.next;
                    // 删除的不是尾巴节点
                    if (last.val != key) {
                        cur.next.prev = cur.prev;
                    } else {
                        last = cur.prev;
                    }
                }
                return;
            }
            cur = cur.next;
        }
    }

    // 删除所有值为key的节点
    public void removeAllKey(int key) {
        ListNode cur = head;
        while (cur != null) {
            if (cur.val == key) {
                if (cur == head) {
                    head = head.next;
                    if (head != null) { // 防止只有一个节点
                        head.prev = null;
                    }
                } else {
                    cur.prev.next = cur.next;
                    // 删除的不是尾巴节点
                    if (cur.next != null) {
                        cur.next.prev = cur.prev;
                    } else {
                        // 删除的是尾结点
                        last = cur.prev;
                    }
                }
            }
            cur = cur.next;
        }
    }

    // 得到单链表的长度
    public int size() {
        ListNode cur = head;
        int len = 0;
        while (cur != null) {
            len++;
            cur = cur.next;
        }
        return len;
    }

    // 清空链表
    public void clear() {
        ListNode cur = head;
        while (cur != null) {
            ListNode nextCur = cur.next;
            cur.next = null;
            cur.prev = null;
            cur = nextCur;
        }
        head = null;
        last = null;
    }
}
5. LinkedList的优缺点

优点:

  1. 插入和删除操作效率高:在链表中插入和删除元素的效率很高,只需要修改节点的指针,不需要移动其他元素。
  2. 灵活性:链表可以动态地分配内存空间,可以根据需要动态地添加或删除节点。

缺点:

  1. 随机访问效率低:链表中要想访问第k个元素,需要从头节点开始顺序遍历,时间复杂度为O(n)。
  2. 占用空间多:链表中每个节点都需要额外的空间来存储指针,占用的空间比数组大。
  3. 不支持随机访问:链表不支持通过下标直接访问元素,只能通过指针进行遍历访问。

总结

LinkedList 适合需要频繁插入和删除操作、对随机访问要求不高的场景,但在需要频繁随机访问元素时性能较差。

(四) ArrayList和LinkedList的区别

ArrayList 和 LinkedList 都是 Java 中的集合类,用于存储一组元素。它们之间的主要区别在于底层的数据结构和对元素的访问方式。

ArrayList 是基于数组实现的动态数组,它提供了快速的随机访问和遍历。在 ArrayList 中,每个元素都有一个索引,可以通过索引快速访问元素,但在插入和删除元素时需要移动其他元素,因此插入和删除操作的效率较低。

LinkedList 是基于链表实现的双向链表,它提供了快速的插入和删除操作。在 LinkedList 中,每个元素都包含对前一个元素和后一个元素的引用,因此插入和删除操作的效率比较高。但是在访问元素时需要从头或尾开始遍历,因此随机访问的效率较低。

总结

如果需要频繁进行插入和删除操作,可以选择 LinkedList;如果需要频繁进行随机访问和遍历操作,可以选择 ArrayList。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/325596.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

上门按摩APP系统公众号H5搭建能为客户带来哪些便捷。

大家好&#xff01;今天我来给大家介绍一下上门按摩系统H5搭建。你有没有曾经因为工作疲劳、肌肉酸痛而感到身体不适&#xff1f;或者是因为长时间坐在电脑前&#xff0c;感觉脖子和肩膀快要僵硬了&#xff1f;如果你有这样的困扰&#xff0c;那么上门按摩系统公众号绝对是你的…

黑马程序员——javase基础——day01——Java入门IDEA基础语法

目录&#xff1a; Java入门 Java简介JDK的下载和安装第一个程序常见问题常用DOS命令Path环境变量IDEA IDEA概述和安装IDEA中HelloWorldIDEA中基本配置&注释IDEA中常用快捷键IDEA中模块操作基础语法 字面量数据类型变量变量的案例 手机信息描述疫情防控信息采集表变量的注意…

linux云服务器 如何将数据盘挂载到系统盘上面?

先认识认识下面几个常用命令 lsblk 命令&#xff1a;查看设备列表&#xff0c;也就是能看到系统盘和数据盘一般为&#xff1a;vda&#xff08;系统盘&#xff09;、vdb&#xff08;数据盘&#xff09;等等 lsblk"ls" 是 "list" 的缩写&#xff1a; lsblk…

29K star!关于shell,你需要的都在这里

Awesome 是GitHub上一个神奇的单词&#xff0c;搜索Awesome可以发现非常多精彩的汇总性项目&#xff0c;涉及到各种方面&#xff0c;而且star都非常多。 今天我们推荐的开源项目帮你整理了玩转shell所需的一切&#xff0c;本项目目前在GitHub已超过29K Star&#xff0c;它就是…

Go后端开发 -- 数组 slice map range

Go后端开发 – 数组 && slice && map && range 文章目录 Go后端开发 -- 数组 && slice && map && range一、数组1.数组的声明和初始化2.数组的传参 二、slice切片1.slice的定义和初始化2.len()和cap()函数3.空切片4.切片截取5…

新书速览|数据科学技术:文本分析和知识图谱

百分科技书解数据科学&#xff0c;文本分析、知识图谱详解&#xff0c;实战案例呈现&#xff0c;助你深入理解技术原理&#xff0c;行业应用启发&#xff0c;助力创新发展。 本书内容 数据科学的关键技术包括数据存储计算、数据治理、结构化数据分析、语音分析、视觉分析、文本…

牛客周赛 Round 5 解题报告 | 珂学家 | 思维场

前言 剑&#xff0c;和茶一样&#xff0c;只有细细品味&#xff0c;才能理解它的风雅。 整体评价 挺难的一场比赛&#xff0c;C题差点点错科技树(想着用Dsu On Tree), D题开始上难度&#xff0c;但是只是分析其实就是一个区间求交集的脑筋急转弯&#xff0c;E题盲猜是菊花图。…

Ansys Zemax | 如何使用光学制造全息图修正像差

附件下载 联系工作人员获取附件 本文介绍了利用光学全息图降低单透镜像差的方法。在描述了表示全息图构造光束的两个 ZMX 文件之后&#xff0c;本文演示了如何在重现文件中设置 OFH。然后解释了如何轻松地从重现文件中访问任何结构造光束变量&#xff0c;以实现衍射受限单透镜…

【分享】我发布的视频教程列表

为了方便大家的观看&#xff0c;我将已经发布的视频列表进行了整理&#xff0c;大家可以按照自己习惯的网站进行访问。 My Key Published Videos Series | video_published 同时&#xff0c;这个列表会随时更新&#xff0c;大家可以在进度条上了解上传的比例。 欢迎大家提出…

动态路由协议

文章目录 一、动态路由协议二、管理距离&#xff08;Administrative Distance&#xff09;三、静态路由四、环回接口五、缺省路由&#xff08;默认路由&#xff09;六、动态路由协议&#xff0c;RIP距离矢量路由协议RIP解决环路问题的机制RIP配置RIP案例1RIPV2的路由汇总 一、动…

枚举类状态做批量查询以及范围查询优化

文章目录 前言问题目标现存的状态思路三大状态状态计算(1)状态计算(2) 工具类示例 前言 往往项目中有一些类似于订单类的数据中有很多状态相关的流转操作&#xff0c;这些时候有可能因为某些业务逻辑要对状态进行范围查询或者多值匹配、排除之类的操作。 问题 在进行数据查询…

SpringBoot集成Mybatis Plus【附源码】

1. 背景 作为SpringBoot集成中间件其中的一篇文章吧&#xff0c;既然打算出这么一个系列了&#xff0c;争取做到虽小却全&#xff0c;又精又美的一个系列吧。 Mybatis Plus作为我入行以来&#xff0c;一直接触的一个中间件&#xff0c;也必须集成一下。同时也为初学者带来一些…

大数据传输慢的真正原因与解决方案

随着企业数据不断增长&#xff0c;大数据传输已成为一项至关重要的任务。然而&#xff0c;许多企业在处理大数据传输时频繁遭遇传输速度慢的问题。本文将深入探讨大数据传输速度慢的根本原因&#xff0c;并提供一些切实有效的解决方案。 大数据传输在企业中的重要性不言而喻&am…

旧衣回收小程序搭建:降低企业成本,提高回收效率!

在人们环保意识提升下&#xff0c;旧衣回收行业受到了大众的关注&#xff0c;同时旧衣回收具有门槛低、利润大的优势。在我国&#xff0c;回收行业不仅帮助普通人就业获利&#xff0c;还对环保做出了较大贡献。因此&#xff0c;旧衣回收行业成为了当下的热门商业模式&#xff0…

行为树(Behavior Trees)

行为树&#xff08;Behavior Trees&#xff09;是一种在游戏开发中广泛使用的AI设计模式&#xff0c;主要用于描述AI的行为和决策过程&#xff0c;实现更加智能和自然的游戏AI。它由多个节点组成&#xff0c;每个节点代表一个行为或决策&#xff0c;按照特定的方式连接在一起&a…

智能助手的巅峰对决:ChatGPT对阵文心一言

在人工智能的世界里&#xff0c;ChatGPT与文心一言都是备受瞩目的明星产品。它们凭借先进的技术和强大的性能&#xff0c;吸引了大量用户的关注。但究竟哪一个在智能回复、语言准确性、知识库丰富度等方面更胜一筹呢&#xff1f;下面就让我们一探究竟。 首先来谈谈智能回复能力…

数据结构学习 jz41 数据流中的中位数

关键词&#xff1a;排序 大顶堆 小顶堆 题目&#xff1a;数据流中的中位数 这道题我没有想到用两个堆来做。 思路&#xff1a; 关键&#xff1a;维护两个堆&#xff0c;一个大顶堆一个小顶堆。 大顶堆&#xff1a;装较小的那一半的数&#xff0c;它的顶就是较小那一半数的最…

淘宝搜索引擎API接口关键字搜索商品列表获取商品详情价格评论销量API

item_search-按关键字搜索淘宝商品 公共参数 查看API完整文档 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地址中&#xff09;[item_search,item_get,it…

如何在企业微信开发者中心使用内网穿透工具回调本地接口服务

文章目录 1. Windows安装Cpolar2. 创建Cpolar域名3. 创建企业微信应用4. 定义回调本地接口5. 回调和可信域名接口校验6. 设置固定Cpolar域名7. 使用固定域名校验 企业微信开发者在应用的开发测试阶段&#xff0c;应用服务通常是部署在开发环境&#xff0c;在有数据回调的开发场…

Mysql root 密码重置详解

文章目录 1 概述1.1 前言1.2 mysql 版本查询 2 windows 操作系统2.1 mysql 8 及以上版本2.1.1 关闭 mysql 服务2.1.2 通过无认证方式启动 mysql2.1.3 新开窗口&#xff0c;登录 mysql&#xff0c;重置密码 1 概述 1.1 前言 不同的操作系统&#xff08;如&#xff1a;windows、…