Java集合框架:优先级队列、PriorityQueue详解

news2024/9/21 4:37:03

目录

一、优先级队列介绍

1. 什么是大根堆(大堆)和小根堆(小堆)

2. 堆的性质

二、堆的创建

1. 向下调整建堆

向下调整算法代码实现:

2. 创建大根堆

三、堆的插入和删除(向上调整算法)

1. 堆的插入

2. 堆中插入元素代码实现  

3. 堆的删除

堆的删除的步骤

3. 堆的删除代码实现

四、堆的模拟实现优先级队列

五、常用接口:PriorityQueue 的介绍

1.  介绍PriorityQueue类

2. PriorityQueue的构造方法

 构造方法使用的演示

 3. PriorityQueue底层源码详解

4. 如何将标准库中的PriorityQueue(小根堆)变成大根堆

  代码实现

  解释

六、优先级队列涉及到的TopK问题

1. 找前K个最大的元素 :oj题链接: 寻找第K大_牛客题霸_牛客网

    思路

    代码实现

2. 找前K个最小的元素

    思路

    代码实现


前言

     上一篇文章已经介绍过队列和Java集合框架中的Queue,队列是一种先进先出的数据结构,但有些情况下操作的数据带有优先级,一般出队列时,可能需要优先级高的元素先出队列,此时,就又引出了另一种关于队列的数据结构,优先级队列。

     在上述场景下,数据结构 应该提供两个基本操作,一个时返回最高优先级对象,一个是添加新的对象,此时这种数据结构就是优先级队列。

一、优先级队列介绍

 

1. 什么是大根堆(大堆)和小根堆(小堆)

    堆的本质就是一颗完全二叉树,如上图所示;用顺序存储的方式来进行存储(如果是非完全二叉树,不宜采用顺序方式来存储数据,此时会有数组空间的浪费)。

大根堆   如果一组数据集合中的所有的元素按照完全二叉树的顺序存储方式来进行存储,并且根节点都大于左右孩子节点,此时这个就称作大根堆。
小根堆和大根堆类似,本质也是用顺序存储的方式存储的一颗二叉树,并且根节点小于左右孩子节点,此时称作这个堆为小根堆。

     而优先级队列的本质就是一个大根堆或者小根堆。

2. 堆的性质

堆中的某个节点的值总是不大于或者不小于其父亲节点的值。
堆总是一颗完全二叉树。

二、堆的创建

1. 向下调整建堆

    以小根堆为例,首先向下调整是从最后一颗子树的根节点开始进行调整,如下图:

向下调整算法代码实现:

    注:此时如果是一个需要向下调整很多步才能建好的堆,如何才能保证这个堆调整结束了呢?

就需要每颗子树的位置不能大于顺序存储(数组)的长度。

    时间复杂度:logN --> 最坏的情况就是一直从最后一颗子树的根节点一直调整到二叉树的根节点,此时调整的就是树的高度

    思路:首先要知道最后一颗子树亲节点和孩子节点,才能向下调整,最后一颗子树的叶子节点就是数组长度-1,其父亲节点就是 (孩子节点-1)/ 2。找到之后进行比较,以小根堆为例:先比较左右孩子谁最小(因为父亲节点要比他俩都小),然后再和父亲节点进行比较,看需否需要交换位置进行向下调整。

/*parent:每棵树的根节点
    * len:每颗子树调整的结束位置  不能大于len(这里的参数传过来的是usedSize)*/
    private void shiftDown(int parent, int len) {
        int child = 2*parent + 1;
        //1.必须保证有左孩子
        while (child < len) {
            //child+1 < len是为了必须保证有右孩子
            if (child+1 < len && elem[child] < elem[child + 1]) {
                child++;
            }
            if (elem[parent] < elem[child]) {
                int tmp = elem[parent];
                elem[parent] = elem[child];
                elem[child] = tmp;
                //此时只能保证局部是大根堆,但是整体还没有调整结束
                parent = child;
                child = parent*2 + 1;//child继续是parent的左孩子
            }else {
                break;//说明此时已经是大根堆
            }
        }
    }

