LinkedList源码

news2024/12/28 4:02:38

介绍

  • 基于双向链表实现
  • 线程不安全
  • 插入删除效率较高,但不支持随机查找
public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable

image-20230606072823995

常量&变量

    // 元素数量
    transient int size = 0;

    /**
     * Pointer to first node.
     * Invariant: (first == null && last == null) ||
     *            (first.prev == null && first.item != null)
     *  头节点
     */
    transient Node<E> first;

    /**
     * Pointer to last node.
     * Invariant: (first == null && last == null) ||
     *            (last.next == null && last.item != null)
     *  尾节点
     */
    transient Node<E> last;

LinkedList 的底层数据结构为双向链表,每个节点包含两个引用,prev指向当前节点前一个节点,next指向当前节点后一个节点,可以从头结点遍历到尾结点,也可以从尾结点遍历到头结点。

image-20230606072853944

构造方法

    /**
     * Constructs an empty list.
     * 无参构造 创建一个空集合
     */
    public LinkedList() {
    }

    /**
     * Constructs a list containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     *
     * @param  c the collection whose elements are to be placed into this list
     * @throws NullPointerException if the specified collection is null
     */
    public LinkedList(Collection<? extends E> c) {
        //调用无参,创建一个空集合
        this();
        addAll(c);
    }

内部类

ListItr

