【数据结构】图的应用---最小生成树(Prim,Kruskal)、最短路径(BFS,Dijkstra,Floyd)、拓扑排序、关键路径、有向无环图表达式

文章目录

    • 5.图的应用
      • 5.1 最小生成树
        • 5.1.1 Prim算法
        • 5.1.2 Kruskal算法
        • 5.1.3 最小生成树代码
          • A.邻接矩阵
          • B.邻接表
      • 5.2 最短路径
        • 5.2.1 BFS
        • 5.2.2 Dijkstra
        • 5.2.3 Floyd
        • 5.2.4 三种算法的比较
      • 5.3 有向无环图描述表达式
      • 5.4 拓扑排序
      • 5.5 关键路径

5.图的应用

5.1 最小生成树

  • 定义

    对一个带权连通无向图 G = ( V , E ) G=(V,E) G=(V,E),生成树不同,每棵树的权(即树中所有边上的权值之和)也可能不同。

    设R为G的所有生成树的集合,若T为R中边的权值之和最小的生成树,则T称为G的最小生成树(MST)。

  • 性质

    1.最小生成树可能有多个,但边的权值之和总是唯一且最小的;

    2.最小生成树的边数=顶点数-1。砍掉一条则不连通,增加一条会出现回路;

    3.如果一个连通图本身就是一棵树,则其最小生成树就是它本身;

    4.只有连通图才有最小生成树,非连通图只有生成森林。

  • 最小生成树是所有边权值之和最小,但不能保证任意两个顶点之间的路径最短。如:

    在这里插入图片描述

  • 伪代码

    GENERIC_MST(G){
        T=NULL;
        while T未形成一棵生成树;
        	do 找到一条最小代价边(u,v)并且加入T后不会产生回路;
        		T=T∪(u,v);
    }
    

    通用算法每次加入一条边以逐渐形成一棵生成树。

5.1.1 Prim算法
  • 定义

    从某一个顶点开始构建生成树;

    每次将代价最小的新顶点纳入生成树,直到所有顶点都纳入为止。

    • 即选最小权值的结点
  • 时间复杂度

    O ( ∣ V ∣ 2 ) O(|V|^2) O(V2),适用于稠密图(|E|大的)。

  • 算法的实现思想

    • 思路:

      1.从 V 0 V_0 V0开始,总共需要n-1轮处理。

      2.第一轮处理:循环遍历所有个结点,找到lowCast最低的,且还没加入树的顶点。

      3.再次循环遍历,更新还没加入的各个顶点的lowCast值。

      每一轮时间复杂度 O ( 2 n ) O(2n) O(2n),一共有n轮。

    • 代码步骤:

      1.创建isJoin数组,初始为false,判断结点是否加入树。

      2.创建lowCost数组,用于存储到该结点的最短距离。

      3.从 v 0 v_0 v0开始,将与其连接的权值加入到lowCost数组中。

      4.遍历lowCast数组,找到最小值,将其加入树中,并继续遍历与其相连的边。

    在这里插入图片描述

  • 伪代码

    void Prim(G,T){
        T=; //初始化空树
        U={w}; //添加任意一个顶点w
        while((V-U)!=){ //若树中不含全部顶点(u,v)是使u∈U与v∈(V-U),且权值最小的边;
            T=T⋃{(u,v)}; //边归入树
            U=U⋃{v}; //顶点归入树
        }
    }
    
5.1.2 Kruskal算法
  • 定义

    每次选则一条权值最小的边,使这条边的两头连通(原本已经连通的不选),直到所有结点都连通。

    在这里插入图片描述

    • 即每次选最小的边
  • 时间复杂度

    O ( ∣ E ∣ l o g 2 ∣ E ∣ ) O(|E|log_2|E|) O(Elog2E),适用于边稀疏图。

  • 算法的实现思想

    • 思路:

      1.初始:将各条边按权值排序。

      2.共执行e轮,每轮判断两个顶点是否属于同一集合,需要 O ( l o g 2 e ) O(log_2e) O(log2e)

  • 伪代码

    void Kruskal(V,T){
        T=V; //初始化树T,仅含顶点
        numS=n; //连通分量数
        while(numS>1){ //若连通分量数大于1
            从E中取出权值最小的边(v,u);
            if(v和u属于T中不同的连通分量){ //就是没有形成环
                T=T⋃{(v,u)}; //将此边加入生成树中
                numS--; //连通分量数减1
            }
        }
    }
    
