0203优先级下的调度问题_环_拓扑排序-有向图-数据结构和算法(Java)

1 概述

在和有向图相关的实际应用中,有向环特别的重要。在实际应用中,一般只会重点关注其中的一小部分,或者只想知道它们是否存在。

2 调度问题

一种应用广泛的模型是给定一组任务并安排它们的执行顺序,限制条件是这些任务的执行方法和起始时间,也可能是任务的时耗即消耗的其他资源。最重要的一种限制条件叫做优先级限制。

优先级限制下的调度。 给定一组需要完成的任务,以及一组关于任务完成的先后次序的优先级限制。在满足限制条件的前提下如何安排并完成所有的任务?

以一个正在安排课程的大学生为例,有些课程是其他课程的先导课程,如下图2-1所示:

在这里插入图片描述

顶点对应任务,有向边对应优先级顺序,使用整数位顶点的编号的标准模型来表示这个示例,如下图2-2所示:

在这里插入图片描述

在有向图中,优先级限制下的调度问题等价于下面这个基本问题。

拓扑排序。给定一幅有向图,将所有的顶点排序,使得所有的有向边均从排在前面的元素指向排在后面的元素。(或者说明无法做到这一点)

上面大学生课程示例对应的拓扑排序,如下图2-3所示:

在这里插入图片描述

2 有向图中的环

2.1 概念

如果一个有优先级限制的问题中存在有向环,那么这个问题肯定是无解的。

有向环检测。给定的有向图中包含有向环吗?如果有,按照路径的方向从某个顶点返回自己来找到环上的的所有顶点。

2.2 算法

  • 基于深度优先搜索由我们维护的栈表示正式“当前”正在遍历的所有有向路径;
  • 一旦我们找到一条有向边v->w且w已存在于栈中,就找到一个环;
    • 因为栈表示的是一条由w到v的有向路径,而v->w正好补全了这个环。
  • 如果没有找到这样的边,说明这幅有向图上无环的。

2.3 实现

  • API 如下表2.3-1所示:
public classDirectedCycle
DirectedCycle(Digraph digraph)选择有向环的构造函数
public booleanhascycle()是否含有有向环
public Iterable<Integer>cycle()有向环中所有顶点;没有返回null

非递归实现如下代码2.3-1所示:

package com.gaogzhen.datastructure.graph.directed;

import com.gaogzhen.datastructure.graph.undirected.Entry;
import com.gaogzhen.datastructure.stack.Stack;
import edu.princeton.cs.algs4.Digraph;

import java.util.Iterator;

/**
 *  检测有向环
 * @author gaogzhen
 */
public class DirectedCycle {

    /**
     * 标记
     */
    private boolean[] marked;

    /**
     * 指向起点的有向路径
     */
    private int[] edgeTo;

    /**
     * 当前栈上顶点
     */
    private boolean[] onStack;

    /**
     * 有向环
     */
    private Stack<Integer> cycle;

    /**
     * 检测有向环
     * @param digraph 有向图
     */
    public DirectedCycle(Digraph digraph) {
        marked  = new boolean[digraph.V()];
        onStack = new boolean[digraph.V()];
        edgeTo  = new int[digraph.V()];
        for (int v = 0; v < digraph.V(); v++) {
            if (!marked[v] && cycle == null) {
                dfs(digraph, v);
            }
        }
    }