ListItr类定义在LinkedList类的内部(作为普通内部类),它实现了ListIterator接口,具有迭代器的功能。

    private class ListItr implements ListIterator<E> {
        //上一次执行next()或previos()方法时的节点
        private Node<E> lastReturned;
        //下一次即将访问的元素(后继节点)
        private Node<E> next;
        //下一次要访问的元素的索引(后继节点的索引)
        private int nextIndex;
        //将修改次数modCount赋给expectedModCount  预期的修改次数  =  实际修改次数
        private int expectedModCount = modCount;

        ListItr(int index) {
            // assert isPositionIndex(index);
            //根据索引获得后继节点
            next = (index == size) ? null : node(index);
            //后继节点的索引
            nextIndex = index;
        }

        //判断是否有下一个元素可访问
        public boolean hasNext() {
            //nextIndex小于size表示仍然还有后继结点,如果大于等于size那么表示要么是尾结点,要么索引越界了
            return nextIndex < size;
        }
        //获取下一个访问的元素
        public E next() {
            checkForComodification();
            //如果没有下一个元素
            if (!hasNext())
                //抛出NoSuchElementException异常
                throw new NoSuchElementException();
            //保存当前遍历的节点
            lastReturned = next;
            //下个节点
            next = next.next;
            //索引加1
            nextIndex++;
            //返回旧next节点的元素
            return lastReturned.item;
        }
        //判断是否有上一个元素可访问
        public boolean hasPrevious() {
            //向前遍历,当索引大于0,表示前驱节点存在
            return nextIndex > 0;
        }
        //获取上一个访问的元素
        public E previous() {
            checkForComodification();
            if (!hasPrevious())
                throw new NoSuchElementException();

            lastReturned = next = (next == null) ? last : next.prev;
            nextIndex--;
            return lastReturned.item;
        }
        //获取下一个访问的元素在线性表中的索引
        public int nextIndex() {
            return nextIndex;
        }
        //获取上一个访问元素在线性表中的索引
        public int previousIndex() {
            return nextIndex - 1;
        }

        /**
         * 使用迭代器进行迭代的时候不能进行调用list.remove()或list.add()删除修改元素,否则会抛出ConcurrentModificationException异常
         * 所以如果要增加或删除元素需要使用迭代器Iterator内部的remove()和add()方法
         */
        //删除元素
        public void remove() {
            checkForComodification();
            if (lastReturned == null)
                throw new IllegalStateException();
            //后继节点
            Node<E> lastNext = lastReturned.next;
            //删除当前节点
            unlink(lastReturned);
            //next 和 上一次遍历的节点 是同一个对象 说明是向前遍历
            if (next == lastReturned)
                next = lastNext;
            else
                nextIndex--;
            //置null 便于回收
            lastReturned = null;
            expectedModCount++;
        }

        public void set(E e) {
            if (lastReturned == null)
                throw new IllegalStateException();
            checkForComodification();
            lastReturned.item = e;
        }
        //添加
        public void add(E e) {
            checkForComodification();
            lastReturned = null;

            if (next == null)
                //当前节点是尾结点,直接在尾部添加
                linkLast(e);
            else
                //插入到next节点前
                linkBefore(e, next);
            nextIndex++;
            expectedModCount++;
        }

        public void forEachRemaining(Consumer<? super E> action) {
            Objects.requireNonNull(action);
            while (modCount == expectedModCount && nextIndex < size) {
                action.accept(next.item);
                lastReturned = next;
                next = next.next;
                nextIndex++;
            }
            checkForComodification();
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

ListItr类不仅可以遍历元素,还可以遍历元素时添加、删除元素

ListItr类定义在LinkedList的内部,每个ListItr对象隐式持有LinkedList对象的引用,该迭代器在遍历时对ListItr对象添加、删除、修改元素,都会影响到LinkedList对象

    public static void main(String[] args) {
        LinkedList<String> list=new LinkedList();
        list.add("aa");
        list.add("bb");

        System.out.println(list);
        ListIterator<String> iterator = list.listIterator();
        while (iterator.hasNext()) {
            String next = iterator.next();
            if (next.equals("aa")) {
                iterator.add("cc");
            }
        }
        System.out.println(list);
        ListIterator<String> iterator2 = list.listIterator();
        while (iterator2.hasNext()) {
            String next = iterator2.next();
            if (next.equals("bb")){
                iterator2.remove();
            }
        }
        System.out.println(list);
        ListIterator<String> iterator3 = list.listIterator();
        while (iterator3.hasNext()) {
            String next = iterator3.next();
            if (next.equals("cc")){
                iterator3.set("dd");
            }
        }
        System.out.println(list);
    }

image-20230606072957431

对集合使用迭代器遍历时,可以使用迭代器内部的remove()或add()方法对集合中元素进行增删操作

注:使用list的remove()或add()方法会报ConcurrentModificationException,list无set(E e)方法

image-20230606073009482

Node

Node类就是LinkedList中元素的包装类,表示LinkedList中的一个一个元素

    private static class Node<E> {
        //元素
        E item;
        //后节点
        Node<E> next;
        //前节点
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

DescendingIterator

为listitter .previous提供降序迭代器的适配器,即从LinkedList的列表末尾开始,逆序遍历进而到达列表头部。

    /**
     * Adapter to provide descending iterators via ListItr.previous
     */
    private class DescendingIterator implements Iterator<E> {
        private final ListItr itr = new ListItr(size());
        public boolean hasNext() {
            return itr.hasPrevious();
        }
        public E next() {
            return itr.previous();
        }
        public void remove() {
            itr.remove();
        }
    }

LLSpliterator

用于并行流的可分割式迭代器

    /** A customized variant of Spliterators.IteratorSpliterator */
    static final class LLSpliterator<E> implements Spliterator<E> {
        static final int BATCH_UNIT = 1 << 10;  // batch array size increment
        static final int MAX_BATCH = 1 << 25;  // max batch array size;
        final LinkedList<E> list; // null OK unless traversed
        Node<E> current;      // current node; null until initialized
        int est;              // size estimate; -1 until first needed
        int expectedModCount; // initialized when est set
        int batch;            // batch size for splits

        LLSpliterator(LinkedList<E> list, int est, int expectedModCount) {
            this.list = list;
            this.est = est;
            this.expectedModCount = expectedModCount;
        }

        final int getEst() {
            int s; // force initialization
            final LinkedList<E> lst;
            if ((s = est) < 0) {
                if ((lst = list) == null)
                    s = est = 0;
                else {
                    expectedModCount = lst.modCount;
                    current = lst.first;
                    s = est = lst.size;
                }
            }
            return s;
        }

        public long estimateSize() { return (long) getEst(); }

        public Spliterator<E> trySplit() {
            Node<E> p;
            int s = getEst();
            if (s > 1 && (p = current) != null) {
                int n = batch + BATCH_UNIT;
                if (n > s)
                    n = s;
                if (n > MAX_BATCH)
                    n = MAX_BATCH;
                Object[] a = new Object[n];
                int j = 0;
                do { a[j++] = p.item; } while ((p = p.next) != null && j < n);
                current = p;
                batch = j;
                est = s - j;
                return Spliterators.spliterator(a, 0, j, Spliterator.ORDERED);
            }
            return null;
        }

        public void forEachRemaining(Consumer<? super E> action) {
            Node<E> p; int n;
            if (action == null) throw new NullPointerException();
            if ((n = getEst()) > 0 && (p = current) != null) {
                current = null;
                est = 0;
                do {
                    E e = p.item;
                    p = p.next;
                    action.accept(e);
                } while (p != null && --n > 0);
            }
            if (list.modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }

        public boolean tryAdvance(Consumer<? super E> action) {
            Node<E> p;
            if (action == null) throw new NullPointerException();
            if (getEst() > 0 && (p = current) != null) {
                --est;
                E e = p.item;
                current = p.next;
                action.accept(e);
                if (list.modCount != expectedModCount)
                    throw new ConcurrentModificationException();
                return true;
            }
            return false;
        }

        public int characteristics() {
            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
        }
    }

常用方法

add

image-20230606073137530

    /**
     * Appends the specified element to the end of this list.
     *
     * <p>This method is equivalent to {@link #addLast}.
     *
     * @param e element to be appended to this list
     * @return {@code true} (as specified by {@link Collection#add})
     * 插入尾部,并返回true 与addLast方法等价
     */
    public boolean add(E e) {
        linkLast(e);
        return true;
    }
    
    /**
     * Inserts the specified element at the specified position in this list.
     * Shifts the element currently at that position (if any) and any
     * subsequent elements to the right (adds one to their indices).
     *
     * @param index index at which the specified element is to be inserted
     * @param element element to be inserted
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public void add(int index, E element) {
        checkPositionIndex(index);

        if (index == size)
            //尾部添加
            linkLast(element);
        else
            //在索引对应的节点前插入element
            linkBefore(element, node(index));
    }

checkPositionIndex

    private void checkPositionIndex(int index) {
        //不符合条件 报错
        if (!isPositionIndex(index))
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
    
    
    /**
     * Tells if the argument is the index of a valid position for an
     * iterator or an add operation.
     * 参数index是否符合条件
     */
    private boolean isPositionIndex(int index) {
        return index >= 0 && index <= size;
    }

linkLast

在尾部添加元素

    /**
     * Links e as last element.
     */
    void linkLast(E e) {
        // 获取尾部元素
        final Node<E> l = last;
        // 实例化一个新的节点,前一个节点为l,当前节点为传入的添加节点,下一个节点为null
        final Node<E> newNode = new Node<>(l, e, null);
        // 将尾部节点进行更新(添加上新加入的节点)
        last = newNode;
        // 当尾部节点为空时,头节点即为新添加的节点
        if (l == null)
            first = newNode;
        // 否则,尾部节点的下一个为新添加的节点
        else
            l.next = newNode;
        // 元素数量+1
        size++;
        // 修改次数+1
        modCount++;
    }

linkBefore

    /**
     * Inserts element e before non-null Node succ.
     * 在非空节点succ前,插入元素 e
     */
    void linkBefore(E e, Node<E> succ) {
        // assert succ != null;
        //原index对应节点succ的前驱节点
        final Node<E> pred = succ.prev;
        //创建新的节点  pred <-- e --> succ
        final Node<E> newNode = new Node<>(pred, e, succ);
        //succ的前驱节点为newNode   pred <-- e <--> succ 
        succ.prev = newNode;
        if (pred == null)
            // e <--> succ 
            first = newNode;
        else
            //pred的后继节点为newNode  pred <--> e <--> succ 
            pred.next = newNode;
        size++;
        modCount++;
    }

addAll

image-20230606073253283

     /**
     * Appends all of the elements in the specified collection to the end of
     * this list, in the order that they are returned by the specified
     * collection's iterator.  The behavior of this operation is undefined if
     * the specified collection is modified while the operation is in
     * progress.  (Note that this will occur if the specified collection is
     * this list, and it's nonempty.)
     *
     * @param c collection containing elements to be added to this list
     * @return {@code true} if this list changed as a result of the call
     * @throws NullPointerException if the specified collection is null
     * 将指定集合中的所有元素追加到此列表的末尾。
     */
    public boolean addAll(Collection<? extends E> c) {
        return addAll(size, c);
    }
    
    /**
     * Inserts all of the elements in the specified collection into this
     * list, starting at the specified position.  Shifts the element
     * currently at that position (if any) and any subsequent elements to
     * the right (increases their indices).  The new elements will appear
     * in the list in the order that they are returned by the
     * specified collection's iterator.
     *
     * @param index index at which to insert the first element
     *              from the specified collection
     * @param c collection containing elements to be added to this list
     * @return {@code true} if this list changed as a result of the call
     * @throws IndexOutOfBoundsException {@inheritDoc}
     * @throws NullPointerException if the specified collection is null
     * 将指定集合(Collection c)中的所有元素插入到此列表中,从指定的位置(index)开始。
     */
    public boolean addAll(int index, Collection<? extends E> c) {
        //判断索引是否越界
        checkPositionIndex(index);
        //通过指定集合获得数组
        Object[] a = c.toArray();
        //数组的长度
        int numNew = a.length;
        //长度为空,直接返回失败
        if (numNew == 0)
            return false;
        //节点的前驱节点、后继节点
        Node<E> pred, succ;
        //直接从尾部添加该集合
        if (index == size) {
            //后继节点为null,前驱节点为尾节点
            succ = null;
            pred = last;
        } else {
            //指定索引对应的节点为后继节点,节点的前节点为前驱节点
            succ = node(index);
            pred = succ.prev;
        }
        //遍历数组
        for (Object o : a) {
            //类型转换
            @SuppressWarnings("unchecked") E e = (E) o;
            //构造新节点       pred  <-- e
            Node<E> newNode = new Node<>(pred, e, null);
            if (pred == null)
                //新节点为头节点  e
                first = newNode;
            else
                //前驱节点的下一个节点为新节点  pred <--> e
                pred.next = newNode;
            //为了下个循环,将新节点置为前驱节点
            pred = newNode;
        }
        //如果后继节点为null(尾部插入的情况),前驱节点就是尾结点
        if (succ == null) {
            // pred <--> e
            last = pred;
        } else {
            //前驱节点的后节点为后继节点   pred <--> e --> succ
            pred.next = succ;
            //后继节点的前节点为前驱节点   pred <--> e <--> succ
            succ.prev = pred;
        }

        size += numNew;
        modCount++;
        return true;
    }

remove(int index)

image-20230606073315312

    /**
     * Removes the element at the specified position in this list.  Shifts any
     * subsequent elements to the left (subtracts one from their indices).
     * Returns the element that was removed from the list.
     *
     * @param index the index of the element to be removed
     * @return the element previously at the specified position
     * @throws IndexOutOfBoundsException {@inheritDoc}
     * 删除指定下标的元素
     */
    public E remove(int index) {
        // 检测下标是否越界
        checkElementIndex(index);
        // 调用unlink删除元素
        return unlink(node(index));
    }
    
    
    
     /**
     * Unlinks non-null node x.
     */
    E unlink(Node<E> x) {
        // assert x != null;
        // 获取当前元素
        final E element = x.item;
        // 获取下一个节点
        final Node<E> next = x.next;
        // 获取上一个节点
        final Node<E> prev = x.prev;
        // 当上一个节点为null时,将当前节点的下一个节点设置为头节点
        if (prev == null) {
            first = next;
        // 不为null时,将上一个节点的下一个节点设置为当前节点的下一个节点(跳过当前元素),然后将当前节点的前一个节点设置为null,断开连接
        } else {
            prev.next = next;
            x.prev = null;
        }
        // 当下一个节点为null时,将尾节点设置为上一个节点
        if (next == null) {
            last = prev;
        // 否则将下一个节点的前一个节点设置为前一个节点,并且将当前节点的下一个节点设置为null,断开连接
        } else {
            next.prev = prev;
            x.next = null;
        }
        // 设置当前元素为null
        x.item = null;
        // 元素数量-1
        size--;
        // 修改次数+1
        modCount++;
        // 返回当前元素
        return element;
    }

remove()

    /**
     * Retrieves and removes the head (first element) of this list.
     *
     * @return the head of this list
     * @throws NoSuchElementException if this list is empty
     * @since 1.5
     * 删除头节点
     */
    public E remove() {
        // 直接调用removeFirst,删除头节点
        return removeFirst();
    }


   /**
     * Removes and returns the first element from this list.
     *
     * @return the first element from this list
     * @throws NoSuchElementException if this list is empty
     */
    public E removeFirst() {
        // 获取头节点
        final Node<E> f = first;
        // 头节点为null时直接抛出
        if (f == null)
            throw new NoSuchElementException();
        // 调用删除头节点的方法
        return unlinkFirst(f);
    }
    
    
    /**
     * Unlinks non-null first node f.
     */
    private E unlinkFirst(Node<E> f) {
        // assert f == first && f != null;
        // 获取当前元素
        final E element = f.item;
        // 获取下一个节点
        final Node<E> next = f.next;
        // 将当前元素设置为null
        f.item = null;
        // 将下一个节点设置为null
        f.next = null; // help GC
        // 因为为删除头节点,所以将头节点设置为下一个节点(跳过当前头节点)
        first = next;
        // 当下一个节点为null时,尾节点设置为null
        if (next == null)
            last = null;
        // 否则下一个节点的前一个节点设置为null,断开与之前头节点的连接
        else
            next.prev = null;
        // 元素数量-1
        size--;
        // 操作次数+1
        modCount++;
        // 返回删除的元素
        return element;
    }

element


    /**
     * Retrieves, but does not remove, the head (first element) of this list.
     *
     * @return the head of this list
     * @throws NoSuchElementException if this list is empty
     * @since 1.5
     * 获取头节点但不删除,链表为null抛出异常
     */
    public E element() {
        // 直接调用getFirst获取头节点返回
        return getFirst();
    }
    
    
     /**
     * Returns the first element in this list.
     *
     * @return the first element in this list
     * @throws NoSuchElementException if this list is empty
     * 获取头节点
     */
    public E getFirst() {
        // 获取头节点
        final Node<E> f = first;
        // 当头节点为null时抛出异常
        if (f == null)
            throw new NoSuchElementException();
        // 否则返回头节点的值
        return f.item;
    }

offer

    /**
     * Adds the specified element as the tail (last element) of this list.
     *
     * @param e the element to add
     * @return {@code true} (as specified by {@link Queue#offer})
     * @since 1.5
     * 尾部添加指定元素
     */
    public boolean offer(E e) {
        //直接调用add方法
        return add(e);
    }

poll

    /**
     * Retrieves and removes the head (first element) of this list.
     *
     * @return the head of this list, or {@code null} if this list is empty
     * @since 1.5
     * 获取头节点并删除
     */
    public E poll() {
        // 获取头节点
        final Node<E> f = first;
        // 当为null时直接返回null,否则调用unlinkFirst
        return (f == null) ? null : unlinkFirst(f);
    }

peek

    /**
     * Retrieves, but does not remove, the head (first element) of this list.
     *
     * @return the head of this list, or {@code null} if this list is empty
     * @since 1.5
     * 获取头节点,但不删除,链表为null则返回null
     */
    public E peek() {
        // 获取头节点
        final Node<E> f = first;
        // 头节点为null直接返回null,否则返回元素
        return (f == null) ? null : f.item;
    }

push

    /**
     * Pushes an element onto the stack represented by this list.  In other
     * words, inserts the element at the front of this list.
     *
     * <p>This method is equivalent to {@link #addFirst}.
     *
     * @param e the element to push
     * @since 1.6
     * 压入元素
     */
    public void push(E e) {
        // 直接调用addFirst方法,addFirst调用了linkFirst
        addFirst(e);
    }
    
     /**
     * Inserts the specified element at the beginning of this list.
     *
     * @param e the element to add
     */
    public void addFirst(E e) {
        linkFirst(e);
    }
    
     /**
     * Links e as first element.
     * 头部添加元素
     */
    private void linkFirst(E e) {
        // 获取头节点
        final Node<E> f = first;
        // 实例化一个新的节点,上一个节点为null,当前节点为传入元素,下个节点为头节点
        final Node<E> newNode = new Node<>(null, e, f);
        // 将新的节点赋值给头节点
        first = newNode;
        // 当头节点为空时,尾节点也直接设置为新节点
        if (f == null)
            last = newNode;
        // 否则头节点的前一个节点为新节点
        else
            f.prev = newNode;
        // 元素数量+1
        size++;
        // 修改次数+1
        modCount++;
    }

pop

    /**
     * Pops an element from the stack represented by this list.  In other
     * words, removes and returns the first element of this list.
     *
     * <p>This method is equivalent to {@link #removeFirst()}.
     *
     * @return the element at the front of this list (which is the top
     *         of the stack represented by this list)
     * @throws NoSuchElementException if this list is empty
     * @since 1.6
     * 弹出元素
     */
    public E pop() {
        // 直接调用removeFirst方法,removeFirst进行判空,空抛出异常,然后调用unlinkFirst
        return removeFirst();
    }
    
    /**
     * Removes and returns the first element from this list.
     *
     * @return the first element from this list
     * @throws NoSuchElementException if this list is empty
     */
    public E removeFirst() {
        // 获取头节点
        final Node<E> f = first;
        // 头节点为null时直接抛出
        if (f == null)
            throw new NoSuchElementException();
        // 调用删除头节点的方法
        return unlinkFirst(f);
    }

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

秒杀抢购案例,基于 Redis 实现

目录 1、关于全局唯一 ID 生成器 1.1 需要满足的特性 1.2 代码实现 1.3 其他的唯一 ID 生成策略 2、实现秒杀下单 2.1 超卖问题的产生 2.2 超卖问题的分析与解决 2.21 悲观锁与乐观锁 2.22 乐观锁中的两种常用方案 ▶️version 版本控制方案 ▶️CAS方案 2…

AIGC资源整理

这几个月我深入研究了AIGC&#xff0c;同时业翻阅和搜集了大量的资料&#xff0c;累计也花了1000去买了各种信息源 为了方便我的好朋友们学习&#xff0c;我将那些优质的免费信息源和工具&#xff0c;都进行了整理。 如果你也想学习AIGC、ChatGPT相关的内容&#xff0c;那么我很…

深入探索:在std::thread中创建并管理QEventLoop的全面指南

深入探索&#xff1a;在std::thread中创建并管理QEventLoop的全面指南 1. 前言&#xff1a;理解QEventLoop和std::thread的基本概念1.1 QEventLoop的基本概念和工作原理1.2 std::thread的基本概念和工作原理1.3 QTimer的基本概念和工作原理 2. 在std::thread中创建QEventLoop&a…

chatgpt赋能python:Python字大小调整:优化SEO效果

Python字大小调整&#xff1a;优化SEO效果 随着互联网信息技术的不断发展&#xff0c;SEO&#xff08;搜索引擎优化&#xff09;已经成为互联网领域的重要一环。在进行网站制作和信息发布时&#xff0c;如何提高网站的曝光度和排名成为了关键问题。针对Python编程爱好者和从业…

chatgpt赋能python:Python定义分段函数的完整指南

Python定义分段函数的完整指南 什么是分段函数&#xff1f; 当我们在解决线性和非线性方程时&#xff0c;分段函数是一个非常重要的数学工具。 分段函数可以是由不同的函数组成&#xff0c;它们在定义域中的不同部分内具有不同的公式或条款。换句话说&#xff0c;一个分段函数…

PyGame游戏编程

Python非常受欢迎的一个原因是它的应用领域非常广泛&#xff0c;其中就包括游戏开发。而是用Python进行游戏开发的首选模块就是PyGame。 1. 初识Pygame PyGame是跨平台Python模块&#xff0c;专为电子游戏设计&#xff0c;包含图像、声音等&#xff0c;创建在SDL&#xff08;…

量子前沿 | 单光子,为什么是量子科技的“源头”?

光子盒研究院出品 前言&#xff1a;基础研究是科技创新的基石。鉴于此&#xff0c;光子盒增设“量子前沿”全新栏目&#xff0c;旨在介绍量子科技的一系列基础技术、相关进展及现状前景。 我们对量子信息的兴趣出现在20世纪90年代和21世纪。在该领域的发展过程中&#xff0c;单…

文件上传与PDF报表入门

文件上传与PDF报表入门 理解DataURL的基本使用&#xff0c;实现DataURL的文件上传完成基于七牛云的文件上传 理解 JasperReport生命周期 独立完成 JasperReport的入门案例 图片上传 需求分析 如图所示&#xff0c;实现员工照片上传功能 Data URL DataURL概述 所谓DataURL是指&q…

chatgpt赋能python:Python定义未知长度数组

Python定义未知长度数组 Python是一种受欢迎的编程语言&#xff0c;广泛用于数据分析&#xff0c;人工智能&#xff0c;WEB开发和其他领域。其中一个非常方便的特性是它提供了定义未知长度数组的选项。 在本文中&#xff0c;我们将介绍如何使用Python定义未知长度数组&#x…

四、纹理显示图片

第一部分纹理基础 1)基础概念 在 OpenGLES 开发中&#xff0c;纹理除了用于装饰物体表面&#xff0c;还可以用来作为存储数据的容器。 纹理映射&#xff1a;纹理映射就是通过为图元的顶点坐标指定恰当的纹理坐标&#xff0c;通过纹理坐标在纹理图中选定特定的纹理区域&#…

汽车电子AUTOSAR之Event

上文AUTOSAR基础篇之DTC中提到event是故障监控的基本单元&#xff0c;本文将从event的使能条件&#xff08;Enable Condition&#xff09;、上报方式、去抖动策略&#xff08;Debouncing Strategy&#xff09;、优先级&#xff08;Priority&#xff09;、Displacement、依赖关系…

解决SpringBoot配置文件项目重启出现乱码的情况

近日&#xff0c;在创建了SpringBoot项目后往配置文件中写了相关的系统配置&#xff0c;并且在上面加了中文注释&#xff0c;但是在重启项目或开机重启后遇到了注释乱码的情况&#xff0c;查询了各种相关资料&#xff0c;得以解决 发现问题 首先看到我在这个application.prope…

Golang每日一练(leetDay0089) 滑动窗口最大值、中位数

目录 239. 滑动窗口最大值 Sliding Window Maximum &#x1f31f;&#x1f31f;&#x1f31f; 480. 滑动窗口中位数 Sliding Window Median &#x1f31f;&#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Rust每日一练 专栏 Golang每日一练 专…

chatgpt赋能python:Python安装FBProphet:绝佳的时间序列预测工具

Python安装FBProphet&#xff1a;绝佳的时间序列预测工具 随着时间序列数据应用场景的不断增加&#xff0c;越来越多的数据科学家和工程师开始使用FBProphet进行时间序列预测。FBProphet是由Facebook开发的一种开源预测工具&#xff0c;它使用先进的统计方法进行时间序列分析&…

案例40:基于Springboot疫苗预约系统开题报告设计

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

Day_41顺序查找与折半查找

目录 一. 顺序查找和折半查找的实现 1. 顺序查找 1.1 一般线性表的顺序查找 1.2 有序表的顺序查找 2. 折半查找 二. 代码实现 1. 内部节点 2. 类的构造函数 3. 顺序查找 4. 折半查找 三. 代码展示 四. 数据测试 五. 小结 一. 顺序查找和折半查找的实现 1. 顺序查找…

chatgpt赋能python:Python定义错误:什么是Python定义错误

Python定义错误&#xff1a;什么是Python定义错误 Python是一种强大的编程语言&#xff0c;被广泛用于各种领域&#xff0c;例如Web开发&#xff0c;数据分析&#xff0c;机器学习等。然而&#xff0c;即使是最有经验的Python开发人员也会犯一些常见的错误&#xff0c;其中之一…

在线教育机构的视频如何做防下载和防盗录?

在线教育平台付费课程、企业内训的培训课程&#xff0c;这类视频课程内容是如何做防下载和防盗录的&#xff1f; 1.AI隐形溯源水印 这个功能能够将水印隐藏在视频中&#xff0c;不会影响观看体验&#xff0c;但却能够帮助企业很好的视频版权保护。更重要的是&#xff0c;对于盗…

【ArcGIS Pro二次开发】(34):从字符串中提取中文、英文、数字与特殊符号

这是一个基于字段计算的工具。 有时候我们会遇到一些混杂着各种中文、英文、数字、特殊符号的文字&#xff0c;这个工具的目的是从这些复杂文字中提取出想要的特定文字。 比如说从CAD测绘图中可以读取到类似【混3】、【砖2】的文字&#xff0c;如果想要从中提取出层数或结构&…

chatgpt赋能python:Python宏变量——简介

Python宏变量——简介 Python是一种高级编程语言&#xff0c;具有易学易用、简洁清晰等优点。但我们在编写代码的时候&#xff0c;有时需要用到常量或者宏定义&#xff0c;这就需要用到宏变量。在Python中&#xff0c;宏变量是一种常见的编程方法&#xff0c;本文将详细介绍Py…