5.1.3 最小生成树代码
A.邻接矩阵
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <limits.h>

#define V 5 // 图的顶点数

// 找到距离集合最近的顶点
int min_key(int key[], bool mst_set[]) {
    int min = INT_MAX, min_index;
    for (int v = 0; v < V; v++) {
        if (mst_set[v] == false && key[v] < min) {
            min = key[v];
            min_index = v;
        }
    }
    return min_index;
}

// 打印最小生成树
void print_mst(int parent[], int graph[V][V]) {
    printf("Edge   Weight\n");
    for (int i = 1; i < V; i++)
        printf("%d - %d    %d \n", parent[i], i, graph[i][parent[i]]);
}

// Prim算法
void prim_mst(int graph[V][V]) {
    int parent[V]; // 存放最小生成树的父节点
    int lowCost[V];    // 用于存放顶点到最小生成树的最小权重
    bool isJoin[V]; // 记录顶点是否已经加入最小生成树

    for (int i = 0; i < V; i++) {
        lowCost[i] = INT_MAX;
        isJoin[i] = false;
    }

    lowCost[0] = 0; // 初始点为0
    parent[0] = -1; // 根节点没有父节点

    for (int count = 0; count < V - 1; count++) {
        int u = min_key(lowCost, isJoin);
        isJoin[u] = true;

        for (int v = 0; v < V; v++) {
            if (graph[u][v] && !isJoin[v] && graph[u][v] < lowCost[v]) {
                parent[v] = u;
                lowCost[v] = graph[u][v];
            }
        }
    }

    print_mst(parent, graph);
}

// Kruskal算法

// 结构体用于表示边
struct Edge {
    int src, dest, weight;
};

// 比较函数,用于排序
int compare(const void* a, const void* b) {
    return ((struct Edge*)a)->weight - ((struct Edge*)b)->weight;
}

// 查找函数,用于查找集合的根节点
int find(int parent[], int i) {
    if (parent[i] == -1)
        return i;
    return find(parent, parent[i]);
}

// 合并函数,用于合并两个集合
void Union(int parent[], int x, int y) {
    int xset = find(parent, x);
    int yset = find(parent, y);
    parent[xset] = yset;
}

// Kruskal算法
void kruskal_mst(int graph[V][V]) {
    struct Edge result[V]; // 用于存放最小生成树的边
    int e = 0; // 表示result数组中的边数
    int i = 0; // 表示当前考虑的边

    // 边集合
    struct Edge edges[V*V];
    for (int u = 0; u < V; u++) {
        for (int v = u + 1; v < V; v++) {
            if (graph[u][v] != 0) {
                edges[e].src = u;
                edges[e].dest = v;
                edges[e].weight = graph[u][v];
                e++;
            }
        }
    }

    // 根据权重对边进行排序
    qsort(edges, e, sizeof(edges[0]), compare);

    int parent[V]; // 用于记录每个顶点的父节点
    for (int v = 0; v < V; v++)
        parent[v] = -1;

    // 最小生成树的边数小于V-1时继续
    while (i < V - 1 && e > 0) {
        struct Edge next_edge = edges[--e];

        // 检查是否会产生环
        int x = find(parent, next_edge.src);
        int y = find(parent, next_edge.dest);

        if (x != y) {
            result[i++] = next_edge;
            Union(parent, x, y);
        }
    }

    printf("Edge   Weight\n");
    for (int i = 0; i < V - 1; i++)
        printf("%d - %d    %d \n", result[i].src, result[i].dest, result[i].weight);
}

// 测试主函数
int main() {
    int graph[V][V] = {
            {0, 2, 0, 6, 0},
            {2, 0, 3, 8, 5},
            {0, 3, 0, 0, 7},
            {6, 8, 0, 0, 9},
            {0, 5, 7, 9, 0}
    };

    printf("Prim's Minimum Spanning Tree:\n");
    prim_mst(graph);

    printf("\nKruskal's Minimum Spanning Tree:\n");
    kruskal_mst(graph);

    return 0;
}
image-20240428215225889
B.邻接表
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <limits.h>

