Java 集合框架:Java 中的优先级队列 PriorityQueue 的实现

大家好,我是栗筝i,这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 018 篇文章,在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验,并希望进一步完善自己对整个 Java 技术体系来充实自己的技术栈的同学。与此同时,本专栏的所有文章,也都会准备充足的代码示例和完善的知识点梳理,因此也十分适合零基础的小白和要准备工作面试的同学学习。当然,我也会在必要的时候进行相关技术深度的技术解读,相信即使是拥有多年 Java 开发经验的从业者和大佬们也会有所收获并找到乐趣。

在许多应用程序中,数据的优先级排序对于实现高效的数据处理和任务调度至关重要。Java 中的 PriorityQueue 是一种基于堆的数据结构,广泛用于需要优先级排序的场景。与传统的队列不同,优先级队列可以确保在队列中的元素按照其优先级顺序进行处理,而不是按照插入顺序。本文将深入探讨 PriorityQueue 的实现,包括其基本概念、底层数据结构、各种操作的实现细节,并展示一些实际应用场景和简单用例,帮助你更好地理解和使用这一强大的数据结构。


文章目录

      • 1、PriorityQueue 概述
        • 1.1、优先级队列 介绍
        • 1.2、堆排序与最小堆
      • 2、PriorityQueue 底层实现
        • 2.1、PriorityQueue 数据结构
        • 2.2、插入操作
        • 2.3、删除操作
        • 2.4、搜索操作
      • 3、PriorityQueue 的使用
        • 3.1、PriorityQueue 的使用场景
        • 3.2、PriorityQueue 的简单用例


1、PriorityQueue 概述

1.1、优先级队列 介绍

PriorityQueue 在 Java 中是一种基于堆(Heap)数据结构实现的优先级队列。堆是一种特殊的完全二叉树,分为最小堆和最大堆。

  • 在最小堆中,每个节点的值都小于或等于其子节点的值;
  • 在最大堆中,每个节点的值都大于或等于其子节点的值。

Java 的 PriorityQueue 使用最小堆实现,因此队列头部总是优先级最高(值最小)的元素。

1.2、堆排序与最小堆

堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树(树的所有级别都被完全填充,除了最低级别的节点从尽可能左侧填充之外)。

大根堆的要求是每个节点的值都不大于其父节点的值,即 A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。

最小堆是一棵完全二叉树,非叶子结点的值不大于左孩子和右孩子的值。

image-20240721170628400


2、PriorityQueue 底层实现

2.1、PriorityQueue 数据结构

在 Java 中 PriorityQueue 用数组来表示堆,i 结点的父结点下标就为 (i – 1) / 2。它的左右子结点下标分别为 2 * i + 12 * i + 2。如第 0 个结点左右子结点下标分别为 12