2. 创建大根堆

     时间复杂度:O(N)(此时计算时间复杂度是用到了错位相减法和求节点个数的公式来推导的,此处就不进行介绍了)

    思路:遍历数组中的元素,每次进行比较的时候都要进行向下调整,看是否当前的堆满足大根堆或者小根堆的要求,最后数组中的元素遍历完了之后,也就是一颗大根堆了。

/*建堆的时间复杂度:O(n)(用到错位相减法和求节点个数的公式来推导的)*/
    public void createHeap() {
        //从最后一个子树的根节点开始进行调整
        /*(useSized-2)/2一直孩子节点,推导父亲节点,0下标这棵树也需要进行调整
        * parent--是因为从最后一个子树的根节点的下标开始往前走*/
        for (int parent = (useSized-2)/2; parent >= 0; parent--) {
            /*这里第二个参数是usedSize是因为每次调整之后程序如何才能知道此时调整
            * 应该结束了,当定义的孩子下标往下走的时候,发现下标值超过了usedSize
            * 此时就说明没有这个孩子节点,此时调整结束*/
            shiftDown(parent,useSized);//从每颗子树向下调整
        }
    }
    /*parent:每棵树的根节点
    * len:每颗子树调整的结束位置  不能大于len(这里的参数传过来的是usedSize)*/
    private void shiftDown(int parent, int len) {
        int child = 2*parent + 1;
        //1.必须保证有左孩子
        while (child < len) {
            //child+1 < len是为了必须保证有右孩子
            if (child+1 < len && elem[child] < elem[child + 1]) {
                child++;
            }
            if (elem[parent] < elem[child]) {
                int tmp = elem[parent];
                elem[parent] = elem[child];
                elem[child] = tmp;
                //此时只能保证局部是大根堆,但是整体还没有调整结束
                parent = child;
                child = parent*2 + 1;//child继续是parent的左孩子
            }else {
                break;//说明此时已经是大根堆
            }
        }
    }

三、堆的插入和删除(向上调整算法)

1. 堆的插入

(1)先将元素放入到堆的最后一个节点的位置(也就是数组的有效元素的最后的一个位置)注:此时空间不够时需要进行扩容。
(2)将最后新插入的节点向上调整,直到满足堆的性质

    如上图所示:此时的调整算法称为向上调整算法,是从最后一个叶子节点开始向上调整,上图是建立一个小根堆,此时最后一个节点 10 不满足小根堆的性质,此时直接和父亲节点进行比较,然后交换,之后一路向上,和父亲节点一直进行比较,最后一直调整到根节点。

2. 堆中插入元素代码实现  

           注:

 (1)此时数组放满之后要进行扩容。
 (2)在判断何时才能向上调整结束的条件时,此时要考虑到根节点可能也是需要进行调整的,所以结束条件就是孩子节点 > 0 时(此时父亲节点下标已经是负数了),向上调整结束。
//插入元素    时间复杂度:O(logN) 最大调整树的高度
    public void offer(int val) {
        if (isFull()) {
            //2倍扩容
            elem = Arrays.copyOf(this.elem,2*this.elem.length);
        }
        this.elem[useSized] = val;
        useSized++;
        //然后想办法重新调整为大根堆
        shiftUp(useSized - 1);//这里参数传的是下标
    }
    //向上调整算法:
    private void shiftUp(int child) {
        int parent = (child - 1) / 2;
        while (child > 0) {//此时0下标的位置也是需要调整的
            //但是此时不能是parent > 0,parent为0的时候还没有调整0下标位置的节点
            if (elem[child] > elem[parent]) {
                int tmp = elem[child];
                elem[child] =  elem[parent];
                elem[parent] = tmp;
                //此时还是只是局部是大根堆
                child = parent;
                parent = (child-1) / 2;
            }else {
                break;
            }
        }
    }
    private boolean isFull() {
        return useSized == elem.length;
    }