    /**
     * 深度优先检测有向环
     * @param digraph   有向图
     * @param s 起点
     */
    private void dfs(Digraph digraph, int s) {
        Stack<Entry<Integer, Iterator<Integer>>> path = new Stack<>();
        // marked[v] = true;
        if (!marked[s]) {
            // 键值对起点-起点对应邻接表迭代器压入栈中
            marked[s] = true;
            onStack[s] = true;
            Iterable<Integer> iterable = digraph.adj(s);
            Iterator<Integer> it;
            if (iterable != null && (it = iterable.iterator()) != null){
                path.push(new Entry<>(s, it));
            }
        }
        deepLevel:
        while (!path.isEmpty()) {
            Entry<Integer, Iterator<Integer>> entry = path.pop();
            int x;
            Iterator<Integer> it = entry.getValue();
            Integer f = entry.getKey();
            while (it.hasNext()) {
                // 当前顶点对应的邻接表迭代器还有元素,获取下一个元素
                x = it.next();
                if (cycle != null) {
                    return;
                } else if (!marked[x]) {
                    // 顶点未被标记,标记顶点且标记路径x->f
                    // f是x所在邻接表对应的顶点
                    marked[x] = true;
                    onStack[x] = true;
                    edgeTo[x] = f;
                   // if (it.hasNext()) {
                    // 邻接表迭代器还有元素,重新压入栈
                    path.push(entry);
                   // }
                    // 按照深度优先原则,把新标记顶点对应的键值对压入栈中,在下次循环时优先访问
                    Iterable<Integer> iterable = digraph.adj(x);
                    if (iterable != null && (it = iterable.iterator()) != null){
                        path.push(new Entry<>(x, it));
                    }
                    continue deepLevel;
                } else if (onStack[x]) {
                    // 存在有向环
                    // 遍历有向路径,构建有向环
                    cycle = new Stack<>();
                    for (int i = f; i != x ; i = edgeTo[i]) {
                        cycle.push(i);
                    }
                    cycle.push(x);
                    cycle.push(f);
                }
            }
            onStack[f] = false;

        }
    }

    /**
     * 是否存在有向环
     * @return {@code true} 存在有向环, {@code false} 否则
     */
    public boolean hasCycle() {
        return cycle != null;
    }

    /**
     * 返回有向环
     */
    public Iterable<Integer> cycle() {
        return cycle;
    }


    /**
     * 证明确实有有向环
     * @return {@code true} 确实存在一个有向环, {@code false}否则
     */
    private boolean check() {

        if (hasCycle()) {
            // verify cycle
            int first = -1, last = -1;
            for (int v : cycle()) {
                if (first == -1) {
                    first = v;
                }
                last = v;
            }
            if (first != last) {
                System.err.printf("cycle begins with %d and ends with %d\n", first, last);
                return false;
            }
        }


        return true;
    }
}

说明:

  • onStack[]表示当前在栈上的顶点,首次访问设置true;当顶点对应的邻接表访问完毕,该结点会退出当前栈,设置为false。
  • continue deepLevel;我们是实用非递归的深度优先搜索算法,当邻接表有未访问的顶点时,表示我们需要优先访问下一层的顶点,但是当前顶点不退出当前栈。
  • // if (it.hasNext()) { 在之前的代码中我们这里放开,表示当前邻接表没有元素,不在放入栈中;但是这里注释掉,因为我们需要外围的while循环判断是否邻接表已经遍历完毕,设置onStack[]对应顶点为false。按照逻辑,不能出现有下层结点在栈中而父结点退出栈的情况。

2.4 测试

测试代码2.4-1如下所示:

    public static void testDirectedCycle() {
        String path = System.getProperty("user.dir") + File.separator + "asserts/tinyDAG.txt";
        In in = new In(path);
        Digraph digraph = new Digraph(in);
        System.out.println(digraph.adj(10));
        DirectedCycle cycle = new DirectedCycle(digraph);
        System.out.println(cycle);
        int v = 0;
        System.out.println(cycle.hasCycle());
        System.out.println(cycle.cycle());
    }

测试用有向图2数据在代码仓库中有,结构如下2.4-1所示

在这里插入图片描述

测试结果如下2.4-1所示:

com.gaogzhen.datastructure.graph.directed.DirectedCycle@3764951d
true
[7, 6, 9, 10, 7]

命题E。当且仅当一幅有向图时无环图时它才能进行拓扑排序。

证明。当一幅有向图含有一个环时,它就不可能时拓扑排序的。

3 顶点的深度优先次序

基于深度优先的顶点排序。它的思想时深度优先搜索正好只会访问每个顶点一次。如果将遍历的顶点参数保存在一个数据结构中,遍历这个数据结构就可以访问图中的所有顶点,遍历的顺序取决于数据结构的性质以及在递归(非递归栈)调用之前还是之后进行保存。