public class PriorityQueue<E> extends AbstractQueue<E> implements java.io.Serializable {// 省略其他方法和实现细节...// 默认初始容量为 11private static final int DEFAULT_INITIAL_CAPACITY = 11;/*** 优先级队列,使用平衡二叉堆表示:* queue[n] 的两个子节点为 queue[2*n+1] 和 queue[2*(n+1)]。* 优先级队列按 comparator 排序,若 comparator 为 null,则按元素的自然顺序排序:* 对堆中每个节点 n 及其每个后代 d,n <= d。最小值元素位于 queue[0]。*/transient Object[] queue; // 非私有以简化嵌套类访问/*** 优先级队列中的元素数量*/private int size = 0;/*** 比较器,若为 null 则使用元素的自然顺序*/private final Comparator<? super E> comparator;/*** 优先级队列被结构性修改的次数。详见 AbstractList。*/transient int modCount = 0; // 非私有以简化嵌套类访问/*** 创建默认初始容量为 11,按自然顺序排序的优先级队列。*/public PriorityQueue() {this(DEFAULT_INITIAL_CAPACITY, null);}/*** 创建指定初始容量,按自然顺序排序的优先级队列。** @param initialCapacity 优先级队列的初始容量* @throws IllegalArgumentException 若 initialCapacity 小于 1*/public PriorityQueue(int initialCapacity) {this(initialCapacity, null);}/*** 创建默认初始容量,按指定比较器排序的优先级队列。** @param comparator 用于排序的比较器。若为 null,则使用元素的自然顺序。* @since 1.8*/public PriorityQueue(Comparator<? super E> comparator) {this(DEFAULT_INITIAL_CAPACITY, comparator);}/*** 创建指定初始容量,按指定比较器排序的优先级队列。** @param initialCapacity 优先级队列的初始容量* @param comparator 用于排序的比较器。若为 null,则使用元素的自然顺序。* @throws IllegalArgumentException 若 initialCapacity 小于 1*/public PriorityQueue(int initialCapacity, Comparator<? super E> comparator) {if (initialCapacity < 1) // 如果初始容量小于1则抛出异常throw new IllegalArgumentException();this.queue = new Object[initialCapacity]; // 初始化队列数组this.comparator = comparator; // 设置比较器}/*** 创建包含指定集合元素的优先级队列。* 若指定集合是 SortedSet 或其他 PriorityQueue 实例,则优先级队列按相同顺序排序。* 否则,按元素的自然顺序排序。** @param c 要放入此优先级队列的集合* @throws ClassCastException 若集合元素不能根据优先级队列的排序规则相互比较* @throws NullPointerException 若集合或其中的任何元素为 null*/@SuppressWarnings("unchecked")public PriorityQueue(Collection<? extends E> c) {if (c instanceof SortedSet<?>) {SortedSet<? extends E> ss = (SortedSet<? extends E>) c;this.comparator = (Comparator<? super E>) ss.comparator();initElementsFromCollection(ss); // 从集合中初始化元素} else if (c instanceof PriorityQueue<?>) {PriorityQueue<? extends E> pq = (PriorityQueue<? extends E>) c;this.comparator = (Comparator<? super E>) pq.comparator();initFromPriorityQueue(pq); // 从优先级队列中初始化} else {this.comparator = null;initFromCollection(c); // 从一般集合中初始化}}/*** 创建包含指定优先级队列元素的优先级队列。按相同顺序排序。** @param c 要放入此优先级队列的优先级队列* @throws ClassCastException 若元素不能根据 c 的排序规则相互比较* @throws NullPointerException 若优先级队列或其任何元素为 null*/@SuppressWarnings("unchecked")public PriorityQueue(PriorityQueue<? extends E> c) {this.comparator = (Comparator<? super E>) c.comparator();initFromPriorityQueue(c); // 从优先级队列中初始化}/*** 创建包含指定排序集元素的优先级队列。按相同顺序排序。** @param c 要放入此优先级队列的排序集* @throws ClassCastException 若排序集元素不能根据排序集的排序规则相互比较* @throws NullPointerException 若排序集或其任何元素为 null*/@SuppressWarnings("unchecked")public PriorityQueue(SortedSet<? extends E> c) {this.comparator = (Comparator<? super E>) c.comparator();initElementsFromCollection(c); // 从排序集中初始化元素}// 省略其他方法和实现细节...
}

从这部分源码可以看出 PriorityQueue 使用数组实现一个平衡二叉堆,并提供了多种构造方法以便根据不同的需求初始化优先级队列

2.2、插入操作

插入操作(addoffer):插入新元素时,PriorityQueue 会将其添加到数组的末尾,然后进行上浮(percolate up)操作以维护堆的有序性:

  1. 将新元素添加到堆的末尾。
  2. 比较新元素与其父节点的值,如果新元素的值小于父节点的值,则交换它们的位置。
  3. 重复步骤 2,直到新元素到达合适的位置,满足堆的性质。
