【数据结构-JAVA】堆和优先级队列

news2024/11/20 11:24:15

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

JDK1.8中的 PriorityQueue 底层使用了堆这种数据结构,而堆实际就是在完全二叉树的基础上进行了一些调整。 下面将详细介绍堆。

1. 堆

1.1 堆的概念

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

堆的性质: 1. 堆中某个节点的值总是不大于或不小于其父节点的值。 2. 堆总是一棵完全二叉树。

从堆的概念可知,堆是一棵完全二叉树,因此可以层序的规则采用顺序的方式来高效存储,而对于非完全二叉树,则不适合使用顺序方式进行存储,因为为了能够还原二叉树,空间中必须要存储空节 点,就会导致空间利用率比较低。 将元素存储到数组中后,假设 i 为节点在数组中的下标,则有: 如果 i 为0,则 i 表示的节点为根节点,否则 i 节点的双亲节点为 (i - 1)/2 如果 2 * i + 1 小于节点个数,则节点i的左孩子下标为 2 * i + 1 ,否则没有左孩子 如果 2 * i + 2 小于节点个数,则节点i的右孩子下标为 2 * i + 2 ,否则没有右孩子

1.2 堆的创建

堆是存储在一个一维数组中的,那么怎么用通过一个数组,让其变成一个堆呢?先简单介绍一下向下调整形成大根堆的思路:由于输入的数组是随机的,其对应的二叉树,也并不总是父亲节点的值大于孩子节点,所以我们要做的就是调整位置,让父亲节点的值与左右孩子节点的最大值做比较,小了,就与孩子节点交换位置,而大了,不做改变,从而让这个二叉树变成大根堆。

1.2.1 堆向下调整

public class TextHeap {
    public int[] elem;
    public int usedSized;

    public TextHeap() {
        this.elem = new int[10];
    }
    
    public void initElem(int[] arr){
        for (int i = 0; i < arr.length; i++) {
            elem[i] = arr[i];
            usedSized++;
        }
    }

    /*
    //创建大根堆
     */
    public void createHeap(){
        //找到这个完全二叉树中,最后一个父亲节点的下标:
        //最后一个节点的父亲节点,也是该二叉树的最后一个父亲节点,以此开始
        for (int parent = (usedSized - 1 - 1 )/ 2;  parent >= 0 ; parent--) {
            //使用 usedSize 作为向下调整的最大边界
            shiftDown(parent,usedSized);
        }
    }

    private void shiftDown(int parent,int len){
        //最起码有左孩子
        int child = 2 * parent + 1;

        // 可能需要多次向下调整:
        while(child < len){
            //如果有右孩子时,得让 child 这个下标对应左右孩子最大值的下标
            if(child + 1 < len && elem[child] < elem[child + 1]){
                child++;
            }

            if(elem[child] > elem[parent]){
                int temp = elem[child];
                elem[child] = elem[parent];
                elem[parent] = temp;
                parent = child;
                child = 2 * parent + 1;
            }else{
                break;
            }
        }
    }
}

1.3 堆向下调整创建堆的时间复杂度

按照最坏的情况来看,即创建一棵高度为 h 的满二叉树的话,这样的堆的时间复杂度该如何计算呢?

高度为 h ,那么最后一层就是第 h 层,该层的节点总数为 ,这一层都是叶子节点,并不需要向下调整。而倒数第二层,即 h - 1 层,该层的节点总数为 ,而这里的每一个节点都需要向下调整 1 次。以此类推到第一层。

由② - ① 得:

化简得:

又因为总节点数 n 满足:

所以有

所以时间复杂度为

1.4 堆向上调整创建堆的时间复杂度

② - ① 得

化简得:

最后:

因此时间复杂度为:

1.5 堆的插入

