20240312-1-Graph(图)

news2024/11/26 20:18:19

Graph(图)

在这里插入图片描述

在面试的过程中,一般不会考到图相关的问题,因为图相关的问题难,而且描述起来很麻烦.
但是也会问道一下常见的问题,比如,最短路径,最小支撑树,拓扑排序都被问到过.

  1. 图常用的表示方法有两种: 分别是邻接矩阵和邻接表.
    邻接矩阵是不错的一种图存储结构,对于边数相对顶点较少的图,这种结构存在对存储空间的极大浪费.
    因此,找到一种数组与链表相结合的存储方法称为邻接表.

1. 最短路径

  • Dijkstra
  1. 维护一个最短路径的的集合(sptSet)和最短距离数组, 直到遍历所有的点, 初始化起始点的距离是0, 集合为空.
  2. 初始化起始点s到所有的点的距离是INF, 注意s到s的距离是0.
  3. while sptSet 不包含所有的顶点:
    • 选择当前能到达点的最小距离的点u,加入 sptSet
    • 使用u作为中间顶点,更新所有点的距离,选择最小距离的替换
    • dist[u]+graph[u][v] < dist[v]

百度百科
wikipedia

int minDistance(vector<int> dist, set<int> sptSet) {
    int min_d = INT_MAX, u;
    for(int i = 0, i < dist.size(); i ++) {
        if(sptSet.find(i) == sptSet.end() && dist[v] < min_d) {
            min_d = dist[i], u = i;
        }
    }
    return u;
}
// 使用vector 表示的邻接矩阵, return 起始点到所有点的最小距离
// 没有边的用0填充
vector<int> dijstra(vector<vector<int>> graph, set<int> &sptSet,int src) {
    int V = graph.size();
    vector<int> dist(V, 0);
    for(int i = 0;i < V; i ++) {
        if(i != src) dist[i] = INT_MAX;
    }
    while(sptSet.size() < V-1) {
        // pick mininum distance u
        int u = minDistance(dist, sptSet); 
        sptSet.insert(u);
        // 使用u更新距离
        for(int v = 0; v < V; v ++) {
            if(sptSet.find(v)==sptSet.end() && graph[u][v] 
                        && dist[u] != INT_MAX
                        && dist[u]+graph[u][v] < dist[v]) {
                dist[v] = dist[u] + graph[u][v];
            }
        }
    }
    return dist;
}

  • Floyd Warshall
    Floyd算法是使用动态规划算法, dist[i][j]表示i–>j的最短距离,
    那么是否存在i–>k–>j的路径小于dist[i][j],于是就有了下面的更新公式,
  • if dist[i][k] + dist[k][j] < dist[i][j]:
    dist[i][j] = dist[i][k] + dist[k][j]

百度百科
wikipedia

void floydWarshall(vector<vector<int> > graph, vector<vector<int>> &dist, vector<vector<int> > &path) {
    int V = graph.size();
    // 参数dist和path需要初始化大小, 确定是否已经初始化
    vector<vector<int> > tmp(V, vector<int>(V));
    dist = path = tmp;
    for(int i = 0; i < V; i ++) {
        for(int j = 0; j < V; j ++) {
            dist[i][j] = graph[i][j];
            path[i][j] = j;
        }
    }
    for(int i = 0; i < V; i++) {
        for(int j = 0; j < V; j++) {
            for(int k = 0; k < V; k++) {
                if(dist[i][j] > dist[i][k] + dist[k][j]) {
                    dist[i][j] = dist[i][k] + dist[k][j];
                    pre[i][j] = pre[i][k];
                }
            }
        }
    }
}
//打印最短路径 u ---> v
int pfpath(int u, int v, vector<vector<int> > path) { 
    while(u != v) {
        cout << u  << " ";
        u = path[u][v];
    }
    cout << u << endl;
}

2. 最小支撑树

  • Prim Algorithm
  1. 用一个集合mstSet维护已经满足要求的顶点
  2. 使用dist表示从mstSet集合某个点到u的最小距离为INF, 初始点Src的距离是0.
  3. while mstSet doesn’t include all vertices:
    • 选择一个不在mstSet中, 并且在dist中距离最小的顶点u, 加入到mstSet
    • 使用u更新dist距离, 表示从mstSet某个点到达为使用的点的最小距离

百度百科
wikipedia