public class PriorityQueue<E> extends AbstractQueue<E> implements java.io.Serializable {// 省略其他方法和实现细节.../*** 将指定元素插入到优先级队列中。** @return {@code true} (如 {@link Collection#add} 所指定)* @throws ClassCastException 如果指定元素无法根据优先级队列的排序规则与当前队列中的元素进行比较* @throws NullPointerException 如果指定元素为 null*/public boolean add(E e) {return offer(e); // 调用 offer 方法插入元素}/*** 将指定元素插入到优先级队列中。** @return {@code true} (如 {@link Queue#offer} 所指定)* @throws ClassCastException 如果指定元素无法根据优先级队列的排序规则与当前队列中的元素进行比较* @throws NullPointerException 如果指定元素为 null*/public boolean offer(E e) {if (e == null)throw new NullPointerException(); // 若元素为 null,抛出空指针异常modCount++; // 修改次数增加int i = size; // 当前队列大小if (i >= queue.length)grow(i + 1); // 若当前大小已达数组容量上限,扩展数组容量size = i + 1; // 队列大小增加if (i == 0)queue[0] = e; // 若队列为空,直接将元素放在根节点elsesiftUp(i, e); // 否则执行上滤操作,将元素放入适当位置return true;}/*** 上滤操作,将元素插入到适当的位置。** @param k 要插入的位置索引* @param x 要插入的元素*/private void siftUp(int k, E x) {if (comparator != null)siftUpUsingComparator(k, x); // 使用比较器进行上滤elsesiftUpComparable(k, x); // 使用自然排序进行上滤}/*** 使用自然排序进行上滤操作。** @param k 要插入的位置索引* @param x 要插入的元素*/@SuppressWarnings("unchecked")private void siftUpComparable(int k, E x) {Comparable<? super E> key = (Comparable<? super E>) x; // 将元素转换为 Comparablewhile (k > 0) {int parent = (k - 1) >>> 1; // 计算父节点索引Object e = queue[parent]; // 获取父节点元素if (key.compareTo((E) e) >= 0)break; // 如果插入元素大于等于父节点元素,则终止上滤queue[k] = e; // 将父节点元素移到当前位置k = parent; // 更新当前位置为父节点位置}queue[k] = key; // 将插入元素放到最终位置}/*** 使用比较器进行上滤操作。** @param k 要插入的位置索引* @param x 要插入的元素*/@SuppressWarnings("unchecked")private void siftUpUsingComparator(int k, E x) {while (k > 0) {int parent = (k - 1) >>> 1; // 计算父节点索引Object e = queue[parent]; // 获取父节点元素if (comparator.compare(x, (E) e) >= 0)break; // 如果插入元素大于等于父节点元素,则终止上滤queue[k] = e; // 将父节点元素移到当前位置k = parent; // 更新当前位置为父节点位置}queue[k] = x; // 将插入元素放到最终位置}/*** 扩展优先级队列的容量,确保其至少能够容纳指定的最小容量。** @param minCapacity 所需的最小容量*/private void grow(int minCapacity) {int oldCapacity = queue.length; // 旧的容量// 若旧容量小于 64,则新容量为旧容量的两倍加上 2;否则,新容量增加 50%int newCapacity = oldCapacity + ((oldCapacity < 64) ?(oldCapacity + 2) :(oldCapacity >> 1));// 防止溢出的代码if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity); // 若新容量超出最大数组大小,则计算巨大容量queue = Arrays.copyOf(queue, newCapacity); // 复制数组并扩展容量}/*** 计算巨大的容量大小。** @param minCapacity 所需的最小容量* @return 合适的巨大容量大小*/private static int hugeCapacity(int minCapacity) {if (minCapacity < 0) // 溢出检查throw new OutOfMemoryError(); // 如果最小容量为负数,则抛出内存不足错误return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE : // 若最小容量超过最大数组大小,则返回 Integer 的最大值MAX_ARRAY_SIZE; // 否则,返回最大数组大小}// 省略其他方法和实现细节...
}

