一万字关于java数据结构堆的讲解,让你从入门到精通

news2025/1/23 10:41:35

目录

java类和接口总览

队列(Queue)

1. 概念

2. 队列的使用

以下是一些常用的队列操作:

1.入队操作

2.出队操作

3.判断队列是否为空

4.获取队列大小

5.其它

优先级队列(堆)

1. 优先级队列概念

Java中的PriorityQueue具有以下特点

2.常用的PriorityQueue操作

1.PriorityQueue的创建

2.插入元素

3.删除具有最高优先级的元素

4.查找具有最高优先级的元素

5.其它

3. 优先级队列的模拟实现

1.堆的概念

2.堆的性质

3.堆的存储方式

4.堆的创建

1.如何把给定的一棵二叉树,变成最小堆或者最大堆

以变成最大堆为例

2.时间复杂度分析

建堆的时间复杂度

 5.堆的删除

 6.用堆模拟实现优先级队列

7.常用接口介绍

1.关于PriorityQueue的使用注意事项

1. 优先级队列的构造

2. 插入/删除/获取优先级最高的元素                                           

完结撒花✿✿ヽ(°▽°)ノ✿


java类和接口总览

队列(Queue)


1. 概念

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First
In First Out) 入队列:进行插入操作的一端称为队尾(Tail/Rear) 出队列:进行删除操作的一端称为队头(Head/Front)

2. 队列的使用


在Java中,Queue是个接口,底层是通过链表实现的
 

Java中提供了多种队列(Queue)的实现,如LinkedList、ArrayDeque、PriorityQueue等,可以根据不同的需求选择适合的实现类。

以下是一些常用的队列操作:

1.入队操作

入队操作:使用add()或offer()方法将元素添加到队列的末尾。add()方法如果添加失败会抛出异常,而offer()方法则会返回一个boolean值表示添加是否成功。

Queue<Integer> queue = new LinkedList<>();
queue.add(1);
queue.offer(2);

2.出队操作

出队操作:使用poll()或remove()方法从队列的头部获取并移除元素。poll()方法如果队列为空则会返回null,而remove()方法则会抛出异常。

Queue<Integer> queue = new LinkedList<>();
queue.add(1);
queue.add(2);
int item = queue.poll(); // item的值为1
int item2 = queue.remove(); // item2的值为2

3.判断队列是否为空

判断队列是否为空:使用isEmpty()方法判断队列是否为空。

Queue<Integer> queue = new LinkedList<>();
queue.add(1);
boolean isEmpty = queue.isEmpty(); // isEmpty的值为false

4.获取队列大小

获取队列大小:使用size()方法获取队列的大小。

Queue<Integer> queue = new LinkedList<>();
queue.add(1);
queue.add(2);
int size = queue.size(); // size的值为2

5.其它

除了以上常用的操作外,Java的Queue接口还提供了其他一些方法,如element()方法用于获取队列的头元素但不移除,peek()方法用于获取队列头元素但不移除且判断队列是否为空等。可以根据具体需求选择适合的方法使用。


  

优先级队列(堆)

1. 优先级队列概念

前面介绍过队列,队列是一种先进先出(FIFO)的数据结构,但有些情况下,操作的数据可能带有优先级,一般出队列时,可能需要优先级高的元素先出队列,该中场景下,使用队列显然不合适,比如:在手机上玩游戏的时候,如果有来电,那么系统应该优先处理打进来的电话;初中那会班主任排座位时可能会让成绩好的同学先挑座位。
在这种情况下,数据结构应该提供两个最基本的操作,一个是返回最高优先级对象,一个是添加新的对象。这种数据结构就是优先级队列(Priority Queue)。堆实现了Queue这个接口,可以把它当做优先级队列

Java中的优先级队列(PriorityQueue)是一种特殊的队列,它使用二叉堆实现。在优先级队列中,每个元素都有一个优先级,优先级越高的元素在队列中的位置越靠前。

Java中的PriorityQueue具有以下特点