将要插入的元素放在堆的最后位置,向上调整,时间复杂度为二叉树的高度,只需一路向上,跟父亲节点比较交换即可。

   private void shiftUp(int child){
        int parent = (child - 1)/2;
        while(child > 0){
            if(elem[child] > elem[parent]){
                int temp = elem[child];
                elem[child] = elem[parent];
                elem[parent] = temp;
                child = parent;
                parent = (child - 1)/2;
            }else{
                break;
            }
        }
    }

    //堆的插入
    public void offer(int val){
        if(isFull()){
            //满了就扩容
            elem = Arrays.copyOf(elem,elem.length+5);
        }
        elem[usedSized++] = val;
        shiftUp(usedSized - 1);
    }

    private boolean isFull(){
        return usedSized == elem.length;
    }

1.6 堆的删除

堆的删除,只能删除根节点元素。删除的思路:把根节点元素与堆中最后一个元素交换,usedSize--,同时向下调整。

    //堆的删除
    public void pop(){
        if(isEmpty()){
            return;
        }
        elem[0] = elem[usedSized - 1];
        usedSized--;
        //只需从0下标的这个父亲节点去向下调整就可以了
        shiftDown(0,usedSized);


    }
    private boolean isEmpty(){
        return usedSized == 0;
    }

1.7 堆排序

堆排序:将存储堆的数组里的元素,从小到大或从大到小排序

从小到大,建大堆

public class Text{    
public static void main(String[] args) {
        int[] arr = {1,4,6,235,15,75,123,61,70,13};
        TextHeap heap = new TextHeap();
        heap.initElem(arr);
        heap.createHeap();
        heap.heapSort();
        System.out.println();
    }
}

public class TextHeap{
........
//省略的部分可往前文查找
    private void swap(int[] arr,int i ,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    //堆排序
    public void heapSort(){
        int end = usedSized - 1;
        while(end > 0 ){
            swap(elem,0,end);
            shiftDown(0,end);
            end--;
        }
    }
}

时间复杂度O(nlogn),空间复杂度O(1)。

而从大到小,则建小堆。这里就不再赘述。

2. 优先级队列(Priority Queue)

2.1 优先级队列的性质

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

关于PriorityQueue的使用要注意: 1. 使用时必须导入PriorityQueue所在的包,即:

import java.util.PriorityQueue;

2. PriorityQueue中放置的元素必须要能够比较大小,不能插入无法比较大小的对象,否则会抛出 ClassCastException异常

比如以下代码,priorityQueue中存放的是Student的对象,此时这些对象并不能比较大小:

    public static void main(String[] args) {
        Queue<Student> priorityQueue = new PriorityQueue<>();
        priorityQueue.offer(new Student("huahua",15));
        priorityQueue.offer(new Student("liu",34));
        System.out.println(priorityQueue.poll());
    }

因此报错:

3. 不能插入null对象,否则会抛出NullPointerException

4. 没有容量限制,可以插入任意多个元素,其内部可以自动扩容 5. 插入和删除元素的时间复杂度为,也就是二叉树的高度 6. PriorityQueue底层使用了堆数据结构 7. PriorityQueue默认情况下是小堆---即每次获取到的元素都是最小的元素

    //检验一下 PriorityQueue 真的默认为小根堆?
    public static void main(String[] args) {
        Queue<Integer> priorityQueue = new PriorityQueue<>();
        priorityQueue.offer(1);
        priorityQueue.offer(88);
        System.out.println(priorityQueue.poll());
    }

2.2 top-k 问题

设计一个算法,找出数组中最小或最大的前k个数。以任意顺序返回这k个数均可。

2.2.1 排序思路——效率较低

将这个数组建成小根堆,拿这小根堆的前10个元素,但这种方法效率低下。