典型的应用中,顶点有3种排列顺序:

  • 前序:在递归调用(加入非递归栈)之前将顶点加入队列。
  • 后序:在递归调用(加入非递归栈)之后将顶点加入队列。
  • 逆后序:在递归调用(加入非递归栈)之后将顶点加入栈。

顶点深度优先次序类DepthFirstOrder类,API如下表3-1所示:

public classDepthFirstOrder
DepthFirstOrder(Digraph digraph)深度优先顶点排序构造函数
public Iterable<Integer>pre()深度优先的前序排列
public intpre(int v)顶点v前序排列索引
public Iterable<Integer>post()深度优先的后序排列
public intpost(int v)顶点v后序排列索引
public Iterable<Integer>reversePost()深度优先的逆后序排列

非递归实现代码3-1如下所示:

package com.gaogzhen.datastructure.graph.directed;

import com.gaogzhen.datastructure.graph.undirected.Entry;
import com.gaogzhen.datastructure.stack.Stack;
import edu.princeton.cs.algs4.*;

import java.util.Iterator;

/**
 *  基于深度优先的顶点排序
 * @author gaogzhen
 */
public class DepthFirstOrder {

    /**
     * 顶点已访问标记
     */
    private boolean[] marked;

    /**
     * 基于深度优先的顶点前序排列索引
     */
    private int[] pre;

    /**
     * 基于深度优先的顶点后序排序索引
     */
    private int[] post;

    /**
     * 基于深度优先的顶点前序排列
     */
    private Queue<Integer> preOrder;

    /**
     * 基于深度优先的后序排列
     */
    private Queue<Integer> postOrder;

    /**
     * 当前前序顶点计数
     */
    private int preCounter;

    /**
     * 当前后序顶点计数
     */
    private int postCounter;

    /**
     * 深度优先的顶点排序
     * @param digraph 有向图
     */
    public DepthFirstOrder(Digraph digraph) {
        pre    = new int[digraph.V()];
        post   = new int[digraph.V()];
        postOrder = new Queue<Integer>();
        preOrder  = new Queue<Integer>();
        marked    = new boolean[digraph.V()];
        for (int v = 0; v < digraph.V(); v++) {
            if (!marked[v]) {
                dfs(digraph, v);
            }
        }

        assert check();
    }

    /**
     * 有向图的深度优先顶点排序
     * @param digraph   有向图digraph
     * @param v 起点
     */
    private void dfs(Digraph digraph, int v) {
        Stack<Entry<Integer, Iterator<Integer>>> path = new Stack<>();
        // marked[v] = true;
        if (!marked[v]) {
            // 键值对起点-起点对应邻接表迭代器压入栈中
            marked[v] = true;
            pre[v] = preCounter++;
            preOrder.enqueue(v);
            Iterable<Integer> iterable = digraph.adj(v);
            Iterator<Integer> it;
            if (iterable != null && (it = iterable.iterator()) != null){
                path.push(new Entry<>(v, it));
            }
        }
        // 保证深度优先跳转标记
        nextLevel:
        while (!path.isEmpty()) {
            Entry<Integer, Iterator<Integer>> entry = path.pop();
            int x;
            Iterator<Integer> it = entry.getValue();
            Integer f = entry.getKey();
            while (it.hasNext()) {
                // 当前顶点对应的邻接表迭代器还有元素,获取下一个元素
                x = it.next();
                if (!marked[x]) {
                    // 顶点未被标记,标记顶点且标记路径x->f
                    // f是x所在邻接表对应的顶点
                    marked[x] = true;
                    pre[x] = preCounter++;
                    preOrder.enqueue(x);
                    // if (it.hasNext()) {
                        // 邻接表迭代器还有元素,重新压入栈
                        path.push(entry);
                    // }
                    // 按照深度优先原则,把新标记顶点对应的键值对压入栈中,在下次循环时优先访问
                    Iterable<Integer> iterable = digraph.adj(x);
                    if (iterable != null && (it = iterable.iterator()) != null){
                        path.push(new Entry<>(x, it));
                    }
                    // 保证深度优先:下一层有未访问结点,优先访问下层结点
                    continue nextLevel;
                }
            }

            // 顶点f对应的邻接表访问完毕,后序排列开始记录
            postOrder.enqueue(f);
            post[f] = postCounter++;
        }
    }