插入操作:向PriorityQueue中插入元素时,会根据元素的优先级确定其位置。如果新插入的元素的优先级高于当前队列中的最高优先级元素,则新元素将成为队列中的最高优先级元素。
删除操作:从PriorityQueue中删除元素时,会删除具有最高优先级的元素。如果队列中有多个具有相同最高优先级的元素,则会按照它们在队列中的顺序删除。
可查找操作:PriorityQueue支持查找操作,可以查找具有最高优先级的元素,或者查找具有指定优先级的元素。

2.常用的PriorityQueue操作

以下是一些常用的PriorityQueue操作

1.PriorityQueue的创建

在Java中,PriorityQueue可以使用以下代码创建:

PriorityQueue<Integer> pq = new PriorityQueue<>();

2.插入元素

可以使用add()方法向PriorityQueue中插入元素,例如:

pq.add(3);
pq.add(1);
pq.add(2);

3.删除具有最高优先级的元素

可以使用poll()方法从PriorityQueue中删除具有最高优先级的元素,例如:

int max = pq.poll(); // max = 3

4.查找具有最高优先级的元素

可以使用peek()方法查找具有最高优先级的元素,例如:

java
int max = pq.peek(); // max = 3

5.其它

除了默认的PriorityQueue外,Java还提供了一些其他类型的PriorityQueue,例如ArrayDeque、LinkedBlockingDeque等。这些PriorityQueue的实现方式略有不同,可以根据实际需求选择适合的类型。

3. 优先级队列的模拟实现

JDK1.8中的PriorityQueue底层使用了堆这种数据结构,而堆实际就是在完全二叉树的基础上进行了一些调整,本质上堆是一棵顺序存储的二叉树

Java中的优先级队列(PriorityQueue)是使用二叉堆实现的一种数据结构。二叉堆是一种特殊的树形数据结构,其中每个节点都满足堆的性质:根节点的值小于或等于其子节点的值(最大堆)或根节点的值大于或等于其子节点的值(最小堆)。

虽然Java中的PriorityQueue是使用二叉堆实现的,但我们可以使用其他数据结构来模拟实现优先级队列。

下面是一种使用数组实现优先级队列的示例代码:

public class PriorityQueue<T extends Comparable<T>> {
    private int[] heap;
    private int size;

    public PriorityQueue(int capacity) {
        heap = new int[capacity + 1];
    }

    public void enqueue(T value) {
        if (size == heap.length - 1) {
            resize();
        }
        int index = size;
        heap[index] = value.compareTo(((T) heap[index - 1])) > 0 ? value : heap[index - 1];
        upHeap(index);
        size++;
    }

    public T dequeue() {
        if (size == 0) {
            throw new IllegalStateException("Priority queue is empty");
        }
        T max = (T) heap[0];
        heap[0] = heap[size - 1];
        size--;
        downHeap(0);
        return max;
    }

    private void resize() {
        int[] newHeap = new int[heap.length * 2];
        System.arraycopy(heap, 0, newHeap, 0, heap.length);
        heap = newHeap;
    }

    private void upHeap(int index) {
        while (index > 0) {
            int parentIndex = (index - 1) / 2;
            if (heap[parentIndex].compareTo((T) heap[index]) <= 0) {
                break;
            }
            swap(parentIndex, index);
            index = parentIndex;
        }
    }

    private void downHeap(int index) {
        int size = heap.length - 1;
        while (true) {
            int leftChildIndex = 2 * index + 1;
            int rightChildIndex = 2 * index + 2;
            int largestIndex = index;
            if (leftChildIndex < size && heap[leftChildIndex].compareTo((T) heap[largestIndex]) > 0) {
                largestIndex = leftChildIndex;
            }
            if (rightChildIndex < size && heap[rightChildIndex].compareTo((T) heap[largestIndex]) > 0) {
                largestIndex = rightChildIndex;
            }
            if (largestIndex == index) {
                break;
            }
            swap(index, largestIndex);
            index = largestIndex;
        }
    }

    private void swap(int i, int j) {
        Object temp = heap[i];
        heap[i] = heap[j];
        heap[j] = temp;
    }
}