#define MaxVertexNum 100
#define INF 9999

typedef struct ArcNode {
    int adjvex;
    int weight;
    struct ArcNode *next;
} ArcNode;

typedef struct VNode {
    int data;
    ArcNode *first;
} VNode, AdjList[MaxVertexNum];

typedef struct {
    AdjList vertices;
    int vexnum, arcnum;
} ALGraph;

void InitALGraph(ALGraph *G, int vexnum, int arcnum) {
    G->vexnum = vexnum;
    G->arcnum = arcnum;
    for (int i = 0; i < vexnum; i++) {
        G->vertices[i].data = i;
        G->vertices[i].first = NULL;
    }
}

void AddEdgeUndirectedALGraph(ALGraph *G, int v1, int v2, int weight) {
    ArcNode *arcNode1 = (ArcNode *)malloc(sizeof(ArcNode));
    arcNode1->adjvex = v2;
    arcNode1->weight = weight;
    arcNode1->next = G->vertices[v1].first;
    G->vertices[v1].first = arcNode1;

    ArcNode *arcNode2 = (ArcNode *)malloc(sizeof(ArcNode));
    arcNode2->adjvex = v1;
    arcNode2->weight = weight;
    arcNode2->next = G->vertices[v2].first;
    G->vertices[v2].first = arcNode2;
}

void PrintALGraph(ALGraph G) {
    for (int i = 0; i < G.vexnum; i++) {
        printf("%d -> ", G.vertices[i].data);
        ArcNode *p = G.vertices[i].first;
        while (p != NULL) {
            printf("(%d, %d) ", p->adjvex, p->weight);
            p = p->next;
        }
        printf("\n");
    }
}

// Prim算法
void Prim(ALGraph G) {
    int lowCost[G.vexnum], parent[G.vexnum];
    bool inMST[G.vexnum];

    for (int i = 0; i < G.vexnum; i++) {
        lowCost[i] = INF;
        parent[i] = -1;
        inMST[i] = false;
    }

    lowCost[0] = 0;

    for (int i = 0; i < G.vexnum - 1; i++) {
        int minIndex, minCost = INF;
        for (int j = 0; j < G.vexnum; j++) {
            if (!inMST[j] && lowCost[j] < minCost) {
                minCost = lowCost[j];
                minIndex = j;
            }
        }

        inMST[minIndex] = true;

        ArcNode *p = G.vertices[minIndex].first;
        while (p != NULL) {
            if (!inMST[p->adjvex] && p->weight < lowCost[p->adjvex]) {
                lowCost[p->adjvex] = p->weight;
                parent[p->adjvex] = minIndex;
            }
            p = p->next;
        }
    }

    printf("Edge   Weight\n");
    for (int i = 1; i < G.vexnum; i++) {
        printf("%d - %d    %d\n", parent[i], i, lowCost[i]);
    }
}

// Kruskal算法
typedef struct {
    int src, dest, weight;
} Edge;

int find(int parent[], int i) {
    if (parent[i] == -1)
        return i;
    return find(parent, parent[i]);
}

void Union(int parent[], int x, int y) {
    int xset = find(parent, x);
    int yset = find(parent, y);
    parent[xset] = yset;
}

int compare(const void *a, const void *b) {
    return ((Edge *)a)->weight - ((Edge *)b)->weight;
}