    /**
     * 返回指定顶点v在前序排列中的索引
     * @param  v 指定顶点v
     * @return 指定顶点v在前序排列中的索引
     * @throws IllegalArgumentException unless {@code 0 <= v < V}
     */
    public int pre(int v) {
        validateVertex(v);
        return pre[v];
    }

    /**
     * 返回顶点v在后序排列中的索引
     * @param  v 顶点v
     * @return 顶点v在后序排列中的索引
     * @throws IllegalArgumentException unless {@code 0 <= v < V}
     */
    public int post(int v) {
        validateVertex(v);
        return post[v];
    }

    /**
     * 返回顶点的后序排列
     */
    public Iterable<Integer> post() {
        return postOrder;
    }

    /**
     * 返回顶点的前序排列
     */
    public Iterable<Integer> pre() {
        return preOrder;
    }

    /**
     * 返回顶点的逆后序排列
     */
    public Iterable<Integer> reversePost() {
        Stack<Integer> reverse = new Stack<Integer>();
        for (int v : postOrder) {
            reverse.push(v);
        }
        return reverse;
    }


    /**
     * 校验前序和后序排列结果是否和pre(v)与post(v)相等
     * @return {@code true}结果一致;{@code false}有一个不相等
     */
    private boolean check() {

        // check that post(v) is consistent with post()
        int r = 0;
        for (int v : post()) {
            if (post(v) != r) {
                StdOut.println("post(v) and post() inconsistent");
                return false;
            }
            r++;
        }

        // check that pre(v) is consistent with pre()
        r = 0;
        for (int v : pre()) {
            if (pre(v) != r) {
                StdOut.println("pre(v) and pre() inconsistent");
                return false;
            }
            r++;
        }

        return true;
    }

    /**
     * 校验顶点v
     * @param v 顶点v
     */
    private void validateVertex(int v) {
        int V = marked.length;
        if (v < 0 || v >= V) {
            throw new IllegalArgumentException("vertex " + v + " is not between 0 and " + (V-1));
        }
    }

}

测试用有向图数据3-1同之前一样,如下所示:

13
15
2 3
0 6
0 1
2 0
11 12
9 12
9 10
9 11
3 5
8 7
5 4
0 5
6 4
6 9
7 6

测试用有向图如下图3-1所示:

在这里插入图片描述

测试代码如下3-2所示:

public static void testDepthFirstOrder() {
    String path = System.getProperty("user.dir") + File.separator + "asserts/tinyDGO.txt";
    In in = new In(path);
    Digraph digraph = new Digraph(in);
    DepthFirstOrder depthFirstOrder = new DepthFirstOrder(digraph);
    System.out.println(depthFirstOrder);

    System.out.println("前序排列:" + depthFirstOrder.pre());
    System.out.println("后序排列:" + depthFirstOrder.post());
    System.out.println("逆后序排列:" + depthFirstOrder.reversePost());

    int v = 4;
    System.out.println("顶点:" + v + " 前序排列索引 " + depthFirstOrder.pre(v));
    System.out.println("顶点:" + v + " 后序排列索引 " + depthFirstOrder.post(v));
}

测试结果:

后序排列:4 5 1 12 11 10 9 6 0 3 2 7 8 
逆后序排列:[8, 7, 2, 3, 0, 6, 9, 10, 11, 12, 1, 5, 4]
顶点:4 前序排列索引 2
顶点:4 后序排列索引 0

4 拓扑排序

拓扑排序API如下表4-1所示:

public classTopological
Topological(Digraph digraph)拓扑排序的构造函数
public booleanhasOrder()digraph可拓扑排序吗
public Iterable<Integer>order()顶点的拓扑排序
public intrank(int v)顶点v在拓扑排序中的索引

非递归实现代码如下4-1所示:

package com.gaogzhen.datastructure.graph.directed;

import edu.princeton.cs.algs4.Digraph;

/**
 *  拓扑排序
 * @author gaogzhen
 */
public class Topological {

    /**
     * 顶点的拓扑排序
     */
    private Iterable<Integer> order;

    /**
     * 顶点在拓扑排序中索引
     */
    private int[] rank;