    //top-k问题
    //排序思路
    public int[] topK1(int[] arr,int k){
        int[] ret = new int[k];
        if(arr == null || k == 0){
            return ret;
        }
        Queue<Integer> priorityQueue = new PriorityQueue<>();
        for (int i = 0; i < arr.length; i++) {
            priorityQueue.offer(arr[i]);
        }
        for (int i = 0; i < k; i++) {
            ret[i] = priorityQueue.poll();
        }
        return ret;
    }

2.2.2 善于利用堆排序解决topk问题

如果是输出数组中前k个最大的元素,其实只要创建容量为k的优先队列即可,而不是像3.2.1那样,创建一个容量为arr.length的优先队列。

此时容量为k的优先队列默认为小根堆,让数组的前k个元素放入优先级队列中,之后让数组从第k+1个元素往后遍历,每一个都与小根堆的堆顶元素做比较。由于是小根堆,堆顶元素就是k个元素中,最小的一个,与数组第k+1个元素及以后的元素作比较,挨个置换比根节点大的元素,那么等数组遍历完之后,小根堆里存储的元素都比数组中其余元素要大,不然的话,还是会被置换出来的。如此一来,小根堆存储的就是数组中前k个最大元素。

    public static int[] topK2(int[] arr,int k){
        int[] ret = new int[k];
        if(arr == null || k == 0){
            return ret;
        }
        Queue<Integer> priorityQueue = new PriorityQueue<>(k);
        for (int i = 0; i < k; i++) {
            priorityQueue.offer(arr[i]);
        }
        for (int i = k; i < arr.length; i++) {
            if(arr[i] > priorityQueue.peek()){
                priorityQueue.poll();
                priorityQueue.offer(arr[i]);
            }
        }
        for (int i = 0; i < k; i++) {
            ret[i] = priorityQueue.poll();
        }
        return ret;
    }

    public static void main(String[] args) {
        int[] arr = {1,6,43,2,7,88,67,17,29,257,35};
        int[] ret = topK2(arr,3);
        System.out.println(Arrays.toString(ret));
    }

输出:

[67, 88, 257]

问题换一换,找第k大的元素?

其实就是堆顶元素啦~~

那如果要求的是前k个最小元素呢?这时候就要用到大根堆,可优先级队列默认是小根堆,那该如何在优先级队列中创建大根堆呢?

2.3 优先级队列构造方法

此处只是列出了PriorityQueue中常见的几种构造方式。

构造器

功能介绍

PriorityQueue()

创建一个空的优先级队列,默认容量是11

PriorityQueue(int initialCapacity)

创建一个初始容量为initialCapacity的优先级队列,注意: initialCapacity不能小于1,否则会抛IllegalArgumentException异 常

PriorityQueue(int initialCapacity, Comparator<? super E> comparator)

创建一个初始容量为initialCapacity的优先级队列,并且有比较器

PriorityQueue(Collection<? extends E> c)

用一个集合来创建优先级队列

    public static void main(String[] args) {
        // 创建一个空的优先级队列,底层默认容量是11
        Queue<Integer> q1 = new PriorityQueue<>();

        // 创建一个空的优先级队列,底层的容量为 100
        Queue<Integer> q2 = new PriorityQueue<>(100);

        // 用ArrayList对象来构造一个优先级队列的对象
        // q3中已经包含了三个元素
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(45);
        list.add(23);
        Queue<Integer> q3 = new PriorityQueue<>(list);
        q3.offer(9);
        System.out.println(q3.size());
    }

输出:

4

2.4 对象的比较方式

优先级队列在插入元素时有个要求:插入的元素不能是null或者元素之间必须要能够 进行比较,为了简单起见,我们只是插入了Integer类型,那优先级队列中能否插入自定义类型对象呢?

优先级队列底层使用堆,而向堆中插入元素时,为了满足堆的性质,必须要进行元素的比较,而在优先级队列的性质那一小节中,优先级队列插入的是引用类型,是没有办 法直接进行比较的,因此抛出异常。因此在这里引出一个问题,对象的比较方式,以下介绍三种方法:

2.4.1 equals方法