3. 堆的删除

    堆的删除的步骤:

1. 将堆顶元素和堆中的最后一个元素进行交换。

2. 将堆中有效数据减少一个。
3. 对堆顶元素进行向下调整。

    思路:删除的元素一定在大根堆的最后一个位置,也就是数组的最后一个位置;而且删除的元素只能是堆顶元素,所以首先堆顶元素和最后一个叶子节点交换位置,然后删除最后一个位置的元素,有效元素个数 - 1。

3. 堆的删除代码实现

public int pop () {
        if (isEmpty()) return -1;
        //交换堆顶和最后一个位置的元素
        int tmp = elem[0];
        elem[0] = elem[useSized - 1];
        elem[useSized - 1] = tmp;
        useSized--;
        //保证它仍然是一个大根堆
        shiftDown(0,useSized);
        return tmp;//tmp就是删除的元素
    }
/*parent:每棵树的根节点
    * len:每颗子树调整的结束位置  不能大于len(这里的参数传过来的是usedSize)*/
    private void shiftDown(int parent, int len) {
        int child = 2*parent + 1;
        //1.必须保证有左孩子
        while (child < len) {
            //child+1 < len是为了必须保证有右孩子
            if (child+1 < len && elem[child] < elem[child + 1]) {
                child++;
            }
            if (elem[parent] < elem[child]) {
                int tmp = elem[parent];
                elem[parent] = elem[child];
                elem[child] = tmp;
                //此时只能保证局部是大根堆,但是整体还没有调整结束
                parent = child;
                child = parent*2 + 1;//child继续是parent的左孩子
            }else {
                break;//说明此时已经是大根堆
            }
        }
    }

四、堆的模拟实现优先级队列

     Java 集合框架中 PriorityQueue 的底层就是一个小根堆,所以这部分代码和底层的源码大概意思是差不多的。

public class TextHeap {
    public int[] elem;
    public int useSized;
    public static final int DEFAULT_SIZE = 10;

    public TextHeap() {
        elem = new int[DEFAULT_SIZE];
    }

    public void initElem(int[] array) {
        for (int i = 0; i < array.length; i++) {
            elem[i] = array[i];
            useSized++;
        }
    }
    /*建堆的时间复杂度:O(n)(用到错位相减法和求节点个数的公式来推导的)*/
    public void createHeap() {
        //从最后一个子树的根节点开始进行调整
        /*(useSized-2)/2一直孩子节点,推导父亲节点,0下标这棵树也需要进行调整
        * parent--是因为从最后一个子树的根节点的下标开始往前走*/
        for (int parent = (useSized-2)/2; parent >= 0; parent--) {
            /*这里第二个参数是usedSize是因为每次调整之后程序如何才能知道此时调整
            * 应该结束了,当定义的孩子下标往下走的时候,发现下标值超过了usedSize
            * 此时就说明没有这个孩子节点,此时调整结束*/
            shiftDown(parent,useSized);//从每颗子树向下调整
        }
    }
    /*parent:每棵树的根节点
    * len:每颗子树调整的结束位置  不能大于len(这里的参数传过来的是usedSize)*/
    private void shiftDown(int parent, int len) {
        int child = 2*parent + 1;
        //1.必须保证有左孩子
        while (child < len) {
            //child+1 < len是为了必须保证有右孩子
            if (child+1 < len && elem[child] < elem[child + 1]) {
                child++;
            }
            if (elem[parent] < elem[child]) {
                int tmp = elem[parent];
                elem[parent] = elem[child];
                elem[child] = tmp;
                //此时只能保证局部是大根堆,但是整体还没有调整结束
                parent = child;
                child = parent*2 + 1;//child继续是parent的左孩子
            }else {
                break;//说明此时已经是大根堆
            }
        }
    }
    //插入元素    时间复杂度:O(logN) 最大调整树的高度
    public void offer(int val) {
        if (isFull()) {
            //2倍扩容
            elem = Arrays.copyOf(this.elem,2*this.elem.length);
        }
        this.elem[useSized] = val;
        useSized++;
        //然后想办法重新调整为大根堆
        shiftUp(useSized - 1);//这里参数传的是下标
    }
    //向上调整算法:
    private void shiftUp(int child) {
        int parent = (child - 1) / 2;
        while (child > 0) {//此时0下标的位置也是需要调整的
            //但是此时不能是parent > 0,parent为0的时候还没有调整0下标位置的节点
            if (elem[child] > elem[parent]) {
                int tmp = elem[child];
                elem[child] =  elem[parent];
                elem[parent] = tmp;
                //此时还是只是局部是大根堆
                child = parent;
                parent = (child-1) / 2;
            }else {
                break;
            }
        }
    }
    private boolean isFull() {
        return useSized == elem.length;
    }
    //删除堆中的元素(一定只能删除堆顶元素)
    public int pop () {
        if (isEmpty()) return -1;
        //交换堆顶和最后一个位置的元素
        int tmp = elem[0];
        elem[0] = elem[useSized - 1];
        elem[useSized - 1] = tmp;
        useSized--;
        //保证它仍然是一个大根堆
        shiftDown(0,useSized);
        return tmp;//tmp就是删除的元素
    }
    public boolean isEmpty() {
        return useSized == 0;
    }
    //查看堆顶元素
    public int peek() {
        if (isFull()) return -1;
        return elem[0];
    }
}