    /**
     * 构建有向图digraph拓扑排序
     */
    public Topological(Digraph digraph) {
        DirectedCycle finder = new DirectedCycle(digraph);
        if (!finder.hasCycle()) {
            DepthFirstOrder dfs = new DepthFirstOrder(digraph);
            order = dfs.reversePost();
            rank = new int[digraph.V()];
            int i = 0;
            for (int v : order) {
                rank[v] = i++;
            }
        }
    }

    /**
     * 返回顶点的拓扑排序,没有返回null
     * @return 顶点的拓扑排序,没有返回null
     */
    public Iterable<Integer> order() {
        return order;
    }

    /**
     * 是否可拓扑排序
     * @return {@code true} 可以拓扑排序,同时说明是有向无环图;{@code false}否则
     */
    public boolean hasOrder() {
        return order != null;
    }

    /**
     * 指定顶点v在拓扑排序中索引
     * @param v 指定顶点v
     * @return 顶点v在拓扑排序中索引
     * @throws IllegalArgumentException unless {@code 0 <= v < V}
     */
    public int rank(int v) {
        validateVertex(v);
        if (hasOrder()) {
            return rank[v];
        } else {
            return -1;
        }
    }

    /**
     * 校验顶点v是否索引越界
     * @param v 指定顶点
     */
    private void validateVertex(int v) {
        int V = rank.length;
        if (v < 0 || v >= V) {
            throw new IllegalArgumentException("vertex " + v + " is not between 0 and " + (V-1));
        }
    }
}

以#4中的有向图为例,测试代码如下;

public static void testTopological() {
    String path = System.getProperty("user.dir") + File.separator + "asserts/tinyDGO.txt";
    In in = new In(path);
    Digraph digraph = new Digraph(in);
    Topological topological = new Topological(digraph);
    System.out.println(topological);

    System.out.println("是否可拓扑排序(是否是有向无环图):" + topological.hasOrder());
    System.out.println("拓扑排序:" + topological.order());

    int v = 4;
    System.out.println("顶点:" + v + " 拓扑排列索引 " + topological.rank(v));
}

测试结果:

是否可拓扑排序(是否是有向无环图):true
拓扑排序:[8, 7, 2, 3, 0, 6, 9, 10, 11, 12, 1, 5, 4]
顶点:4 拓扑排列索引 12

命题F。一幅有向无环图的拓扑顺序即为所有顶点的逆后序排列。

证明。对于任意边v->w,在访问v(递归dfs(v))时,下面三种情况比有其一成立。

  • w已经被访问过且已放入队列(w已经被标记)
  • w还没有被访问(未标记),因此v->w会直接或者间接访问w且加入队列,w会在v之前加入队列。
  • w已经被访问但未加入队列。

证明的关键在于,在有向无环图中这种情况时不可能出现的。这是由于栈访问顺序 意味着存在从w到v的路径,但存在v->w则表示存在一个环。

在两种可能的情况中,w都会在v之前加入队列,因此在后序排列中w排在v之前而逆后序中w排在v之后。因此任意一条边v->w都如我们所愿地从排名较前顶点指向排名较后的顶点。

命题G。使用深度优先搜索对有向无环图进行拓扑排序所需的时间和V+E成正比。

证明。由代码可知,第一遍深度优先搜索保证了不存在有向环,第二遍深度优先搜索产生了顶点的逆后序排列。两次搜索都访问了所有的顶点和所有的边。因此所需时间和V+E成正比。

5 任务调度方案

在实际应用中 ,拓扑排序和有向环检测总会一起出现,因为有向环检测是拓扑排序的前提。因此,解决任务调度类应用通常需要以下3步:

  • 指明任务和优先级;
  • 不断检测和去除有向图中的所有环,以确保存在可行方案;
  • 使用拓扑排序解决任务调度问题。

类似地,调度方案的任何变动之后都需要再次检测是否存在环,然后再计算新的调度安排。

结语

如果小伙伴什么问题或者指教,欢迎交流。

❓QQ:806797785

⭐️源代码仓库地址:https://gitee.com/gaogzhen/algorithm

参考链接:

[1][美]Robert Sedgewich,[美]Kevin Wayne著;谢路云译.算法:第4版[M].北京:人民邮电出版社,2012.10.p369-377.

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

机器学习:逻辑回归模型算法原理(附案例实战)

机器学习&#xff1a;逻辑回归模型算法原理 作者&#xff1a;i阿极 作者简介&#xff1a;Python领域新星作者、多项比赛获奖者&#xff1a;博主个人首页 &#x1f60a;&#x1f60a;&#x1f60a;如果觉得文章不错或能帮助到你学习&#xff0c;可以点赞&#x1f44d;收藏&#…

Github学生包申请秒过经验并使用Copilot

写在前面 前提是在校学生&#xff0c;且有学校邮箱&#xff0c;当然你也得有Github账户前往学信网下载 教育部学籍在线验证报告将报告转换成英文版本&#xff0c;我用的是手机夸克自带的拍照翻译功能 具体流程 设置Github个人信息 来到 https://github.com/settings/profil…

如何用Postman做接口自动化测试?没有比这个更详细的了

目录 前言 什么是自动化测试 自动化测试有哪些分类 为什么需要自动化测试 Postman自动化测试演示 1.新建集合 2.新建接口 3.填写自动化测试脚本 4.录入所有接口 5.执行自动化测试 前言 什么是自动化测试 把人对软件的测试行为转化为由机器执行测试行为的一种实践。 …

腾讯Coding平台学习笔记二:自定义团队插件的使用方法

目录一、前言二、系统环境三、工作目标四、流水线设置五、开发工具5.1 教程地址5.2 开发工具程序结构5.3 qciplugin.yml文件5.4 main.py文件六、插件的安装6.1 打包成zip6.2 上传zip包6.3 构建新插件6.4 质量门禁7、流水线设置7.1 添加质量管理阶段节点7.2 添加其它动作八、流水…

cookie和session的原理以及在Servlet中的应用

文章目录简介cookiecookie的实质及实现原理cookie在Servlet的应用sessionsession的实质及实现原理session在Servlet中的应用HttpServletRequest&#xff0c;Session&#xff0c;ServletContext简介 cookie保存在客户端&#xff0c;session保存在服务器端。二者均用于描述会话的…

【第十一届“泰迪杯”数据挖掘挑战赛】B题产品订单的数据分析与需求预测“解题思路“”以及“代码分享”

【第十一届泰迪杯B题产品订单的数据分析与需求预测产品订单的数据分析与需求预测 】第一大问代码分享&#xff08;后续更新LSTMinformer多元预测多变量模型&#xff09; PS: 代码全写有注释&#xff0c;通俗易懂&#xff0c;包看懂&#xff01;&#xff01;&#xff01;&…

RK3568平台开发系列讲解(驱动基础篇)IO 模型的分类

🚀返回专栏总目录 文章目录 一、阻塞 IO二、非阻塞 IO三、IO 多路复用四、信号驱动五、异步 IO沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将针对IO模型进行分类。 假设有这样一个场景,从磁盘中循环读取 100M 的数据并处理,磁盘读取 100M 需要花费 20 秒的…

Transformer在计算机视觉中的应用-VIT、TNT模型

上期介绍了Transformer的结构、特点和作用等方面的知识&#xff0c;回头看下来这一模型并不难&#xff0c;依旧是传统机器翻译模型中常见的seq2seq网络&#xff0c;里面加入了注意力机制&#xff0c;QKV矩阵的运算使得计算并行。 当然&#xff0c;最大的重点不是矩阵运算&…

【数据结构】树的概念

Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法......感兴趣就关注我吧&#xff01;你定不会失望。 &#x1f308;个人主页&#xff1a;主页链接 &#x1f308;算法专栏&#xff1a;专栏链接 我会一直往里填充内容哒&#xff01; &…

网络基础认识

目录 一、计算机网络背景 1.1 网络发展 1.2 "协议"由来 二、网络协议初识 2.1 协议分层 2.2 OSI七层模型 2.3 TCP/IP五层模型 三、网络协议栈 四、数据包封装与分用 五、网络传输基本流程 5.1 同局域网的两台主机通信 5.2 跨网络的两台主机通信 六、网络…

MySQL高级第六篇:数据库性能分析与优化