void Kruskal(ALGraph G) {
    Edge result[G.arcnum];
    Edge edges[G.arcnum];
    int parent[G.vexnum];

    int e = 0;
    for (int i = 0; i < G.vexnum; i++) {
        ArcNode *p = G.vertices[i].first;
        while (p != NULL) {
            if (i < p->adjvex) {
                edges[e].src = i;
                edges[e].dest = p->adjvex;
                edges[e].weight = p->weight;
                e++;
            }
            p = p->next;
        }
    }

    qsort(edges, G.arcnum, sizeof(Edge), compare);

    for (int i = 0; i < G.vexnum; i++)
        parent[i] = -1;

    int i = 0, j = 0;
    while (i < G.vexnum - 1 && j < G.arcnum) {
        Edge next_edge = edges[j++];

        int x = find(parent, next_edge.src);
        int y = find(parent, next_edge.dest);

        if (x != y) {
            result[i++] = next_edge;
            Union(parent, x, y);
        }
    }

    printf("Edge   Weight\n");
    for (int i = 0; i < G.vexnum - 1; i++) {
        printf("%d - %d    %d\n", result[i].src, result[i].dest, result[i].weight);
    }
}

int main() {
    ALGraph G;
    InitALGraph(&G, 5, 7);
    AddEdgeUndirectedALGraph(&G, 0, 1, 2);
    AddEdgeUndirectedALGraph(&G, 0, 3, 6);
    AddEdgeUndirectedALGraph(&G, 1, 2, 3);
    AddEdgeUndirectedALGraph(&G, 1, 3, 8);
    AddEdgeUndirectedALGraph(&G, 1, 4, 5);
    AddEdgeUndirectedALGraph(&G, 2, 4, 7);
    AddEdgeUndirectedALGraph(&G, 3, 4, 9);
    PrintALGraph(G);

    printf("Prim's Minimum Spanning Tree:\n");
    Prim(G);

    printf("\nKruskal's Minimum Spanning Tree:\n");
    Kruskal(G);

    return 0;
}
image-20240428215759712

5.2 最短路径

  • 单源最短路径问题

    从一个顶点出发,到各个顶点的最短路径。

    • BFS算法(无权图)

    • Dijkstra算法(带权图、无权图)

  • 各顶点间的最短路径

    每对顶点间的最短路径。

    • Floyd算法(带权图、无权图)
5.2.1 BFS
  • 定义

    求无权图的单源最短路径

    在广度优先遍历基础上改造。

    在这里插入图片描述

    • 局限性:只适用于无权图,或所有边的权值都相同的图。

      如下图,G港直接到R城的距离不是最短的,先到P城再到R城才是最短的。

  • 代码

    const int MAX_INT=0X7fffffff; //表示无穷大
    //求顶点u到其他顶点的最短路径
    void BFS_MIN_Distance(Graph G,int u){
        //d[i]表示从u到i结点的最短路径
        for(i=0;i<G.vexnum;i++){
            d[i]=MAX_INT; //初始化路径长度
            path[i]=-1; //最短路径从哪个顶点过来的
        }
        d[u]=0;
        visited[u]=TRUE;
        EnQueue(Q,u);
        //BFS算法主过程
        while(!isEmpty(Q)){
            DeQueue(Q,u); //队头元素u出队
            for(w=FirstNeighbor(G,u);w>=0;w=NextNeighbor(G,u,w)){
                //若w为u尚未访问的邻接顶点
                if(!visited[w]){
                    d[w]=d[u]+1; //w的路径长度为起始顶点到u的距离加1
                    path[w]=u; //w的最短路径是从u过来的
                    visited[w]=TRUE; //设已访问标记
                    EnQueue(Q,w); //顶点w入队
                }
            }
        }
    }
    
5.2.2 Dijkstra
  • 定义

    • 带权路径长度:带权图中,一条路径上所有边的权值之和。

    • Dijkstra算法可解决带权图和无权图的单源最短路径问题。

    • 局限性:不适用于有负权值的带权图:

  • 算法思想

    1.从v0开始,初始化以下三个数组:

    2.遍历所有顶点,找到还没确定最短路径的顶点(final值为false),且dist最小的顶点Vi,令final[i]=true(i的最短路径确定了)。

    3.检查所有邻接自Vi的顶点,若finalfalse,则更新distpath信息。

    4.重复第2、3步,直到final都为true

  • 时间复杂度

    O ( ∣ V ∣ 2 ) O(|V|^2) O(V2):所有顶点遍历一次(把final从false变成true)为O(n)的时间,每次遍历path数组找到最短路径又是 O ( n ) O(n) O(n)的时间,所以为 O ( n 2 ) O(n^2) O(n2)