其中:

  1. PriorityQueue 中的 add 方法实际上调用 offer 方法将指定元素插入到优先级队列中。offer 方法首先检查元素是否为 null,然后增加 modCount 以记录修改次数。如果当前队列大小已达到数组容量上限,则调用 grow 方法扩展数组容量。之后,增加队列大小,并根据当前队列是否为空决定将元素放在根节点还是调用 siftUp 方法将元素插入到适当位置;
  2. PriorityQueue 中的 grow 方法用于扩展队列的容量,当队列容量不足以容纳新元素时,会根据当前容量进行扩展。扩展规则是:如果当前容量小于 64,则新容量为旧容量的两倍加二;否则,新容量为旧容量的 1.5 倍。如果计算出的新容量超过了最大数组大小 MAX_ARRAY_SIZE,则调用 hugeCapacity 方法来处理,确保不会溢出,并返回合适的新容量。在 hugeCapacity 方法中,如果所需容量大于最大数组大小 MAX_ARRAY_SIZE,则返回 Integer.MAX_VALUE,否则返回 MAX_ARRAY_SIZE
  3. PriorityQueue 中的 siftUp 方法用于在插入元素时维护堆的有序性。该方法根据是否存在比较器 comparator,调用不同的上滤操作:siftUpComparable 使用元素的自然排序,siftUpUsingComparator 使用提供的比较器。上滤过程中,通过不断比较新插入元素与其父节点元素,决定是否交换位置,直到找到合适的位置,以保证最小堆性质。
2.3、删除操作

删除堆顶元素时,PriorityQueue 会将堆尾元素移动到堆顶,然后进行下沉(percolate down)操作以维护堆的有序性:

  1. 将堆尾元素移动到堆顶,删除原堆顶元素。
  2. 比较新堆顶元素与其子节点的值,将其与值较小的子节点交换位置。
  3. 重复步骤 2,直到新堆顶元素到达合适的位置,满足堆的性质。