int minDistance(vector<int> dist, set<int> mstSet) {
    int min_d = INT_MAX, u;
    for(int i = 0, i < dist.size(); i ++) {
        if(mstSet.find(i) == mstSet.end() && dist[v] < min_d) {
            min_d = dist[i], u = i;
        }
    }
    return u;
}
// 使用vector 表示的邻接矩阵, return 起始点到所有点的最小距离
// 没有边的用0填充
vector<int> dijstra(vector<vector<int>> graph, set<int> &mstSet,int src) {
    int V = graph.size();
    vector<int> dist(V, 0);
    int parent[V]; // 每个顶点的相邻的点
    parent[src] = -1;
    for(int i = 0;i < V; i ++) {
        if(i != src) dist[i] = INT_MAX;
    }
    while(mstSet.size() < V-1) {
        // pick mininum distance u
        int u = minDistance(dist, sptSet); 
        mstSet.insert(u);
        // 使用u更新距离
        for(int v = 0; v < V; v ++) {
            if(mstSet.find(v)==mstSet.end() && graph[u][v] 
                        && graph[u][v] < dist[v]) {
                dist[v] = graph[u][v];
                parent[v] = u;
            }
        }
    }
    return dist;
}

  • Kruskal Algorithm
  1. 根据权重排序所有的边
  2. 选择一个小权重的边,如果它没有和最小支撑顶点形成环,就加入这个边
  3. 重复2,知道包含V-1个边

百度百科
wikipedia
Code 抄写

struct Edge { 
    int src, dest, weight; 
}; 
struct Graph { 
    int V, E;   
    struct Edge* edge; 
}; 
struct Graph* createGraph(int V, int E) { 
    struct Graph* graph = new Graph; 
    graph->V = V; 
    graph->E = E;   
    graph->edge = new Edge[E]; 
    return graph; 
} 
struct subset { 
    int parent; 
    int rank; 
}; 
int find(struct subset subsets[], int i) { 
    if (subsets[i].parent != i) 
        subsets[i].parent = find(subsets, subsets[i].parent); 
    return subsets[i].parent; 
} 
void Union(struct subset subsets[], int x, int y) { 
    int xroot = find(subsets, x); 
    int yroot = find(subsets, y);   
    if (subsets[xroot].rank < subsets[yroot].rank) 
        subsets[xroot].parent = yroot; 
    else if (subsets[xroot].rank > subsets[yroot].rank) 
        subsets[yroot].parent = xroot;   
    else { 
        subsets[yroot].parent = xroot; 
        subsets[xroot].rank++; 
    } 
} 
int myComp(const void* a, const void* b) { 
    struct Edge* a1 = (struct Edge*)a; 
    struct Edge* b1 = (struct Edge*)b; 
    return a1->weight > b1->weight; 
} 
void KruskalMST(struct Graph* graph) { 
    int V = graph->V; 
    struct Edge result[V];  
    int e = 0; 
    int i = 0; 
    qsort(graph->edge, graph->E, sizeof(graph->edge[0]), myComp);   
    struct subset *subsets = 
        (struct subset*) malloc( V * sizeof(struct subset) ); 
    for (int v = 0; v < V; ++v) { 
        subsets[v].parent = v; 
        subsets[v].rank = 0; 
    }   
    while (e < V - 1) { 
        struct Edge next_edge = graph->edge[i++];   
        int x = find(subsets, next_edge.src); 
        int y = find(subsets, next_edge.dest);   
        if (x != y) { 
            result[e++] = next_edge; 
            Union(subsets, x, y); 
        } 
    }   
    return; 
} 

3. 拓扑排序

定义: 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。

  1. 计算所有节点的入度
  2. 每次选择一个入度为0的顶点u,如果的已经排序的结果中
  3. 将u所到达的所有顶点v,入度减1,
  4. 重复1,2,直到遍历所有顶点

百度百科
wikipedia

class Graph { 
    int V;  // 顶点的个数
    list<int> *adj; // 所有顶点的起始指针
};

void topologicalSort(int V, list<int> *adj) { 
    // 计算所有入度
    vector<int> in_degree(V, 0);   
    for (int u=0; u<V; u++) { 
        list<int>::iterator itr; 
        for (itr = adj[u].begin(); itr != adj[u].end(); itr++) {
             in_degree[*itr]++; 
        }
    } 
    // 加入入度为0的点
    queue<int> q; 
    for (int i = 0; i < V; i++) { 
        if (in_degree[i] == 0) q.push(i); 
    }
    int cnt = 0;   
    vector <int> top_order;   
    while (!q.empty()) { 
        int u = q.front(); 
        q.pop(); 
        top_order.push_back(u);   
        // 所有连接点, 入度减去1
        list<int>::iterator itr; 
        for (itr = adj[u].begin(); itr != adj[u].end(); itr++) {
            if (--in_degree[*itr] == 0) q.push(*itr); 
        }
        cnt++; 
    } 
    if (cnt != V) { 
        cout << "There exists a cycle in the graph\n"; 
        return; 
    }   
    for (int i=0; i<top_order.size(); i++) 
        cout << top_order[i] << " "; 
    cout << endl; 
} 