5.2.3 Floyd
  • 定义

    求出一对顶点间的最短路径。

    使用动态规划思想,将问题的求解分为多个阶段:

    • 也可以解决带负权值的图,但是不能解决带负权回路的图(有负权值的边组成回路),这种图有可能没有最短路径。如:

  • 步骤

    1.初始化两个二维数组

    2.以 V k V_k Vk为中转点(以下公式中,k是中转点,要判断i直接到j的距离和结果k中转的i到j的距离哪个更加短):

    3.从 A ( − 1 ) A^{(-1)} A(1) p a t h ( − 1 ) path^{(-1)} path(1)开始,经过第2步的n轮递推,得到 A ( n − 1 ) A^{(n-1)} A(n1) p a t h ( n − 1 ) path^{(n-1)} path(n1)

  • 核心代码

    //。。。准备工作,根据图的信息初始化矩阵A和path
    for(int k=0;k<n;k++){ //考虑以Vk作为中转点
        for(int i=0;i<n;i++){ //遍历整个矩阵,i为行号,j为列号
            for(int j=0;j<n;j++){ 
                if(A[i][j]>A[i][k]+A[k][j]){ //如果以Vk为中转点的路径更短
                    A[i][j]=A[i][k]+A[k][j]; //更新最短路径长度
                    path[i][j]=k; //更新中转点
                }
            }
        }
    }
    
  • 复杂度

    • 时间复杂度: O ( ∣ V ∣ 3 ) O(|V|^3) O(V3)
    • 空间复杂度: O ( ∣ V ∣ 2 ) O(|V|^2) O(V2)
5.2.4 三种算法的比较

5.3 有向无环图描述表达式

  • 定义

    • 有向无环图:若一个有向图中不存在环,则称为有向无环图,简称DAG图。

    • 有向无环图描述表达式:要用有向无环图的形式描述表达式。如题:

  • 解题方法

    1.把各操作数不重复的排成一排。

    2.标出各个运算符生效的顺序(先后顺序有点出入没关系)。

    3.按顺序在图中加入运算符,注意分层。

    4.从底向上逐层检查同层的运算符是否可以合体。

  • 有向无环图存表达式是不唯一的。

5.4 拓扑排序

  • 定义

    • AOV网(用顶点表示活动的网)

      用DAG图(有向无环图)表示一个工程。顶点表示活动,有向边 < V i , V j > <V_i,V_j> <Vi,Vj>表示活动 V i V_i Vi必须先于活动 V j V_j Vj进行。

    • 拓扑排序

      在图论中,由一个有向无环图的顶点组成的序列,当且仅当满足下列条件时,称为该图的一个拓扑排序:

      1)每个顶点出现且只出现一次;

      2)若顶点A在序列中排在顶点B的前面,则在图中不存在从顶点B到顶点A的路径。

      或定义为:

      拓扑排序是对有向无环图的顶点的一种排序,它使得若存在一条从顶点A到顶点B的路径,则在排序中顶点B出现在顶点A的后面。每个AOV网都有一个或多个拓扑排序序列。

      如:

    在这里插入图片描述

  • 实现步骤

    1.从AOV网中选择一个**没有前驱(入度为0)**的顶点并输出;

    2.从网中删除该顶点和所有以它为起点的有向边;

    3.重复第1和2步,直到当前的AOV网为空或当前网中不存在无前驱的顶点为止。

  • 代码

    bool TopologicalSort(Graph G){
        InitStack(S); //初始化栈,存储入度为0的顶点
        for(int i=0;i<G.vexnum;i++){
            if(indegree[i]==0){
                Push(S,i); //将所有入度为0的顶点进栈
            }
        }
        int count=0; //计数,记录当前已经输出的顶点数
        //栈不为空,说明存在入度为0的顶点
        while(!IsEmpty(S)){
            Pop(S,i); //顶点元素出栈
            print[count++]=i; //输出顶点i
            for(p=G.vertices[i].firstarc;p;p=p->nextarc){
                //将所有i指向的顶点的入度减1,并将入度减1后为0的顶点压入栈S
                v=p->adjvex;
                if(!(--indegree[v])){
                    Push(S,v); //入度为0,则入栈
                }
            }
        }
        if(count<G.vexnum)
            return false; //排序失败,有向图中有回路
        else
            return true;
    }
    
    • 时间复杂度

      • 分析:每个顶点都要入栈出栈,所以每个顶点都要遍历一次,因为要删除每条边,所以每条边也要遍历一次。
      • 邻接表时间复杂度: O ( ∣ V ∣ + ∣ E ∣ ) O(|V|+|E|) O(V+E)
      • 邻接矩阵时间复杂度: O ( ∣ V ∣ 2 ) O(|V|^2) O(V2)
  • 逆拓扑排序

    和拓扑排序的区别就是把入度为0改为出度为0的。

    • 逆拓扑排序的实现(DFS算法)

      //对图G进行深度优先遍历
      void DFSTraverse(Graph G){
          for(v=0;v<G.vexnum;v++){
              visited[v]=false; //初始化已访问标记数据
          }
          for(v=0;v<G.vexnum;v++){
              if(!visited[v]){
                  DFS(G,v);
              }
          }
      }
      //从顶点v出发,深度优先遍历图G
      void DFS(Graph G,int v){
          visited[v]=true;
          for(w=FirstNeighbor(G,v);w>=0;w=NextNeighbor(G,v,w)){
              if(!visited[w]){
                  DFS(G,w);
              }
          }
          print(v);
      }
      
  • 性质

    • 拓扑排序、逆拓扑排序序列可能不唯一。
    • 若图中有环,则不存在拓扑排序/逆拓扑排序序列。