注:该代码定义了一个泛型的PriorityQueue类,支持向队列中插入元素(enqueue)和从队列中删除元素(dequeue)的操作。PriorityQueue使用一个数组来模拟二叉堆,通过调整数组元素的位置来维护堆的性质。在插入元素时,使用upHeap方法调整数组元素的位置,以维护最大堆的性质;在删除元素时,使用downHeap方法调整数组元素的位置,以维护最大堆的性质。在需要获取队列中的最大元素时,始终返回数组的第一个元素即可。

1.堆的概念

如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储 在一
个一维数组中,并满足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为 小堆(或大
堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。


2.堆的性质

1.堆中某个节点的值总是不大于或不小于其父节点的值;

2.堆总是一棵完全二叉树。

3.堆的存储方式

从堆的概念可知,堆是一棵完全二叉树,因此可以层序的规则采用顺序的方式来高效存储,


注意:对于非完全二叉树,则不适合使用顺序方式进行存储,因为为了能够还原二叉树,空间中必须要存储空节点,就会导致空间利用率比较低。
       

      将元素存储到数组中后,可以对树进行还原。

  • 假设i为节点在数组中的下标,则有:
  • 如果i为0,则i表示的节点为根节点,否则i节点的双亲节点为 (i - 1)/2
  • 如果2 * i + 1 小于节点个数,则节点i的左孩子下标为2 * i + 1,否则没有左孩子
  • 如果2 * i + 2 小于节点个数,则节点i的右孩子下标为2 * i + 2,否则没有右孩子

4.堆的创建

问题:对于集合{ 0,1,2,3,5,68 }中的数据,如果将其创建成最大堆呢?

1.如何把给定的一棵二叉树,变成最小堆或者最大堆

以变成最大堆为例

从这棵树的最后一棵子树开始调整,从右往左,从上往下 
仔细观察上图后发现:根节点的左右子树已经完全满足堆的性质,因此只需将根节点向下调整好即可。

向下过程(以最大堆为例):
1. 让parent标记需要调整的节点,child标记parent的左孩子(注意:parent如果有孩子一定先是有左孩子)
2. 如果parent的左孩子存在,即:child > size, 进行以下操作,直到parent的左孩子不存在
        parent右孩子是否存在,存在找到左右孩子中较大的孩子,让child进行标计,
        将parent与较大的孩子child比较,

                如果:parent大于较大的孩子child,调整结束
                否则:交换parent与较大的孩子child,交换完成之后,parent中大的元素向下移动,可能导致子树不满足最大堆的性质,

                因此需要继续向下调整,即parent = child;child = parent*2+1; 然后继续。

public class MaxHeapify {
    private int[] heap; // 存储二叉树节点的数组
    private int size; // 二叉树的大小

    public MaxHeapify(int n) {
        heap = new int[n + 1]; // 创建一个大小为 n+1 的数组,因为数组下标从0开始
        size = 0; // 二叉树的大小初始为0
    }

    public void add(int val) {
        heap[++size] = val; // 将新节点插入到数组的末尾
        int i = size; // 当前节点下标
        while (i > 1 && heap[i / 2] < heap[i]) { // 如果当前节点不是根节点且当前节点的值大于根节点的值
            swap(i, i / 2); // 则交换当前节点和根节点
            i /= 2; // 重新获取当前节点下标
        }
    }

    public int get(int i) {
        return heap[i]; // 返回指定下标的节点的值
    }

    public void maxHeapify(int i) { // i表示当前节点的下标
        int left = 2 * i + 1; // 左子节点的下标
        int right = 2 * i + 2; // 右子节点的下标
        int largest = i; // 记录最大的节点下标
        if (left < size && heap[left] > heap[largest]) { // 如果左子节点存在且值大于当前最大值
            largest = left; // 更新最大值下标为左子节点下标
        }
        if (right < size && heap[right] > heap[largest]) { // 如果右子节点存在且值大于当前最大值
            largest = right; // 更新最大值下标为右子节点下标
        }
        if (largest != i) { // 如果当前节点不是最大值节点
            swap(i, largest); // 则交换当前节点和最大值节点
            maxHeapify(largest); // 对新的当前节点进行最大堆调整
        }
    }

    private void swap(int i, int j) { // i和j分别表示两个节点的下标
        int temp = heap[i]; // 保存第一个节点的值
        heap[i] = heap[j]; // 将第二个节点的值赋给第一个节点
        heap[j] = temp; // 将第一个节点的值赋给第二个节点
    }
}

/*注释:
private int[] heap; 和 private int size; 分别表示存储二叉树节点的数组和二叉树的大小。
public MaxHeapify(int n) 是构造函数,创建一个大小为 n+1 的数组,因为数组下标从0开始。
public void add(int val) 方法将新节点插入到数组的末尾,然后通过交换节点和其父节点来调整二叉树,使其满足最大堆的性质。
public int get(int i) 方法返回指定下标的节点的值。
public void maxHeapify(int i) 方法用于调整以 i 为根节点的子树为最大堆。首先找到左右子节点中最大的节点,然后与当前节点进行交换,并对新的当前节点进行最大堆调整。这个方法使用了递归的方式,直到每个子树都是最大堆为止。
private void swap(int i, int j) 方法用于交换两个节点的值。*/
    public void shiftDown(int[] array, int parent) {
        // child先标记parent的左孩子,因为parent可能右左没有右
        int child = 2 * parent + 1;
        int size = array.length;
        while (child < size) {
            // 如果右孩子存在,找到左右孩子中较小的孩子,用child进行标记
            if (child + 1 < size && array[child + 1] < array[child]) {
                {
                    child += 1;
                }
            }
            // 如果双亲比其最小的孩子还小,说明该结构已经满足堆的特性了
            if (array[parent] <= array[child]) {
                break;
            } else {
            // 将双亲与较小的孩子交换
                int t = array[parent];
                array[parent] = array[child];
                array[child] = t;
            // parent中大的元素往下移动,可能会造成子树不满足堆的性质,因此需要继续向下调整
                parent = child;
                child = parent * 2 + 1;
            }
        }
    }

注意:在调整以parent为根的二叉树时,必须要满足parent的左子树和右子树已经是堆了才可以向下调整。

2.时间复杂度分析

时间复杂度分析:最坏的情况即图示的情况,从根一路比较到叶子,比较的次数为完全二叉树的高度,即时间复杂度为O(log2n)

建堆的时间复杂度


因为堆是完全二叉树,而满二叉树也是完全二叉树,此处为了简化使用满二叉树来证明(时间复杂度本来看的就是
近似值,多几个节点不影响最终结果):

因此:建堆的时间复杂度为O(N)。
堆的插入与删除
2.4.1 堆的插入
堆的插入总共需要两个步骤:
1. 先将元素放入到底层空间中(注意:空间不够时需要扩容)
2. 将最后新插入的节点向上调整,直到满足堆的性质

public void shiftUp(int child) {
    // 找到child的双亲
    int parent = (child - 1) / 2;
    while (child > 0) {
    // 如果双亲比孩子大,parent满足堆的性质,调整结束
       if (array[parent] > array[child]) {
           break;
        } else {
    // 将双亲与孩子节点进行交换
           int t = array[parent];
           array[parent] = array[child];
           array[child] = t;
    // 小的元素向下移动,可能到值子树不满足对的性质,因此需要继续向上调增
           child = parent;
           parent = (child - 1) / 1;
        }
    }
}

 5.堆的删除

 注意:堆的删除一定删除的是堆顶元素。具体如下:
1. 将堆顶元素对堆中最后一个元素交换
2. 将堆中有效数据个数减少一个
3. 对堆顶元素进行向下调整

 6.用堆模拟实现优先级队列

public class MyPriorityQueue {
    // 演示作用,不再考虑扩容部分的代码
    private int[] array = new int[100];
    private int size = 0;

    public void offer(int e) {
        array[size++] = e;
        shiftUp(size - 1);
    }

    public int poll() {
        int oldValue = array[0];
        array[0] = array[--size];
        shiftDown(0);
        return oldValue;
    }

    public int peek() {
        return array[0];
    }
}

7.常用接口介绍

PriorityQueue的特性:Java集合框架中提供了PriorityQueue和PriorityBlockingQueue两种类型的优先级队列,PriorityQueue是线程不安全的,PriorityBlockingQueue是线程安全的,主要介绍的是PriorityQueue。

1.关于PriorityQueue的使用注意事项

关于PriorityQueue的使用要注意:
1. 使用时必须导入PriorityQueue所在的包,即:
import java.util.PriorityQueue;
2. PriorityQueue中放置的元素必须要能够比较大小,不能插入无法比较大小的对象,否则会抛出
ClassCastException异常
3. 不能插入null对象,否则会抛出NullPointerException
4. 没有容量限制,可以插入任意多个元素,其内部可以自动扩容
5. 插入和删除元素的时间复杂度为
6. PriorityQueue底层使用了堆数据结构
7. PriorityQueue默认情况下是小堆---即每次获取到的元素都是最小的元素
3.2 PriorityQueue常用接口介绍


1. 优先级队列的构造

PriorityQueue中常见的几种构造方式

    public static void TestPriorityQueue() {
        // 创建一个空的优先级队列,底层默认容量是11
        PriorityQueue<Integer> q1 = new PriorityQueue<>();
        // 创建一个空的优先级队列,底层的容量为initialCapacity
        PriorityQueue<Integer> q2 = new PriorityQueue<>(100);
        ArrayList<Integer> list = new ArrayList<>();
        list.add(4);
        list.add(3);
        list.add(2);
        list.add(1);
        // 用ArrayList对象来构造一个优先级队列的对象
        // q3中已经包含了三个元素
        PriorityQueue<Integer> q3 = new PriorityQueue<>(list);
        System.out.println(q3.size());
        System.out.println(q3.peek());
    }

 注意:默认情况下,PriorityQueue队列是小堆,如果需要大堆需要用户提供比较器

public class TestPriorityQueue {
    public static void main(String[] args) {
        PriorityQueue<Integer> p = new PriorityQueue<>(new IntCmp());
        p.offer(4);
        p.offer(3);
        p.offer(2);
        p.offer(1);
        p.offer(5);
        System.out.println(p.peek());
    }
}

此时创建出来的就是一个大堆。

2. 插入/删除/获取优先级最高的元素                                           

函数名功能介绍
boolean offer(E e)插入元素e,插入成功返回true,如果e对象为空,抛出NullPointerException异常,时间复杂度O(log2N),注意:空间不够时候会进行扩容
E peek()获取优先级最高的元素,如果优先级队列为空,返回null
E poll()移除优先级最高的元素并返回,如果优先级队列为空,返回null
int size()获取有效元素的个
void clear()清空
boolean isEmpty()检测优先级队列是否为空,空返回true

 public static void TestPriorityQueue2() {
        int[] arr = {4, 1, 9, 2, 8, 0, 7, 3, 6, 5};
        // 一般在创建优先级队列对象时,如果知道元素个数,建议就直接将底层容量给好
        // 否则在插入时需要不多的扩容
        // 扩容机制:开辟更大的空间,拷贝元素,这样效率会比较低
        PriorityQueue<Integer> q = new PriorityQueue<>(arr.length);
        for (int e : arr) {
            q.offer(e);
        }
        System.out.println(q.size()); // 打印优先级队列中有效元素个数
        System.out.println(q.peek()); // 获取优先级最高的元素
        // 从优先级队列中删除两个元素之和,再次获取优先级最高的元素
        q.poll();
        q.poll();
        System.out.println(q.size()); // 打印优先级队列中有效元素个数
        System.out.println(q.peek()); // 获取优先级最高的元素
        q.offer(0);
        System.out.println(q.peek()); // 获取优先级最高的元素
        // 将优先级队列中的有效元素删除掉,检测其是否为空
        q.clear();
        if (q.isEmpty()) {
            System.out.println("优先级队列已经为空!!!");
        } else {
            System.out.println("优先级队列不为空");
        }
    }

注意:以下是JDK 1.8中,PriorityQueue的扩容方式:

    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    private void grow(int minCapacity) {
        int oldCapacity = queue.length;
        // Double size if small; else grow by 50%
        int newCapacity = oldCapacity + ((oldCapacity < 64) ?
                (oldCapacity + 2) :
                (oldCapacity >> 1));
        // overflow-conscious code
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        queue = Arrays.copyOf(queue, newCapacity);
    }
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
    }