4. 有向图判环

题目: 请你判断一个 n 个点,m 条边的有向图是否存在环。参数为两个int数组,start[i]到end[i]有一条有向边.
解析: 这是拓扑排序的一种应用.

bool isCyclicGraph(vector<int> &start, vector<int> &end) {
    // 找到最大顶点值,构造图,
    int n = 0;
    for (int s : start) {
        n = max(n, s);
    }
    for (int e : end) {
        n = max(n, e);
    }
    // 构造图
    vector<vector<int>> graph(n + 1);
    vector<int> d(n + 1);
    int m = start.size();
    // 计算所有顶点的入度
    for (int i = 0; i < m; i++) {
        graph[start[i]].push_back(end[i]);
        d[end[i]]++;
    }
    queue<int> que;
    // 将所有入度为0的点,加入队列
    for (int i = 1; i <= n; i++) {
        if (graph[i].size() && !d[i]) {
            que.push(i);
        }
    }
    while (!que.empty()) {
        int h = que.front();
        que.pop();
        // 将多有入度为0的点,对应的顶点 入度减去1
        for (int y : graph[h]) {
            d[y]--;
            if (!d[y]) {
                que.push(y);
            }
        }
    }
    // 判断是否所有顶点的入度都是0, 如果是,则没有环,否则就有
    for (int i = 1; i <= n; i++) {
        if (d[i]) {
            return true;
        }
    }
    return false;
}

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

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

相关文章

MooC下载pdf转为ppt后去除水印方法

1、从MooC下载的课件&#xff08;一般为pdf文件&#xff09;可能带有水印&#xff0c;如下图所示&#xff1a; 2、将pdf版课件转为ppt后&#xff0c;同样带有水印&#xff0c;如下图所示&#xff1a; 3、传统从pdf中去除水印方法不通用&#xff0c;未找到有效去除课件pdf方法…

c 语言中指针注意事项

看看下面两个 #include<iostream> using namespace std;int main() {int a 10;char p[6];*((int *)p) *(& a); // 正确写法*p *(&a); // 错误写法cout << *(int*)p; } 把原因写在评论区

飞塔防火墙开局百篇——002.FortiGate上网配置——在路由模式下使用虚拟接口对(virtual-wire-pair)

在路由模式下使用虚拟接口对&#xff08;virtual-wire-pair&#xff09; 拓扑配置接口配置策略 使用方有透明模式下一进一出的这样需求的组网&#xff0c;可以在路由模式下使用虚拟接口对&#xff08;virtual-wire-pair&#xff09;替代。 登陆FortiGate防火墙界面&#xff0c;…

01 THU大模型之基础入门

1. NLP Basics Distributed Word Representation词表示 Word representation: a process that transform the symbols to the machine understandable meanings 1.1 How to represent the meaning so that the machine can understand Compute word similarity 计算词相似度 …

中间件 | RabbitMq - [AMQP 模型]

INDEX 1 全局示意2 依赖 1 全局示意 AMQP&#xff0c;即高级消息队列协议&#xff08;Advanced Message Queuing Protocol&#xff09;&#xff0c;整体架构如下图 producer 发送消息给 rabbit mq brokerrabbit mq broker 分发消息给 consumer消费producer/consumer 都通过 …

Python算法题集_搜索旋转排序数组

Python算法题集_搜索旋转排序数组 题33&#xff1a;搜索旋转排序数组1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【二分法区间判断】2) 改进版一【二分找分界标准二分法】3) 改进版二【递归实现二分法】 4. 最优算法5. 相关资源 本文为Pytho…

Android APK体积优化指南:清理项目,打造更小的APK、更快的构建速度和更好的开发体验

Android APK体积优化指南&#xff1a;清理项目&#xff0c;打造更小的APK、更快的构建速度和更好的开发体验 在任何软件项目中&#xff0c;开发是一个持续的过程&#xff0c;随着时间的推移&#xff0c;代码库会变得越来越复杂。这种复杂性可能导致构建时间变慢、APK体积变大&…

DayDreamInGIS 之 ArcGIS Pro二次开发 锐角检查

功能&#xff1a;检查图斑中所有的夹角&#xff0c;如果为锐角&#xff0c;在单独的标记图层中标记。生成的结果放在默认gdb中&#xff0c;以 图层名_锐角检查 的方式命名 大体实现方式&#xff1a;遍历图层中的所有要素&#xff08;多部件要素分别处理&#xff09;&#xff0…

Redis核心数据结构之压缩列表(二)