   class Student{
    public String name;
    public int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
 public static void main(String[] args) {
        Student student1 = new Student("shanshan",15);
        Student student2 = new Student("shanshan",15);
        System.out.println(student1==student2);
        System.out.println(student1.equals(student2));
    }

输出:

false

false

==比较的是地址,输出是false;而当我们一开始直接就用equals时,返回的依旧是false。这是因为Student类中并无equals方法,而所有类都是Object类的子类,所以调用的就是Object类的equals方法:

我们发现,此处的equals方法也等同于==,比较的是引用变量的地址。

但是此处,我们需要比较的是对象中的内容,那该如何处理呢?基于此,我们可以覆写基类的equals方法。(可右击自动生成)

class Student{
    public String name;
    public int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

输出:

false

true

覆写基类equal的方式虽然可以比较,但缺陷是:equal只能按照相等进行比较,不能按照大于、小于的方式进行比较。

因此,优先级队列并不采用equals方法。

2.4.2 Compareble接口

Comparble是JDK提供的泛型的比较接口类,源码实现具体如下:

public interface Comparable<T> {

    public int compareTo(T o);
}

对用用户自定义类型,如果要想按照大于、小于的方式进行比较时:在定义类时,实现Comparble接口即可,然后在类 中重写compareTo方法,举例如下:

class Student implements Comparable<Student>{

......

@Override
    public int compareTo(Student o) {
        return this.age - o.age;
    }
}

但这样compareTo就只能比较年龄了,那要是想比较学生的成绩或是其他,该怎么办呢?

2.4.2 基于比较器比较

Comparator部分源代码:

public interface Comparator<T> {
    int compare(T o1, T o2);

......
}

按照比较器方式进行比较,具体步骤如下: 用户自定义比较器类,实现Comparator接口并且重写Comparator中的compare方法:

//姓名比较器
class nameComparator implements Comparator<Student>{
    @Override
    public int compare(Student o1, Student o2) {
        return o1.name.compareTo(o2.name);
    }
}

//年龄比较器
class AgeComparator implements Comparator<Student>{
    @Override
    public int compare(Student o1, Student o2) {
        return o1.age - o2.age;
    }
}

上面的compareTo方法中,因为name是String类的对象,可以调用String中的compareTo方法,这里比较的是两个字符串的大小。

NameComparator nameComparator = new NameComparator();
System.out.println(nameComparator.compare(student1,student2));

2.5 优先级队列的比较方式

集合框架中的PriorityQueue底层使用堆结构,因此其内部的元素必须要能够比大小,PriorityQueue采用了: Comparble和Comparator两种方式。 1. Comparble是默认的内部比较方式,如果用户插入自定义类型对象时,该类对象必须要实现Comparble接 口,并覆写compareTo方法 2. 用户也可以选择使用比较器对象,如果用户插入自定义类型对象时,必须要提供一个比较器类,让该类实现 Comparator接口并覆写compare方法。

继续用上面Student类的例子,来演示如何将自定义类型对象插入优先级队列,以及如何创建大根堆:

Comparble接口:

class Student implements Comparable<Student>{
    public String name;
    public int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }


    //为创建大根堆
    @Override
    public int compareTo(Student o) {
        return o.age - this.age;
    }
}

    public static void main(String[] args) {
        Student student1 = new Student("shansan",10);
        Student student2 = new Student("shanan",15);
        PriorityQueue<Student> priorityQueue = new PriorityQueue<>();
        priorityQueue.offer(student1);
        priorityQueue.offer(student2);

        System.out.println("sssssssss");
    }

Comparator接口:

    class InCmp implements Comparator<Integer>{
        @Override
        public int compare(Integer o1, Integer o2) {
            //调用了Integer这个类中的compareTo方法
            return o2.compareTo(o1);
            //return o1 - o2;
        }
    }

    public static void main(String[] args) {
        InCmp inCmp = new InCmp();
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(inCmp);
        priorityQueue.offer(5);
        priorityQueue.offer(1);
        priorityQueue.offer(98);
        priorityQueue.offer(23);
        priorityQueue.offer(51);
        System.out.println("2222222222222222222");
    }

还可以使用匿名内部类的方法写:

        //一个实现了Comparator接口的匿名内部类
        PriorityQueue<Integer> priorityQueue1 = new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                //小根堆
                return o1.compareTo(o2);
            }
        });

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

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