5.5 关键路径

  • 定义

    • AOE网

      在带权有向图中,以顶点表示事件,以有向边表示活动,以边上的权值表示完成该活动的开销,称为用边表示活动的网络,简称AOE网。(Activity On Edge Network)

    • AOE网性质

      1)只有在某个顶点所代表的事件发生后,从该顶点出发的各有向边所代表的活动才能开始;

      2)只有在进入某顶点的各有向边所代表的活动已结束时,该顶点所代表的事情才能发送。

      另外,有些活动可以并行。

    • 开始顶点(源点):AOE中只有一个入度为0的,表示整个工程的开始;

      结束顶点(汇点):AOE中只有一个出度为0的顶点,表示整个工程的结束。

    • 关键路径

      关键路径:从源点到汇点的有向路径可能有多条,所有路径中,具有最大路径长度的路径称为关键路径。

      关键活动:关键路径上的活动。

      关键路径长度:完成整个工程最短时间。

    • 各时间点

      事件 v k v_k vk最早发生时间 v e ( k ) ve(k) ve(k):决定了所有从 v k v_k vk开始的活动能够开工的最早时间。

      活动 a i a_i ai最早发生时间 e ( i ) e(i) e(i):指该活动弧的起点所表示的事件的最早发生时间。

      事件 v k v_k vk最迟发生时间 v l ( k ) vl(k) vl(k):指在不推迟整个工程完成的前提下,该事件最迟必须发生的时间。

      活动 a i a_i ai最迟发生时间 l ( i ) l(i) l(i):指该活动弧的终点所表示事件的最迟发生时间与该活动所需时间之差。

      活动 a i a_i ai最早发生时间 d ( i ) = l ( i ) − e ( i ) d(i)=l(i)-e(i) d(i)=l(i)e(i):如果值为0,说明该活动不能拖延,是关键活动。

  • 求关键路径

    1.求所有事件的最早发生时间

    按拓扑排序序列,依次求各个顶点的 v e ( k ) ve(k) ve(k)

    ve(源点)=0;
    ve(k)=Max{ve(j)+Weight(vj,vk)},vj是vk的任意前驱
    

    2.求所有事件的最迟发生时间

    3.求所有活动的最早发生时间

    4.求所有活动的最迟发生时间

    5.所有活动的时间余量

    6.时间余量为0的就是关键活动

  • 关键活动、关键路径的特性

    1.关键活动耗时增加,工期增加;缩短关键活动事件,可缩短工期,但缩到一定程度会变成非关键活动。

    2.可能有多条关键路径,则要加快那些包括在所有关键路径上的关键活动才能达到缩短工期的目的。

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

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