压缩列表 压缩列表节点的构成 encoding 节点的encoding属性记录了节点的content属性所保存数据的类型及长度: 1.一字节、两字节或者五字节长&#xff0c;值得最高位为00、01或者10的是字节数组编码:这种编码表示节点的content属性保存着字节数组&#xff0c;数组的长度由编…

MachineSink - 优化阅读笔记

注&#xff1a;该优化与全局子表达式消除刚好是相反的过程&#xff0c;具体该不该做这个优化得看代价模型算出来的结果(有采样文件指导算得会更准确) 该优化过程将指令移动到后继基本块中&#xff0c;以便它们不会在不需要其结果的路径上执行。 该优化过程并非旨在替代或完全…

Huggingface中Transformer模型使用

一、Huggingface介绍 1、Huggingface定位 NLP自从Transformer模型出现后&#xff0c;处理方式有大统一的趋势&#xff0c;首先回答几个基础问题&#xff1a; 1、自然语言处理究竟要做一件什么事呢&#xff1f;自然语言处理最终解决的是分类问题&#xff0c;但是它不仅仅输出…

基于单片机的智能小车泊车系统设计

摘 要:随着信息技术的进步,汽车逐渐朝着安全、智能方向发展,智能泊车系统的出现不仅能帮助人们更加快速、安全地完成泊车操作,而且适用于狭小空间的泊车操作,降低驾驶员泊车负担,减轻泊车交通事故发生率。文章基于单片机设计自动泊车系统,以单片机为核心来实现信息收集及…

洛谷P6022快乐水

他来到了一家商店门前。 这家商店为了吸引顾客来买快乐水&#xff0c;搞了这么一个活动&#xff1a;「55 个瓶盖换一瓶快乐水」。于是&#xff0c;人们纷纷来他的店里买快乐水。 买完快乐水&#xff0c;他想到了一个问题&#xff1a; 如果一瓶快乐水有m 个附属品&#xff0c…

Java线程的6种状态

线程在生命周期中并不是固定处于某一个状态而是随着代码的执行在不同状态之间切换。 NEW&#xff1a;初始状态&#xff0c;线程被创建出来但没有被调用start()RUNNABLE&#xff1a;运行状态&#xff0c;线程被调用了start()等待运行的状态BLOCKED&#xff1a;阻塞状态&#xf…

uview upicker时间选择器(附Demo)

目录 前言正文 前言 uniapp时间选择器&#xff0c;是upicker&#xff0c;与微信小程序还是有些区别 补充官网的基本知识&#xff1a;uview官网 官网的展示例子如下&#xff1a;&#xff08;但是没Demo&#xff09; 正文 通过上面的展示图&#xff0c;复刻一个类似Demo图&am…

15双体系Java学习之数组的声明和创建

数组的声明 ★小贴士 可以使用int[] a;或者int a[];建议使用第一种风格&#xff0c;因为它将元素类型int[]&#xff08;整型数组&#xff09;与变量名清晰分开了。 在Java中声明数组时不能指定其长度。这种定义是非法的&#xff1a;int a[5]; 注意&#xff1a;上图显示的内存…

学习数据节构和算法的第15天

单链表的实现 链表的基本结构 #pragma once #include<stdio.h> typedf int SLTDataType; typedy struct SListNode {SLTDataType data;struct SListNode*next; }SLTNode;void Slisprint(SLTNode*phead);打印链表 #include<stdio.h> void SListPrint(SLTNode*phe…

【LeetCode】升级打怪之路 Day 18:二叉树题型 —— 树的深度、高度、路经

今日题目&#xff1a; 104. 二叉树的最大深度111. 二叉树的最小深度110. 平衡二叉树257. 二叉树的所有路径112. 路径总和 目录 Problem 1&#xff1a;树的深度LC 104. 二叉树的最大深度 【easy】LC 111. 二叉树的最小深度 【易错】 Problem 2&#xff1a;树的高度LC 110. 平衡二…

嵌入式系统软件及操作系统

0、前言 本专栏为个人备考软考嵌入式系统设计师的复习笔记&#xff0c;未经本人许可&#xff0c;请勿转载&#xff0c;如发现本笔记内容的错误还望各位不吝赐教&#xff08;笔记内容可能有误怕产生错误引导&#xff09;。 考查选择题为多&#xff1a;嵌入式系统软件特点是什么…

解决Klipper下位机ID获取失败问题

使用硬件&#xff1a; 上位机&#xff1a;必趣派&#xff0c;版本CB1_Debian11_Klipper_kernel5.16_20230303 下位机&#xff1a;八爪鱼STM32F407 问题&#xff1a;上位机获取下位机ID失败。 解决&#xff1a;调试过程中&#xff0c;发现上位机和下位机之间没有物理连接&…