相关文章

Hugo博客教程(一)

秋风阁——北溪入江流&#xff1a;https://focus-wind.com/ 秋风阁——计算机视觉实验&#xff1a;边缘提取与特征检测 文章目录Hugo博客教程&#xff08;一&#xff09;博客静态博客静态博客的优缺点常见的静态博客HexoHugo动态博客动态博客的优缺点常见的动态博客WordPressTy…

sql进阶教程

sql进阶教程第一章、神奇的sql1.1 CASE 表达式将已有编号方式转换为新的方式并统计用一条 SQL 语句进行不同条件的统计用 CHECK 约束定义多个列的条件关系在 UPDATE 语句里进行条件分支表之间的数据匹配在 CASE 表达式中使用聚合函数本节要点1.2 自连接的用法面向集合语言SQL可…

shiro(二):springboot整合shiro

1. 整合思路 2. 加入jsp相关配置方便测试 2.1 加入依赖&#xff1a; <!--引入JSP解析依赖--> <dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId></dependency> <dependenc…

Golang——包

1、GOPATH 项目代码肯定要需要保存在一个目录中&#xff0c;但是如果目录不统一&#xff0c;每个人有一套自己的目录结构&#xff0c;读取配置文件的位置不统一&#xff0c;输出的二进制运行文件也不统一&#xff0c;这样会导致开发的标准不统一。 所以&#xff0c;产生环境变量…

QEMU安装Windows 11的完整过程

零、环境介绍 宿主机&#xff1a; Ubuntu 22.04.1 LTS Windows 11镜像&#xff1a; Win11_Chinese(Simplified)_x64v1 QEMU版本&#xff1a; qemu-img version 7.1.0 Copyright (c) 2003-2022 Fabrice Bellard and the QEMU Project developers 一、安装过程 1. 创建…

随机过程与排队论(二)

随机试验 如果一个试验E满足下列条件&#xff0c;就称此试验为随机试验&#xff1a; 在相同条件下可以重复进行。每次试验的结果不止一个&#xff0c;并且能事先明确知道试验的所有结果。一次试验结束之前&#xff0c;不能确定哪一个结果会出现。 样本空间、随机事件体 随机…

估值85亿美元!智驾前装赛道又添新“巨头”,已开始量产交付

随着智能汽车技术与供应链的发展&#xff0c;可以看到很多高端汽车也逐渐开始采用过去在L4上才使用的传感器&#xff0c;例如激光雷达。同时&#xff0c;多传感器融合技术也已进入规模化量产阶段&#xff0c;为L2在乘用车上的大规模应用打开了一个新窗口。 而作为L4领域的资深…

Leetcode力扣秋招刷题路-0124

从0开始的秋招刷题路&#xff0c;记录下所刷每道题的题解&#xff0c;帮助自己回顾总结 124. 二叉树中的最大路径和&#xff08;Hard&#xff09; 路径 被定义为一条从树中任意节点出发&#xff0c;沿父节点-子节点连接&#xff0c;达到任意节点的序列。同一个节点在一条路径序…

智能驾驶 车牌检测和识别(五)《C++实现车牌检测和识别(可实时车牌识别)》

智能驾驶 车牌检测和识别&#xff08;五&#xff09;《C实现车牌检测和识别&#xff08;可实时车牌识别&#xff09;》 目录 智能驾驶 车牌检测和识别&#xff08;五&#xff09;《C实现车牌检测和识别&#xff08;可实时车牌识别&#xff09;》 1. 前言 2. 车牌检测模型&a…

栈与队列——滑动窗口最大值

力扣题目链接 239. 滑动窗口最大值 给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 示例 1&#xff1a; 输入&#xff1a…

CATIA等设计类软件实时渲染流化解决方案