相关文章

Android Studio(AS)使用别人的项目与gradle包并运行项目

一、问题描述 在进行AS开发时&#xff0c;我们可能会使用到别人的项目&#xff0c;但发现别人把项目发给我们后会发现gradle项目同步失败o(≧口≦)o&#xff0c;此时计有三&#xff1a; 1.横行霸道、豪取抢夺&#xff1a;直接空降到项目人那里&#xff0c;强他的电脑占为己有…

哈夫曼编码(上)

文章目录 问题引入哈夫曼编码的编写总述步骤一步骤二步骤三步骤四 实现代码如下 问题引入 哈夫曼编码通常用于通信领域&#xff0c;是对较长信息进行压缩&#xff0c;然后发送到指定的位置&#xff0c;是为了节省发送信息占用的空间。 通常来说&#xff0c;如果信息中字符的重…

《Linux运维总结:ARM64架构CPU基于docker-compose一离线部署rabbitmq 3.10.25容器版镜像模式集群》

总结&#xff1a;整理不易&#xff0c;如果对你有帮助&#xff0c;可否点赞关注一下&#xff1f; 更多详细内容请参考&#xff1a;《Linux运维篇&#xff1a;Linux系统运维指南》 一、部署背景 由于业务系统的特殊性&#xff0c;我们需要面向不通的客户安装我们的业务系统&…

element 输入框禁止输入空格以及复制的值进去删除空格(vue自定义指令)开箱即用

实例图&#xff1a; 代码&#xff1a; //输入框禁止输入空格 Vue.directive(noSpace, {bind(el) {//禁止输入空格el.addEventListener("keydown", function (event) {if (event.keyCode 32) {event.preventDefault();}});//复制值时去掉空格el.addEventListener(&q…

探讨欧盟就人工智能监管达成协议

《人工智能法案》是一项具有里程碑意义的立法&#xff0c;它可以创造一个有利的环境&#xff0c;在这种环境中&#xff0c;人工智能的使用将成为一种更优秀的安全和信任的工具&#xff0c;确保整个欧盟的公共和私人机构利益相关者的参与。 历时3天的“马拉松式”谈判圆满结束&…

CCC数字钥匙各版本关系

CCC钥匙规范版本关系 CCC数字钥匙架构Overview

【教学类-55-01】20240511图层顺序挑战(四格长条纸)(4*4)和“手工纸自制参考图”

作品展示 背景需求 空间思维图层挑战2|逻辑推理|空间想象力 - 小红书 (xiaohongshu.com)https://www.xiaohongshu.com/discovery/item/62cbf6c60000000010026aa0?app_platformandroid&ignoreEngagetrue&app_version8.35.0&share_from_user_hiddentrue&typevi…

机器学习第37周周报 GGNN

文章目录 week37 GGNN摘要Abstract一、文献阅读1. 题目2. abstract3. 网络架构3.1 数据处理部分3.2 门控图神经网络3.3 掩码操作 4. 文献解读4.1 Introduction4.2 创新点4.3 实验过程4.3.1 传感器设置策略4.3.2 数据集4.3.3 实验设置4.3.4 模型参数设置4.3.5 实验结果 5. 结论 …

【linux】详解linux基本指令

目录 cat more less head tail 时间 cal find grep zip/unzip tar bc uname –r 关机 小编一共写了两篇linux基本指令&#xff0c;这两篇涵盖了大部分初学者的必备指令&#xff0c;这是第二篇&#xff0c;第一篇详见http://t.csdnimg.cn/HRlVt cat 适合查看小文…

JAVA 标准接口返回与i18n国际化配置

不喜欢废话直接上代码 标准通用返回 package com.luojie.common;import com.luojie.common.inter.ResponseCommon; import lombok.Data;Data public class ResponseCommonImpl implements ResponseCommon {int code;String msg;Object entity; }package com.luojie.common;im…

vue 中的 Vuex

Vuex Vuex是什么&#xff1f; 概念&#xff1a;专门在vue中实现集中式状态&#xff08;数据&#xff09;管理的一个Vue插件&#xff0c;对Vue应用中多个组件的共享状态进行集中式的管理(读/写&#xff09;&#xff0c;也是一种组件间通信的方式&#xff0c;且适用于任意组件间…