优先级队列的扩容说明:
如果容量小于64时,是按照oldCapacity的2倍方式扩容的
如果容量大于等于64,是按照oldCapacity的1.5倍方式扩容的
如果容量超过MAX_ARRAY_SIZE,按照MAX_ARRAY_SIZE来进行扩容

完结撒花✿✿ヽ(°▽°)ノ✿


 

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

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

相关文章

Doris的执行计划生成、分发与执行

目录 一、执行计划的生成 二、执行计划的分发 三、执行计划的执行 一、执行计划的生成 在Doris的FE端&#xff0c;与大多数数据库系统一样&#xff0c;要从SQL或某种http请求&#xff0c;生成执行计划&#xff0c;从SQL生成&#xff0c;一开始是“抽象语法树”&#xff08;…

FreeRTOS 从入门到精通-任务调度

初写FreeRTOS 从入门到精通系列文章之初&#xff0c;笔者只是当作可以随时回顾的学习笔记来写&#xff0c;并没有想到这些偏技术的文章收获了意料之外的阅读量和关注。首先当然很欣喜自己的文章能够得到了读者们的认可&#xff0c;但同时也有种使命感&#xff0c;既期望启迪并与…

模型评估的常用指标

模型评估的指标 模型是在大量的数据集上训练而来的,无论一个模型是从零训练的还是基于某一个模型,通过微调方法得到的,靠人工评价模型的效果都是异常困难的。那么要想客观的、自动化的评价一个LLM模型,就需要能够选择正确评估模型效果的指标或者基准测试,来客观和自动化的…