CATIA软件在汽车、航空航天、船舶制造、厂房设计(尤其是钢构厂房)、建筑、通用机械制造等领域&#xff0c;提供3D设计和模拟解决方案。可以帮助企业在产品研发领域缩短开发周期&#xff0c;因此使用非常广泛。但随着技术和设备的发展&#xff0c;CATIA模型不仅仅需要在电脑上进…

活体识别5:论文笔记之FeatherNets

说明 这篇文章是这次比赛的第三名&#xff1a;ChaLearn Face Anti-spoofing Attack Detection ChallengeCVPR2019&#xff0c;此次比赛项目是人脸防欺诈攻击检测。 论文标题&#xff1a;《FeatherNets: Convolutional Neural Networks as Light as Feather for Face Anti-spo…

中科蓝讯读取CSV文件中地址来指定地址段烧录

优势&#xff1a;可不需要通过小牛测控来写码&#xff0c;在烧录的时候直接进行读取文件来写码&#xff0c;可节省小牛测控写码并复位耳机的时间 功能&#xff1a;通过读取外置的 excel 表格里面的配置项&#xff0c;实现对 setting 文件里面的特定配置项的值 进行设置&#…

详解 k8s 中的 RBAC

Kubernetes 主要通过 API Server 对外提供服务&#xff0c;对于这样的系统来说&#xff0c;如果不加以安全限制&#xff0c;那么可能导致请求被滥用&#xff0c;甚至导致整个集群崩塌。 Kubernetes 中提供了良好的多租户认证管理机制&#xff0c;RBAC正式其中重要的一个&#…

Linux驱动开发基础__异步通知

目录 1 适用场景 2 使用流程 3 驱动编程 4 应用编程 5 代码 5.1 gpio_key_drv.c 5.2 button_test.c 5.3 Makefile 6 异步通知机制内核代码详解 1 适用场景 在前面引入中断时&#xff0c;我们曾经举过一个例子&#xff1a; 妈妈怎么知道卧室里小孩醒了&#xff1f; 异…

【深度学习】U-Net和FCN具体分析

FCN 相比于普通分类网络而言:FCN把后面几个全连接都换成卷积,这样就可以获得一张2维的feature map,后接softmax获得每个像素点的分类信息,从而解决了像素级分割问题。 整个FCN网络基本原理如图5**(只是原理示意图)**: image经过多个conv和+一个max pooling变为pool1 f…

SpringCloud_Alibaba Sentinel实现熔断与限流

目录一、Sentinel介绍1.官网2.是什么3.能干嘛4.去哪下5.怎么玩二、安装Sentinel控制台1.sentinel组件由2部分组成2.安装步骤三、初始化演示工程1.启动Nacos8848成功2.案例3.启动Sentinel80804.启动微服务84015.启动8401微服务后查看sentienl控制台四、流控规则1.基本介绍2.流控…

计算机网络 | 网络层知识点期末汇总【还不赶紧收藏】

看不完就慢慢看&#xff0c;扎实掌握&#x1f44a;一、网络层的几个重要概念1、互联网设计思路2、虚电路与数据报服务3、网络层的两个层面二、网际协议 IP1、配套协议2、互连虚拟网络3、IP地址&#xff08;1&#xff09;IP 地址及其表示方法&#xff08;2&#xff09;分类的 IP…

基于 PyTorch 的目标检测和跟踪(无敌版)

一个不知名大学生&#xff0c;江湖人称菜狗 original author: jacky Li Email : 3435673055qq.com Time of completion&#xff1a;2023.2.1 Last edited: 2023.2.1 目录 图像中的目标检测 视频中的目标跟踪 作者有言 在文章《基于 PyTorch 的图像分类器》中&#xff0c;介绍…

网卡ID简要说明

一、概述 网卡ID标识着网卡的具体类型&#xff0c;由五个ID共同确认。根据这五个ID可以在公示网站查到具体的网卡型号。 1. Class id (1) 区分不同的PCI(外设)设备 (2) 网卡类型是&#xff1a;0200 (3) 查询网址&#xff1a;http://pci-ids.ucw.cz/read/PD 2. Vendor id: …