五、常用接口:PriorityQueue 的介绍(主要介绍源码中是如何实现小根堆以及如何将底层的小根堆建立成一个大根堆)

1.  介绍PriorityQueue类

 

     PriorityQueue类继承了Queue接口,所以此时的PriorityQueue接口一定是重写了Queue接口的方法,这里的方法应该比Queue接口中的方法多。

2. PriorityQueue的构造方法

 构造方法使用的演示:

class IntCmp implements Comparator<Integer> {
    //此时底层的优先级队列就从一个小根堆变成了一个大根堆
    @Override
    public int compare(Integer o1, Integer o2) {
//        return o2 - o1;
        return o2.compareTo(o1);
    }
}
public static void main2(String[] args) {
        //堆(优先级队列) 标准库中的PriorityQueue底层是一个小堆
        //如果自己实现了比较器,传一个比较器的参数,此时就是变成了大根堆
        PriorityQueue<Integer> queue = new PriorityQueue<>(new IntCmp());//传入一个比较器
        queue.offer(30);
        queue.offer(20);
        queue.offer(3);
        System.out.println(queue.poll());
        System.out.println(queue.poll());
        System.out.println(queue.poll());
    }
public static void main(String[] args) {
       //传入一个实现了Collection接口的list集合
       ArrayList<Integer> list = new ArrayList<>();
       PriorityQueue<Integer> queue = new PriorityQueue<>(list);
       //参数也可以指定一个默认容量
       PriorityQueue<Integer> queue1 = new PriorityQueue<>(222);
       
}

 3. PriorityQueue底层源码详解

PriorityQueue minHeap = new PriorityQueue<>();
minHeap.offer(10);
        minHeap.offer(10);
        minHeap.offer(20);
        System.out.println(minHeap.poll());
        System.out.println(minHeap.poll());
        System.out.println(minHeap.peek());

    当我们什么参数都没给时,我们可以看下PriorityQueue的源码做了啥:this关键字就是谁调用这个minHeap这个引用谁就是this;可以看到给了一个初始容量11,然后传入了一个空的比较器,

    综上图所述 源码的详解,也就是说,当第二次offer元素的时候,如果比第一个offer的元素大,就直接把第二个元素放到数组1下标的位置,第一个元素还是在数组0下标的位置,不用进行交换。

    如下图所示:

    综上所述,PriorityQueue的底层是一个小根堆,

    注:不是建堆的时候就一定要用向下调整,在插入和删除元素的时候就一定用向上调整算法,用哪种算法都是可以的。