C语言刷题指南(二)

&#x1f4d9;作者简介&#xff1a; 清水加冰&#xff0c;目前大二在读&#xff0c;正在学习C/C、Python、操作系统、数据库等。 &#x1f4d8;相关专栏&#xff1a;C语言初阶、C语言进阶、C语言刷题训练营、数据结构刷题训练营、有感兴趣的可以看一看。 欢迎点赞 &#x1f44d…

腾讯开启2024校招,主要招聘5大类岗位

近日&#xff0c;腾讯的大动作一个接一个&#xff0c;前脚刚公布2023上半年财报&#xff0c;后脚就开启了2024校招&#xff0c;不得不让人感叹腾讯真速度&#xff01; 此次招聘对象为毕业时间在2023年9月至2024年8月期间的2024届应届毕业生&#xff0c;覆盖北上广深等多个城市…

Python中定时任务APScheduler库用法详解

在日常工作中&#xff0c;常常会用到需要周期性执行的任务&#xff0c;一种方式是采用 Linux 系统自带的 crond 结合命令行实现。另外一种方式是直接使用Python。 当每隔一段时间就要执行一段程序&#xff0c;或者往复循环执行某一个任务&#xff0c;这就需要使用定时任务来执…

如何搭建游戏服务器?有哪些操作步骤