public class PriorityQueue<E> extends AbstractQueue<E> implements java.io.Serializable {// 省略其他方法和实现细节...// 从优先级队列中移除并返回堆顶元素@SuppressWarnings("unchecked")public E poll() {if (size == 0)return null; // 如果队列为空,返回 nullint s = --size; // 获取当前队列的最后一个元素的位置,并将大小减1modCount++; // 记录结构修改次数E result = (E) queue[0]; // 记录并返回堆顶元素E x = (E) queue[s]; // 取出新的堆尾元素(将要移动到堆顶的位置)queue[s] = null; // 清空堆尾位置if (s != 0)siftDown(0, x); // 将堆尾元素下滤到正确的位置return result; // 返回移除的堆顶元素}// 从队列中移除指定元素/*** 从队列中移除单个指定的元素(如果存在)。具体地说,* 移除元素 {@code e},如果队列中存在一个或多个这样的元素。* 如果队列因该操作而发生变化,则返回 {@code true}。** @param o 要从队列中移除的元素* @return 如果队列因该操作而发生变化,则返回 {@code true}*/public boolean remove(Object o) {int i = indexOf(o); // 查找元素在队列中的位置if (i == -1)return false; // 如果元素不存在,则返回 falseelse {removeAt(i); // 移除元素并维持堆的性质return true; // 返回 true,表示队列发生了变化}}// 查找指定元素在队列中的位置private int indexOf(Object o) {if (o != null) {for (int i = 0; i < size; i++)if (o.equals(queue[i]))return i; // 找到元素,返回其位置}return -1; // 元素不存在,返回 -1}// 移除队列中指定位置的元素/*** 移除队列中第 i 个元素。* 该方法会保持堆的结构,并且可能会对元素进行交换。* 返回值用于维护迭代器的正确性。** @param i 要移除的元素的位置* @return 被移除的元素(如果元素在最后一个位置被移除,则返回 null)*/@SuppressWarnings("unchecked")private E removeAt(int i) {// assert i >= 0 && i < size;modCount++; // 记录结构修改次数int s = --size; // 更新队列大小if (s == i) // 如果移除的是最后一个元素queue[i] = null; // 直接清空该位置else {E moved = (E) queue[s]; // 取出最后一个元素(将用来填补移除元素的位置)queue[s] = null; // 清空原位置siftDown(i, moved); // 下滤元素以维持堆性质if (queue[i] == moved) { // 如果下滤操作未改变元素位置siftUp(i, moved); // 上滤元素以维持堆性质if (queue[i] != moved)return moved; // 返回已移动的元素}}return null; // 如果没有元素被移动,则返回 null}// 将元素 x 插入到位置 k,并维持堆的结构private void siftDown(int k, E x) {if (comparator != null)siftDownUsingComparator(k, x); // 使用比较器进行下滤elsesiftDownComparable(k, x); // 使用元素的自然顺序进行下滤}// 使用自然顺序下滤元素@SuppressWarnings("unchecked")private void siftDownComparable(int k, E x) {Comparable<? super E> key = (Comparable<? super E>)x; // 转换元素为 Comparableint half = size >>> 1; // 计算非叶子节点的数量while (k < half) { // 遍历非叶子节点int child = (k << 1) + 1; // 假设左子节点最小Object c = queue[child];int right = child + 1;// 如果右子节点存在且小于左子节点if (right < size &&((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)c = queue[child = right]; // 选择右子节点// 如果当前元素不小于子节点if (key.compareTo((E) c) <= 0)break; // 下滤结束queue[k] = c; // 交换当前元素与子节点k = child; // 更新当前元素的位置}queue[k] = key; // 将元素放入正确的位置}// 使用比较器下滤元素@SuppressWarnings("unchecked")private void siftDownUsingComparator(int k, E x) {int half = size >>> 1; // 计算非叶子节点的数量while (k < half) { // 遍历非叶子节点int child = (k << 1) + 1; // 假设左子节点最小Object c = queue[child];int right = child + 1;// 如果右子节点存在且小于左子节点if (right < size &&comparator.compare((E) c, (E) queue[right]) > 0)c = queue[child = right]; // 选择右子节点// 如果当前元素不小于子节点if (comparator.compare(x, (E) c) <= 0)break; // 下滤结束queue[k] = c; // 交换当前元素与子节点k = child; // 更新当前元素的位置}queue[k] = x; // 将元素放入正确的位置}  // 省略其他方法和实现细节...
}