4. 如何将标准库中的PriorityQueue(小根堆)变成大根堆

    代码实现:

PriorityQueue<Integer> maxHeap = new PriorityQueue<>(k, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2.compareTo(o1);
            }
        });

  解释:

     可以看到刚才源码中默认的比较器比较的方式是: return o1.compareTo(o2); 也就是第一个元素和第二个元素进行比较,如果反过来比较,用第二个元素和第一个元素进行比较,此时的比较器就会正好相反,如果第二个元素大于第一个元素返回一个正数,我们可以看下刚才向上调整的源码:    也就是key 和 e 正好反过来,如果第一次offer一个10,第二次offer一个20,现在key就是20了,e就是10了,if 条件是成立的,也就是10和20 不用交换位置,此时就是一个大根堆了。

private void siftUpComparable(int k, E x) {
        Comparable<? super E> key = (Comparable<? super E>) x;
        while (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;
    }

六、优先级队列涉及到的TopK问题

1. 找前K个最大的元素 :oj题链接: 寻找第K大_牛客题霸_牛客网

    思路:

   如果是整体建立一个大根堆(此时堆顶元素最大,就弹出,但是这种方法时间复杂度很高)。

   所以另一种思路就是:如果找前K大的元素 -->将数组中前K个元素建立一个小根堆,然后用数组中剩下的元素和堆定元素进行比较,然后重新调整为大根堆。此时如果比堆顶元素大(说明当前堆中的K个元素一定不是最大的),就更新堆顶元素的值,最后比较完数组中剩下的元素,此时堆中就是前K个最大的元素。

     代码实现:

public int findKth (int[] arr, int n, int K) {
        PriorityQueue<Integer> minHeap = new PriorityQueue<>(K);
        for (int i = 0; i < arr.length; i++) {
            if (i < K) {
                minHeap.offer(arr[i]);//入堆
            } else {
                int val = arr[i];
                if (val > minHeap.peek()) {
                    minHeap.poll();
                    minHeap.offer(arr[i]);
                }
            }
        }
        return minHeap.peek();
    }

2. 找前K个最小的元素

    思路:

    和寻找前K个最大的数据是一样的;如果是找前K个最小的元素 ---> 将数组的前K个元素建立一个大根堆,然后用堆顶元素和数组中剩下的元素进行比较,如果堆顶元素比数组中某一个元素小 此时就更新堆顶元素的值,然后重新调整为小根堆。最后堆中的元素就是前K个最小的元素。

     代码实现:

/*时间复杂度:O(N + O(K * logN)),建堆的时间复杂度是O(N),弹出k个元素每次弹出
    * 都需要向上调整,时间复杂度:O(K * logN)*/
    public int[] smallestK(int[] arr, int k) {
        //1.建立一个小根堆
        PriorityQueue<Integer> minHeap = new PriorityQueue<>();
        //2.取出数组中的每一个元素放到堆中
        for (int i = 0; i < arr.length; i++) {
            minHeap.offer(arr[i]);
        }
        int[] tmp = new int[k];
        //3.弹出k个元素放进数组中
        for (int i = 0; i < k; i++) {
            tmp[i] = minHeap.poll();
        }
        return tmp;
    }

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

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

相关文章

Linux性能瓶颈分析之TOP指标分析

Linux性能瓶颈分析之TOP指标分析 文章目录 Linux性能瓶颈分析之TOP指标分析一、查看CPU二、监控CPU总结 一、查看CPU 1.查看cpu基础信息 lscpu2.查看cpu详细信息 cat /proc/cpuinfo3.统计cpu信息 cat /proc/cpuinfo |grep "physical id" |sort |uniq |wc -l 查看…

骨传导耳机可以长期佩戴吗,分享几款舒适度极高的骨传导耳机

近几年有一种新型传播方式的耳机&#xff0c;将声音转化为振动&#xff0c;从而让我们的听觉神经感知到。这种声音传播方式叫做"骨传导"&#xff0c;所以叫做骨传导耳机。因为它不需要通过耳膜进行传播声音&#xff0c;所以可以让耳朵在不接触外界的情况下听到声音。…

B051-cms06-退出 回车登录 登录拦截 记住我 SVN

目录 注销功能实现1.找到退出按钮修改请求路径2.后端删除Session并跳转到登录页面 回车登录功能登陆拦截1.编写登录拦截器2.配置拦截器 记住我后端实现页面实现 取消记住我后端实现页面实现 注销功能实现 1.找到退出按钮修改请求路径 header.jsp <% page language"j…

翻过那座山——Jenkins编译发布web程序(.net framework web application)

&#x1f4e2;欢迎点赞 &#xff1a;&#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff0c;赐人玫瑰&#xff0c;手留余香&#xff01;&#x1f4e2;本文作者&#xff1a;由webmote 原创&#x1f4e2;作者格言&#xff1a;新的征程&#xff0c;我们面对的不是…

无法登录github解决方法

140.82.113.4 github.com 199.232.69.194 github.global.ssl.fastly.net 185.199.108.153 assets-cdn.github.com 185.199.109.153 assets-cdn.github.com 185.199.110.153 assets-cdn.github.com 185.199.111.153 assets-cdn.github.com 注意以管理员方式运行notepad才能保存 …

Github上标星40K的Java面试笔记,解决95%以上的Java面试

该文档在Github上收获40Kstar的Java面试神技&#xff08;这赞数&#xff0c;质量多高就不用我多说了吧&#xff09;非常全面&#xff0c;包涵Java基础、Java集合、JavaWeb、Java异常、OOP、IO与NIO、反射、注解、多线程、JVM、MySQL、MongoDB、Spring全家桶、计算机网络、分布式…

集成学习(ensemble learning)应如何入门?

集成学习算法之间的主要区别在于以下3个方面: 提供给个体学习器的训练数据不同; 产生个体学习器的过程不同; 学习结果的组合方式不同&#xff0c;从这三个方面去学。 多样性 数据样本多样性&#xff1a;产生数据多样性的方法主要有3种: 输入样本扰动; 输入属性扰动; 输出表示…

掌握Python的常用模块pandas

Pandas 简介 Pandas 是 Python 的核心数据分析支持库&#xff0c;提供了快速、灵活、明确的数据结构&#xff0c;旨在简单、直观地处理关系型、标记型数据。Pandas 的目标是成为 Python 数据分析实践与实战的必备高级工具&#xff0c;其长远目标是成为最强大、最灵活、可以支持…

10 编码转换问题

文章目录 字符编码问题编码转换问题ANSI转UnicodeUnicode转ANSIUtf8转 ANSIutf8 转UnicodeANSI 转UTF-8Unicode 转 UTF-8 全部代码 字符编码问题 Windows API 函数 MessageBoxA:MessageBox 内部实现&#xff0c;字符串编码(ANSI)转换成了Unicode,在调用MessageboxW MessageBox:…

助推RASP2.0 领航ADR新赛道 边界无限打造应用安全防护新范式

2023年以来&#xff0c;数字安全一词多次被提及&#xff0c;成为了我们生活和工作中的一项重要课题。近日&#xff0c;由数世咨询、CIO时代联合主办&#xff0c;新基建创新研究院作为智库支持的“第三届数字安全大会”在北京隆重举办&#xff0c;本届大会以“风险驱动”为主题&…

第26章 uView 内置路由使用注意事项

1 uView 内置路由不支持通过“localhost”域名直接获取数据。 在前后分离开发中“axios” 路由支持使用“localhost”域名或IP地址获取后端的数据&#xff0c;所以不管是IIS部署还是后端调试通过“axios” 路由都能获取数据&#xff0c;对于.NetCore的前后端分离开发来说“axio…

python爬虫之Scrapy框架--保存图片(详解)

目录 Scrapy 使用ImagePipeline 保存图片 使用图片管道 具体步骤 安装相关的依赖库 创建Scrapy项目 配置settings.py 定义Item 编写Spider 运行Spider Scrapy 自定义ImagePipeline 自定义图片管道 Scrapy 使用ImagePipeline 保存图片 Scrapy提供了一个 ImagePipelin…

使用原生AJAX请求数据

一、什么是AJAX AJAX英文全称 Asynchronous Javascript And XML&#xff08;异步的JavaScript和XML&#xff09;&#xff0c;是指一种创建交互式网页应用的网页开发技术&#xff0c;用于浏览器和服务器之间进行数据交互。AJAX在浏览器与Web服务器之间使用异步数据传输&#xf…

【Jetpack】Navigation 导航组件 ③ ( 为 Navigation Graph 页面跳转 action 添加跳转动画 )

文章目录 一、为 Navigation Graph 添加跳转动画1、进入 Navigation Graph 配置的 Design 模式2、选中 action 跳转3、为 action 跳转设置 enterAnim 进入动画4、为 action 跳转设置 exitAnim 退出动画5、通过代码为 action 跳转设置进入 / 退出动画6、执行效果 代码地址 : CS…

DBeaver连接mysql时报错com.mysql.cj.jdbc.Driver的解决方法【修改驱动下载的maven地址和重新下载驱动】

文章目录 说明解决方法1、打开DBeaver点击窗口-->窗口-->首选项-->链接-->点击驱动-->Maven-->添加2、删除已有的驱动3、重新创建mysql链接 说明 网上下载了最新版本的DBeaver软件&#xff0c;但是链接mysql的时候驱动下载失败&#xff0c;所以就报下面错误…

Cisco Secure Client 5.0.03072 (macOS, Linux, Windows iOS, Andrord)

Cisco Secure Client 5.0.03072 (macOS, Linux, Windows & iOS, Andrord) 思科安全客户端&#xff08;包括 AnyConnect&#xff09; 请访问原文链接&#xff1a;https://sysin.org/blog/cisco-secure-client-5/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出…

半小时摸清一个行业:ChatGPT+麦肯锡关键词法

大家好&#xff0c;我是可夫小子&#xff0c;关注AIGC、读书和自媒体。 说实话&#xff0c;在行业分析中「关键词分析法」最早见诸于冯唐&#xff0c;并非是麦肯锡公司的方法论。 冯唐作为麦肯锡前合伙人&#xff0c;讲了快速掌握一个行业的基本方法&#xff0c;一共有三个看似…

ChatGPT最新版多功能批量写作工具揭秘

随着人工智能技术的不断进步&#xff0c;自然语言处理领域也取得了巨大的突破。其中&#xff0c;ChatGPT作为一款强大的多功能批量写作工具&#xff0c;备受关注。它的最新版本将用户体验提升到了一个新的高度。本文将从多个方面详细阐述ChatGPT最新版的功能和优势。 自动摘要功…

进程与线程的区别,特点比较区别与联系

进程与线程的区别、关系 定义关系比较对于系统调度来说&#xff1a;从拥有资源来说&#xff1a;并发性上下文&#xff1a;系统开销使用多线程的主要目的&#xff1a; 定义 进程&#xff1a;进程是程序执行的实例&#xff0c;包括程序计数器和寄存器和变量的当前值 进程依赖于程…

漏洞复现-fastjson1.2.24-RCE

0x00 实验环境 攻击机&#xff1a;Win 10、Win Server2012 R2&#xff08;公网环境&#xff0c;恶意java文件所在服务器&#xff09; 靶机也可作为攻击机&#xff1a;Ubuntu18 &#xff08;公网环境&#xff0c;docker搭建的vulhub靶场&#xff09;&#xff08;兼顾反弹shell…