​  选择游戏服务器提供商 为确保游戏服务器的稳定运行和及时响应问题&#xff0c;选择一个正规、靠谱的游戏服务器提供商非常重要。 选择服务器操作系统 根据不同游戏的需求&#xff0c;选择适合的操作系统&#xff0c;通常可选择Linux或WindowsServer操作系统。 上传、安装…

智安网络|零信任安全框架:保障数字化时代网络安全的最佳实践

随着数字化时代的快速发展&#xff0c;网络安全问题变得越来越突出。传统的安全防御模式已经不再适用于现代复杂的网络环境中。为了应对日益增长的网络威胁&#xff0c;零信任安全模式应运而生。 一、什么是零信任&#xff1f; 零信任是一种安全框架和哲学&#xff0c;它基于…

【使用教程】在Ubuntu下运行CANopen通信PMM伺服电机使用教程(NimServoSDK_V2.0.0)

本教程将指导您在Ubuntu操作系统下使用NimServoSDK_V2.0.0来运行CANopen通信的PMM系列一体化伺服电机。我们将介绍必要的步骤和命令&#xff0c;以确保您能够成功地配置和控制PMM系列一体化伺服电机。 NimServoSDK_V2.0.0是一款用于PMM一体化伺服电机的软件开发工具包。它提供了…