MySQL高级第六篇&#xff1a;数据库性能分析与优化一、数据库服务器优化步骤概述二、慢查询日志&#xff1a;记录执行慢的SQL1. 开启慢查询日志2. 设置long_query_time3. 查看慢查询数与慢查询SQL三、分析查询语句&#xff1a;EXPLAIN1. 概述2.EXPLAIN各列的含义一、数据库服务…

【leetCode189】轮转数组

作者&#xff1a;日出等日落 专栏&#xff1a;leetCode刷题训练 要成功不需要什么特别的才能&#xff0c;只要把你能做的小事做得好就行了。 ——维龙 目录 题目&#xff1a; 第一种方法&#xff1a; 第二种方法&#xff1a; 第三种方法&#xff1a; 今…

UDP、TCP三次握手和四次挥手

-----UDP与TCP----- 相同点 tcp、udp都是工作在传输层进行数据传输&#xff08;二进制标识文本或者视频或者图片&#xff09; 不同点 tcp基于连接&#xff0c;保障传输的安全udp基于非连接&#xff0c;保障传输的速度 -----TCP的三次握手----- 过程 为什么不是两次握手&a…

PMP考试备考:你不知道的8个常考概念

PMP考试即将到来&#xff0c;为便于广大考生在考试前查漏补缺&#xff0c;给大家准备了PMP考试中常考的八个重要概念&#xff0c;包括敏感性分析、德尔菲技术等&#xff0c;快来看看吧。 01敏感性分析 敏感性分析有助于确定哪些风险对项目具有最大的潜在影响。它有助于理解项…

UWB芯片DW3000之双边双向测距法

目录 双边双向测距 使用四个信息 使用三个信息 双边双向测距 使用四个信息 双边双向测距(DS-TWR)是基本的单边双向测距的扩展&#xff0c;其中使用两次往返时间测量并结合给出飞行时间结果&#xff0c;即使在相当长的响应延迟情况下也能减少误差。 带有四个信息的双面双向…

安全多方计算之八:Mix-Match

Mix-Match1. 混合网络基于ElGamal加密方案的混合网络2. PET协议3. Mix-Match协议4. 百万富翁问题的Mix-Match解决方案M.Jakobsson和A.Juels提出了基于Mix-Match的安全多方计算协议构造方法&#xff0c;该类协议包括Mix与Match两个阶段&#xff1a; Mix阶段&#xff1a;通过构造…

详解LinkedHashSet和LinkedHashMap

目录 一.LinkedHashSet和LinkedHashMap 1.基本介绍 2.与HashSet和HashMap的区别 3.LinkedHashSet和LinkedHashMap具体的方法 1.LinkedHashSet 2.LinkedHashMap 二.模拟代码实现LinkedHashMap 三.具体应用 一.LinkedHashSet和LinkedHashMap 1.基本介绍 顾名思义,根据名…

gpt4国内可以使用吗-chatgpt国内使用的软件排行榜

gpt4国内怎么用&#xff1f; 目前 OpenAI 尚未正式发布 GPT-4 模型&#xff0c;因此目前尚无法直接使用它。预计当GPT-4发布时&#xff0c;将通过OpenAI平台提供API以供使用者调用&#xff0c;同时新的API接口可能需要在不同国家/地区进行不同程度的注册或许可等手续。 当Ope…

php 修改服务器文件上传大小限制

输入docker cp mlfnginx:/etc/nginx/conf.d/pl.conf .输入vimpl.conf 修改nginx配置文件移动到图中所示位置client_max_body_size 按键盘”i”对图中的xxM修改成需要的大小&#xff0c;然后按”esc”&#xff0c;在按”:wq”&#xff0c;最后按回车键输入docker cp ./pl.con…

寻找2020 (蓝桥杯) JAVA

题目描述 小蓝有一个数字矩阵&#xff0c;里面只包含数字0 和2。小蓝很喜欢2020&#xff0c;他想找到这个数字矩阵中有多少个2020 。 小蓝只关注三种构成2020 的方式&#xff1a; 同一行里面连续四个字符从左到右构成2020。 同一列里面连续四个字符从上到下构成2020。 在一条从…