其中:

  • poll() 方法: 从堆中移除并返回堆顶元素。将堆尾元素移到堆顶位置,然后通过下滤操作恢复堆的结构;
  • remove(Object o) 方法: 从队列中移除指定的元素。如果元素存在,则移除并维护堆的性质;如果元素不存在,则返回 false
  • indexOf(Object o) 方法: 查找指定元素在队列中的位置。如果找到,返回元素的位置;否则返回 `-1;
  • removeAt(int i) 方法: 移除队列中指定位置的元素。将队列最后一个元素移到移除位置,然后通过下滤和上滤操作维持堆的结构;
  • siftDown(int k, E x) 方法: 将元素 x 从位置 k 下滤到正确的位置,以保持堆的性质。根据是否使用比较器选择不同的下滤方法;
  • siftDownComparable(int k, E x) 方法: 使用元素的自然顺序下滤元素 x
  • siftDownUsingComparator(int k, E x) 方法: 使用比较器下滤元素 x
2.4、搜索操作

搜索性能:二叉排序树是为了实现动态查找而涉及的数据结构,它是面向查找操作的,在二叉排序树中查找一个节点的平均时间复杂度是 O(logn);在堆中搜索并不是第一优先级,堆是为了实现排序而实现的一种数据结构,它不是面向查找操作的,因为在堆中查找一个节点需要进行遍历,其平均时间复杂度是 O(n)

/*** 检查优先队列中是否包含指定的元素。** @param o 要检查的元素* @return 如果优先队列中包含指定的元素,则返回 {@code true};否则返回 {@code false}*/
public boolean contains(Object o) {// 通过调用 indexOf 方法查找元素的位置,如果 indexOf 返回 -1,说明元素不存在return indexOf(o) != -1;
}/*** 查找指定元素在优先队列中的索引位置。* 如果元素存在,返回其在队列中的位置;否则返回 -1。** @param o 要查找的元素* @return 如果元素存在,返回其在队列中的索引位置;否则返回 -1*/
private int indexOf(Object o) {// 如果待查找的元素不为 nullif (o != null) {// 遍历队列中的所有元素for (int i = 0; i < size; i++)// 如果找到元素,返回其索引位置if (o.equals(queue[i]))return i;}// 如果元素未找到或元素为 null,返回 -1return -1;
}

3、PriorityQueue 的使用

3.1、PriorityQueue 的使用场景

PriorityQueue 的使用场景包括任务调度、‌数据排序、‌任务优先级管理、‌数据压缩、‌图搜索算法、‌操作系统调度、‌网络数据包处理、‌事件驱动系统等。‌

  • 任务调度:‌PriorityQueue 可以用于实现任务调度,‌根据任务的优先级来确定执行顺序。‌这对于提高系统的稳定性和效率非常有帮助;
  • 数据排序:‌PriorityQueue 也可以用于对数据进行排序,‌通过将需要排序的数据加入队列,‌然后按照数据的优先级顺序依次输出,‌从而提高程序的性能;
  • 任务优先级管理:‌PriorityQueue 适用于管理具有优先级关系的任务,‌例如,‌可以将紧急的任务设置为高优先级,‌不紧急的任务设置为低优先级。‌通过将任务加入优先级队列,‌可以实现任务的优先级管理,‌提高系统的响应速;
  • 数据压缩:‌在哈夫曼编码等压缩算法中,‌可以使用优先队列来实现频率统计和编码的过程;
  • 图搜索算法:‌在最短路径算法(‌如 Dijkstra 算法、‌A* 算法)‌中,‌可以使用优先队列来存储待访问的节点,‌并根据节点的优先级进行遍历;
  • 操作系统调度:‌在操作系统中,‌可以使用优先队列来实现进程调度,‌根据进程的优先级来确定执行顺序;
  • 网络数据包处理:‌在路由器等网络设备中,‌可以使用优先队列来处理网络数据包,‌根据数据包的优先级来确定传输顺序;
  • 事件驱动系统:‌在事件驱动系统中,‌可以使用优先队列来管理事件队列,‌根据事件的优先级来确定处理顺序;

这些场景展示了 PriorityQueue 在提高系统效率、‌优化资源分配、‌以及增强系统响应速度方面的广泛应用。‌

3.2、PriorityQueue 的简单用例

我们通过一个简单的例子看一下 PriorityQueue 的插入和推出时其底层数组结构的变化。

	public static void main(String[] args) {ArrayList<Integer> arrayList = new ArrayList<>();arrayList.add(1);arrayList.add(3);arrayList.add(2);arrayList.add(5);arrayList.add(4);arrayList.add(7);PriorityQueue<Integer> queue = new PriorityQueue<>(arrayList);queue.add(6);System.out.println(Arrays.toString(Arrays.stream(queue.toArray()).toArray()));while (!queue.isEmpty()){System.out.println(queue.poll());System.out.println(Arrays.toString(Arrays.stream(queue.toArray()).toArray()));}}

输出:

[1, 3, 2, 5, 4, 7, 6]
1
[2, 3, 6, 5, 4, 7]
2
[3, 4, 6, 5, 7]
3
[4, 5, 6, 7]
4
[5, 7, 6]
5
[6, 7]
6
[7]
7
[]

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

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

相关文章

用不同的url头利用Python访问一个网站,把返回的东西保存为txt文件

这个需要调用requests模块&#xff08;相当于c的头文件&#xff09; import requests 还需要一个User-Agent头&#xff08;这个意思就是告诉python用的什么系统和浏览器&#xff09; Google Chrome&#xff08;Windows&#xff09;: Mozilla/5.0 (Windows NT 10.0; Win64; x64…

【Git命令】git rebase之合并提交记录

使用场景 在本地提交了两个commit&#xff0c;但是发现根本没有没必要分为两次&#xff0c;需要想办法把两次提交合并成一个提交&#xff1b;这个时候可以使用如下命令启动交互式变基会话&#xff1a; git rebase -i HEAD~N这里 N 是你想要重新调整的最近的提交数。 如下在本地…

vscode配置django环境并创建django项目(全图文操作)

文章目录 创建项目工作路径下载python插件&#xff1a;创建虚拟环境选择虚拟环境在虚拟环境中安装Django创建Django项目 创建项目工作路径 下载python插件&#xff1a; 创建虚拟环境 >python:create 于是会多出一个.venv的目录 选择虚拟环境 在虚拟环境中安装Django …

MySQL 数据库 day 7.16

ok了家人们今天继续记录一下数据库,看看今天学了什么。 一.事物概述 1.1 环境准备 -- 账户表 create table account( id int primary key auto_increment, name varchar(20), money double );insert into account values (null,张三,1000); insert into account values (n…

解决Linux桌面初始化问题

问题 启动vnc桌面&#xff0c;提示问题 定位 从[t]csh手册 可以看到&#xff0c;其初始化流程 经定位&#xff0c;是.cshrc的这段代码存在&#xff0c;导致桌面初始化异常。 [wanlin.wangicinfra-cn-172-16-0-115 ~]$ cat .cshrc ...部分省略... # Environment for anac…

Unity UGUI 之 Canvas Scaler

本文仅作学习笔记与交流&#xff0c;不作任何商业用途 本文包括但不限于unity官方手册&#xff0c;唐老狮&#xff0c;麦扣教程知识&#xff0c;引用会标记&#xff0c;如有不足还请斧正 1.什么是Canvas Scaler Unity - 手册&#xff1a;Canvas Scaler 重点&#xff1a;虽然叫…

【springboot】中使用--WebMvcConfigurer

WebMvcConfigurer 一、页面跳转控制器step1:创建视图&#xff0c;resources/templates/index.htmlstep2:创建SpringMVC配置类step3:测试功能 二、数据格式化step1:创建 DeviceInfo 数据类step2&#xff1a;自定义 Formatterstep3: 登记自定义的 DeviceFormatterstep4: 新建 Con…

Flutter中GetX的用法(超详细使用指南之路由依赖管理篇)

目录 1.前言 2.GetX 依赖管理概述 1.GetX 依赖管理的基本概念 2.与其他依赖管理工具的比较 3. 基础依赖注入 1.Get.put 2.Get.lazyPut 3.Get.putAsync 4.高级依赖注入 1.使用Get.create 2.依赖生命周期管理 5. 参考资料 1.前言 今天这篇博客主要介绍Getx的三大功能…

java基于ssm+vue 药品网购平台

1用户前台功能模块 1.1前台首页 前台首页详情页面&#xff1a;首页、药品信息、疫情常识、保健品推荐、个人中心、后台管理、购物车等操作。程序效果图如下图1所示&#xff1a; 前台页面等内容&#xff0c;如图1所示。 1.2个人中心 在前台页面查看个人中心用户注册、登录&am…

【proteus经典实战】LCD滚动显示汉字

一、简介 Proteus是一款功能丰富的电子设计和仿真软件&#xff0c;它允许用户设计电路图、进行PCB布局&#xff0c;并在虚拟环境中测试电路功能。这款软件广泛应用于教育和产品原型设计&#xff0c;特别适合于快速原型制作和电路设计教育。Proteus的3D可视化功能使得设计更加直…

多任务高斯过程数学原理和Pytorch实现示例

高斯过程其在回归任务中的应用我们都很熟悉了&#xff0c;但是我们一般介绍的都是针对单个任务的&#xff0c;也就是单个输出。本文我们将讨论扩展到多任务gp&#xff0c;强调它们的好处和实际实现。 本文将介绍如何通过共区域化的内在模型(ICM)和共区域化的线性模型(LMC)&…

【Linux知识点汇总】07 Linux系统防火墙相关命令,关闭和开启防火墙、开放端口号

​完整系列文章目录 【Linux知识点汇总】 心血来潮突然想起之前写过的系列文章【Linux知识点汇总】还未完结&#xff0c;那么今天就继续吧 说明&#xff1a;这个系列的内容&#xff0c;在系列【Linux服务器Java环境搭建】中会经常用到&#xff0c;大家可以自行查找相关命令 一、…

Docker搭建本地私有仓库

目录 1.下载运行registry 镜像 2.添加私有镜像仓库地址 3.为镜像添加标签 4.上传到私有仓库 5.查看私有仓库的所有镜像 6.测试私有仓库下载 1.下载运行registry 镜像 docker pull registry docker run -d -v /data/registry:/var/lib/registry -p 5000:5000 --restartal…

PostgreSQL使用(二)——插入、更新、删除数据

说明&#xff1a;本文介绍PostgreSQL的DML语言&#xff1b; 插入数据 -- 1.全字段插入&#xff0c;字段名可以省略 insert into tb_student values (1, 张三, 1990-01-01, 88.88);-- 2.部分字段插入&#xff0c;字段名必须写全 insert into tb_student (id, name) values (2,…

vue3【详解】跨组件通信 -- 依赖注入 provide inject

用于解决跨组件&#xff08;父组件与所有后代&#xff09;数据通信 提供数据 provide 传出数据的组件 &#xff08;通常为父辈组件&#xff09;提供数据 <script setup> import { provide } from vueprovide(/* 注入名 */ message, /* 值 */ hello!) </script>pro…

pycharm中运行.sh文件

最近在跑一个项目代码&#xff0c;里面要运行.sh文件。于是配置了下如何在pycharm中正常运行.sh文件。 首先安装好git&#xff0c;然后 File—>Settings—>Tools—>Terminal—>Shell path&#xff0c;将cmd.exe改成刚刚下载的git的路径&#xff0c;注意选择的是s…

web服务器——虚拟主机配置实战

搭建静态网站 —— 基于 http 协议的静态网站 实验 1 &#xff1a;搭建一个 web 服务器&#xff0c;访问该服务器时显示 “hello world” 欢迎界面 。 实验 2 &#xff1a;建立两个基于 ip 地址访问的网站&#xff0c;要求如下 该网站 ip 地址的主机位为 100 &#xff0c;设置…

web——搭建静态网站——基于http协议的静态网站

实验 4 &#xff1a;建立两个基于域名访问的网站&#xff0c;要求如下&#xff1a; 新建一个网站&#xff0c;域名为 www.ceshi.com &#xff0c;设置网站首页目录为 /www/name &#xff0c;网页内容为 this is test 。 新建一个网站&#xff0c;域名为 rhce.first.day &…

阵列信号处理学习笔记(一)--阵列信号处理定义

阵列信号 阵列信号处理学习笔记&#xff08;一&#xff09;–阵列信号处理定义 阵列信号处理学习笔记&#xff08;二&#xff09;–空域滤波基本原理 文章目录 阵列信号前言一、阵列信号处理定义1.1 信号1.2 阵列 二、雷达数据中哪些属于空间采样总结 前言 MOOC 阵列信号处理…

在线 PDF 制作者泄露用户上传的文档

两家在线 PDF 制作者泄露了数万份用户文档&#xff0c;包括护照、驾驶执照、证书以及用户上传的其他个人信息。 我们都经历过这样的情况&#xff1a;非常匆忙&#xff0c;努力快速制作 PDF 并提交表单。许多人向在线 PDF 制作者寻求帮助&#xff0c;许多人的祈祷得到了回应。 …