第八章LVS中的DR模式详解

1&#xff0c;LVS-DR数据包的流向分析 总结&#xff1a; &#xff08;1&#xff09;客户端发送请求到 Director Server&#xff08;负载均衡器&#xff09;&#xff0c;请求的数据报文&#xff08;源 IP 是 CIP,目标 IP 是 VIP&#xff09;到达内核空间。 &#xff08;2&#…

机器学习基础之《分类算法(3)—模型选择与调优》

作用是如何选择出最好的K值 一、什么是交叉验证&#xff08;cross validation&#xff09; 1、定义 交叉验证&#xff1a;将拿到的训练数据&#xff0c;分为训练和验证集。以下图为例&#xff1a;将数据分成5份&#xff0c;其中一份作为验证集。然后经过5次(组)的测试&#x…

「UG/NX」Block UI 体收集器BodyCollector

✨博客主页何曾参静谧的博客📌文章专栏「UG/NX」BlockUI集合📚全部专栏「UG/NX」NX二次开发「UG/NX」BlockUI集合「VS」Visual Studio「QT」QT5程序设计「C/C+&#

springboot引入druid解析sql

一、前言 在开发中&#xff0c;有时我们可能会需要获取SQL中的表名&#xff0c;那么因为不同的数据源类型SQL会存在部分差异&#xff0c;那么我们就可以使用alibaba 的druid包实现不同的数据源类型的sql解析。 二、引入相关maven依赖 <dependency><groupId>com.a…

Python基础语法入门(第二十二天)——并发编程

在Python中&#xff0c;并发编程的实现有多种方式&#xff0c;包括多线程、多进程和异步编程。每一种方式都有其使用的场景和特点。那么如何去选择多线程、多进程和多协程呢&#xff1f;要知道如何选择的话就要了解一下什么是CPU密集型计算、什么是I/O密集型计算&#xff1b;多…

selenium +Jmeter 的性能测试

通过Jmeter快速将已有的Selenium 代码以性能测试的方式组织起来&#xff0c;并使用JMeter 丰富的报表展示测试结果 from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.by import By driver …

JAVA基础知识(三)——数组

数组 数组一、数组的概述1.1 数组的定义1.2 数组的常见概念1.3 数组的特点1.4 数组的分类 二、一维数组的使用2.1 一维数组的声明和初始化2.2 数组的基本使用2.3 数组元素的默认初始化值2.4 数组的内存解析 三、多维数组的使用3.1 二维数组的理解3.2 二维数组的声明3.3 二维数组…

多家企业加入即将在2024年发射的量子卫星SpeQtral-1任务

近日&#xff0c;总部位于新加坡的量子通信技术公司SpeQtral宣布将与纳米航空电子公司NanoAvionics和卫星光子学公司Mbryonics合作执行即将到来的SpeQtral-1量子密钥分发&#xff08;Quantum Key Distribution, QKD&#xff09;卫星任务。NanoAvionics被选为卫星平台提供商&…

算法题面试实战收集

回文数字 2023-08-18 美团 一面 在不使用额外的内存空间的条件下判断一个整数是否是回文。 回文指逆序和正序完全相同。 数据范围&#xff1a; 进阶&#xff1a; 空间复杂度O(1) &#xff0c;时间复杂度 O(n) 提示&#xff1a; 负整数可以是回文吗&#xff1f;&#xff08;比如…

Python数据分析实战-多进程并发处理列表(附源码和实现效果)

实现功能 有15个列表&#xff0c;尝试多进程并发处理&#xff0c;每个列表一个进程&#xff0c;进程数和 CPU 核数一致 实现代码 import multiprocessing有15个列表&#xff0c;尝试多进程并发处理&#xff0c;每个列表一个进程&#xff0c;进程数和 CPU 核数一致def sum_li…

第P1周:实现mnist手写数字识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 我的环境&#xff1a; 语言环境&#xff1a;Python3.10.7编译器&#xff1a;VScode深度学习环境&#xff1a;TensorFlow 2.13.0 一、前期工作&#xff1a; …