【NTN 卫星通信】参考卫星集成场景和架构

1 卫星接入场景 1.1 同一PLMN内的卫星和地面接入网 一个PLMN可以同时具有地面3GPP接入和卫星3GPP接入。在此场景中&#xff0c;单独的N2实例处理单独的访问类型节点。然而&#xff0c;卫星接入网的覆盖范围可以跨越地面接入网的覆盖范围。 图1 同PLMN架构下的卫星和地面3GPP接…

如何在matlab时间序列中X轴标注月-日

一般我们使用的时间序列都是以年为单位&#xff0c;比如下图&#xff1a; 而如果要绘制月尺度的时间变化图&#xff0c;则需要调整X轴的标注。下面代码展示了如何绘制小时尺度的降水数据。 [sname2,lon2,lat2] kml2xy(GZ_.kml); nc_bound2 [lon2,lat2]; area_ind2inpolygon(e…

# 从浅入深 学习 SpringCloud 微服务架构(十六)

从浅入深 学习 SpringCloud 微服务架构&#xff08;十六&#xff09; 一、SpringCloudStream&#xff1a;自定义消息通道 1、在子工程 stream_product &#xff08;子模块&#xff09;中,创建 自定义的消息通道类 MyProcessor.java /*** spring_cloud_demo\stream_product…

【大数据·Hadoop】从词频统计由浅入深介绍MapReduce分布式计算的设计思想和原理

一、引入&#xff1a;词频统计问题 假如我们有一亿份文档&#xff0c;需要统计这一亿份文档的词频。我们会怎么做&#xff0c;有以下思路 使用单台PC执行&#xff1a;能不能存的下不说&#xff0c;串行计算&#xff0c;一份一份文档读&#xff0c;然后进行词频统计&#xff0…

【35分钟掌握金融风控策略23】定额策略

目录 定额策略 定额策略的开发、部署、监控和调优 定额策略开发 定额策略部署 定额策略监控 定额策略调优 定额策略 定额是对授信审批通过的客户给予合适授信额度的过程。如何定额、定多少额度是由定额策略来决定的。定额的多少与客户未来的动支情况、逾期情况和最终的收…

基于鹈鹕优化算法POA的复杂城市地形下无人机避障三维航迹规划,可以修改障碍物及起始点(Matlab代码)

复杂城市地形下无人机避障三维航迹规划是指在城市等高密度区域内&#xff0c;通过无人机的传感器和导航系统来实现飞行路径的规划和调整&#xff0c;从而避免无人机与建筑物、其他无人机、地面障碍物等发生碰撞和冲突。具体来说&#xff0c;无人机需要实时感知周围环境&#xf…

【报错合集】完美解决“虚拟机使用的是此版本 VMware Workstation 不支持的硬件版本”

文章目录 解决方案&#xff1a;更改设置的硬件版本 今天我需要将别人的虚拟机克隆到我的VMware Workstation上运行&#xff0c;结果发生了以下的错误&#xff1a; 刚开始以为是VMware Workstation的版本问题太低导致的&#xff0c;所以我删除了原来的那个版本&#xff0c;下载…

MySQL数据库的初始化(创建库、创建表、向数据库添加测试数据)

MySQL数据库的初始化&#xff08;创建库、创建表、向数据库添加测试数据&#xff09; MySQL数据库简介MySQL创建一个新的数据库MySQL创建一张新的数据表简单&#xff08;设置&#xff09;表复杂&#xff08;设置&#xff09;表 填充测试数据SQL语句mysql>模式下输入的每句sq…

用 Python 和 AkShare 进行个股数据清洗:简易多功能方法

标题:用 Python 和 AkShare 进行个股数据清洗:简易多功能方法 简介: 本文介绍了如何使用 Python 和 AkShare 库对个股数据进行清洗和处理。个股数据经常需要进行清洗以用于分析、建模或可视化。我们将介绍一些简单但功能强大的方法,包括数据加载、缺失值处理、重复值检测和…