数据结构(八):图介绍及面试常考算法

一、图介绍

1、定义

图由结点的有穷集合V和边的集合E组成。其中,结点也称为顶点。一对结点(x, y)称为边(edge),表示顶点x连接到顶点y。边可以包含权重/成本,显示从顶点x到y所需的成本。若两个顶点之前存在一条边,就表示这两个顶点具有相邻关系。

2、类型

(1)无向图

(2)有向图

3、表示方法

(1)邻接矩阵

邻接矩阵存储结构就是用矩阵表示图中各顶点之间的邻接关系,两个顶点有邻接关系,就记录为1,否则为0。

(2)邻接表

邻接表是图的一种顺序存储与链式存储相结合的存储方式。

4、遍历方法

(1)广度优先搜索

(2)深度优先搜索

二、面试常考的算法

1、实现深度优先搜索

 题目:如下无向图,从节点A开始遍历,其深度优先搜索为:A B D E F C。

思路:深度优先搜索,创建visited数组,用于记录所有被访问过的顶点。

(1)从A出发,访问A。

(2)找出A的第一个没有被访问的邻接点,访问该点。以该顶点为新顶点,重复此步骤,直至刚访问过的顶点没有未被访问的邻接点为止。

(3)返回前一个访问过的仍有未被访问邻接点的顶点,继续访问该顶点的下一个未被访问邻接点。

(4)重复2,3步骤,直至所有顶点均被访问,搜索结束。

#include<iostream>
using namespace std;
#include<vector>
#include<set>
#include<unordered_set>
#include<map>class Graph{private:map<char, vector<char>> graph;  //创建图,graph记录图的节点及邻接关系public:void add_edge(char node, vector<char> neibors){graph[node] = neibors;}void dfs_helper(char node, map<char, int>& visited){visited[node] = 1;cout << node << " ";for(auto n: graph[node]){// 判断当前节点的邻接节点有无被访问if(visited[n] != 1)dfs_helper(n, visited);}}void dfs(char start_node){map<char,int> visited; // visited数组用来记录所有被访问过的顶点,被访问过,就记为1dfs_helper(start_node, visited);}  
};int main(){Graph graph;graph.add_edge('A', {'B', 'C'});graph.add_edge('B', {'A', 'D', 'E'});graph.add_edge('C', {'A', 'F'});graph.add_edge('D', {'B'});graph.add_edge('E', {'B', 'F'});graph.add_edge('F', {'C', 'E'});graph.dfs('A');
}

 

2、实现广度优先搜索

题目:如下无向图,从节点A开始遍历,其广度优先搜索为:A B D C E,从节点B开始遍历,其广度优先搜索为:B A C D E。

思路:广度优先搜索,利用队列来实现。把访问到的顶点入队,再访问该顶点的所有相邻的顶点,等访问完了该顶点的邻接点,再出队顶点和其相邻的顶点,每出队一个,就入队该顶点的未访问过的邻接顶点,重复上述步骤,直到队列为空。

#include<iostream>
#include<queue>
#include<map>
using namespace std;
class Graph{private:map<char, vector<char>> graph;  //创建图,graph记录图的节点及邻接关系public:void add_edge(char node, vector<char> neibors){graph[node] = neibors;}// 层次(广度)遍历void bfs(char node){map<char, int> visited; // visited数组用来记录所有被访问过的顶点,被访问过,就记为1queue<char> que;que.push(node);visited[node] = 1;while(!que.empty()){char temp = que.front(); //出队que.pop();cout << temp << " ";node = temp; //记录出队的点for(auto neibor: graph[node]){if(visited[neibor] != 1)que.push(neibor); //访问出队点的邻接点,并入队visited[neibor] = 1; //已访问的顶点标记为1}}}
};int main(){Graph graph;graph.add_edge('A', {'B', 'D'});graph.add_edge('B', {'A', 'C', 'D'});graph.add_edge('C', {'B', 'D', 'E'});graph.add_edge('D', {'A', 'B', 'C', 'E'});graph.add_edge('E', {'C', 'D'});graph.bfs('B');
}

 

3、利用拓扑排序判断图是否有环路。

题目如下有向图,判断是否存在环路。如果不为树,输出其拓扑排序。

思路通过BFS实现拓扑排序。

(1)首先计算每个节点的入度,将所有入度为0的节点放入队列中

(2)开始执行BFS,我们取队首的节点u,放入结果中;移除u的所有出边,即将u的所有相邻节点的入度减少1,判断如果某个相邻的节点v的入度变为0,就将v放入队列中。

(3)当BFS结束后,如果答案中包含的节点数和图中的节点数相等,那么就得到了图G的拓扑排序,否则说明图中存在环,不存在拓扑排序。

// 利用拓扑排序判断有向图是否存在回路
#include<iostream>
#include<map>
#include<vector>
#include<queue>
using namespace std;
class Graph{private:map<char, vector<char>> graph;public:void add_edge(char node, vector<char> neibors){graph[node] = neibors;}// 广度优先搜索+队列判断void has_cycle(){map<char, int> indegree; //记录每个顶点的入度,默认为0for(auto g: graph){indegree[g.first] = 0;}//计算每个顶点的入度for(auto g: graph){char n = g.first;for(auto nei: graph[n]){indegree[nei] += 1;}}// 1、将所有入度为0的顶点入队queue<char> que;for(auto in: indegree){char c = in.first;if(in.second == 0)que.push(c);}// 2、开始执行BFS,每出队一个顶点,就将该顶点的所有边移除,// 即将该顶点所有相邻节点的入度减1,如果某个相邻节点的入度变为0,就将该节点放入队列中vector<char> tuopu;while(!que.empty()){char temp = que.front();que.pop();tuopu.push_back(temp);for(auto neibor: graph[temp]){indegree[neibor] -= 1;if(indegree[neibor] == 0)que.push(neibor);}}// 3.判断拓扑排序结果里的顶点个数,如果和图的个数相等,则没有环if(tuopu.size() == graph.size()){cout << "该图没有环,为树" << endl << "拓扑排序为:";for(auto t: tuopu){cout << t << " ";}    }elsecout << "该图有环,不为树";}
};int main(){// 没有环Graph graph;graph.add_edge('A', {'B', 'C'});graph.add_edge('B',{});graph.add_edge('C',{'D','E'});graph.add_edge('D', {'B'});graph.add_edge('E', {});graph.has_cycle();// 有环Graph graph2;graph2.add_edge('A', {'B', 'C'});graph2.add_edge('B', {'C'});graph2.add_edge('C',{'D','E'});graph2.add_edge('D', {'B'});graph2.add_edge('E', {});graph2.has_cycle();return 0;
}

 

4、计算图的边数

题目:给定如下无向图,输出该图的边数7。

思路:遍历图中的节点,若该节点的邻接节点没有被访问,则边数count+1。

#include<iostream>
#include<queue>
#include<map>
using namespace std;
class Graph{private:map<char, vector<char>> graph;  //创建图,graph记录图的节点及邻接关系public:void add_edge(char node, vector<char> neibors){graph[node] = neibors;}// 计算图的边数void getNumsofEdge(){map<char, int> visited; //记录节点是否访问int count = 0;// 遍历graph中的节点与邻接节点for(auto g: graph){char n = g.first;for(auto neibor: graph[n]){if(visited[neibor] != 1){count += 1;}// 每遍历一个节点,就将该节点标记为1visited[n] = 1;}}cout << count;}
};
int main(){Graph graph;graph.add_edge('A', {'B', 'D'});graph.add_edge('B', {'A', 'C', 'D'});graph.add_edge('C', {'B', 'D', 'E'});graph.add_edge('D', {'A', 'B', 'C', 'E'});graph.add_edge('E', {'C', 'D'});graph.getNumsofEdge();
}

 

5、找到两个顶点之间的最短路径

题目:如下无向图,A到F的路径有A->B->C->E->F,A->B->C->F,A->D->E->F,输出最短路径A->D->E->F。

 思路:广度优先搜索(BFS)+ 队列实现。

(1)准备queue和map,queue用于BFS,map<char, vector<char>>用于存储当前最短距离。

(2)BFS,将顶点node1入队,并向Map中添加键值对。

(3)当队列非空时,进行循环。现将队首元素x出队,当前路径等x的当前路径,然后遍历x的邻接节点,如果邻接点中的某个节点tmp不在map键值对中(相当于未访问过), 就向Map中加入键值对<tmp,当前路径>,并将tmp入队,如果tmp为node2,就返回Map中tmp对应的路径。

#include<iostream>
#include<queue>
#include<map>
using namespace std;
class Graph{private:map<char, vector<char>> graph;  //创建图,graph记录图的节点及邻接关系public:void add_edge(char node, vector<char> neibors){graph[node] = neibors;}// 计算两个顶点的最短路径:A->B->D->Fvector<char> getShortPath(char node1, char node2){map<char, vector<char>> ShortPath;  //用于存储当前最短路径queue<char> q; //用于广度优先搜索// 如果求自身到自身的最短路径,返回node1->node2if(node1 == node2){return {node1, node2};}//否则将node1入队,并向map中加入键值对q.push(node1);ShortPath[node1] = {node1};while(!q.empty()){char temp = q.front();q.pop();vector<char> path = ShortPath[temp];for(auto neibor: graph[temp]){if(ShortPath.find(neibor) == ShortPath.end()){// 如果邻接节点不在map中(相当于未访问过),就向map中加入键值对ShortPath[neibor] = path;ShortPath[neibor].push_back(neibor);q.push(neibor);if(neibor == node2)return ShortPath[neibor];}}}return {};}
};
int main(){Graph graph;graph.add_edge('A', {'B', 'D'});graph.add_edge('B', {'A', 'C', 'D'});graph.add_edge('C', {'B', 'D', 'E'});graph.add_edge('D', {'A', 'B', 'C', 'E'});graph.add_edge('E', {'C', 'D', 'F'});graph.add_edge('F', {'C','E'});vector<char> short_path = graph.getShortPath('A', 'F');for(auto s: short_path){cout << s;}      
}

 

 

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

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

相关文章

深入解析Python装饰器及*args, **kwargs的妙用

深入解析Python装饰器及*args, **kwargs的妙用 简介&#xff1a; ​ 装饰器&#xff08;Decorator&#xff09;是 Python 中一种强大的语法特性&#xff0c;它允许在不修改原始函数代码的情况下&#xff0c;动态地扩展函数的功能。装饰器是函数或类&#xff0c;用于包装其他函…

云上荆楚丨云轴科技ZStack成功实践精选(湖北)

湖北自古以来有九省通衢的美称&#xff0c;地处长江中游&#xff0c;富有荆楚之美誉&#xff0c;灵秀之蕴意。2022年湖北数字经济强省三年行动计划正式印发&#xff0c;计划到“十四五”末&#xff0c;数字经济核心产业增加值力争达到7000亿元&#xff0c;占GDP的比重超过12%。…

《每天一分钟学习C语言·七》指针、字节对齐等

1、 对于二维数组如a[3][4]可以当做有三个元素的一维数组&#xff0c;每个元素包含四个小元素。 2、 printf(“%-5d”, i); //负号表示左对齐&#xff0c;5d表示空五个光标的位置 3、 栈&#xff1a;先进后出&#xff0c;堆&#xff1a;先进先出 4、 &#xff08;1&#xff…

位运算:Leetcode137.只出现一次的数字(2)

题目描述&#xff1a; 给你一个整数数组 nums &#xff0c;除某个元素仅出现 一次 外&#xff0c;其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。 示例 1&#xff1a; 输入&#xff1a;nums [2,2,3,2] 输出&#xff1a;3示例 2&#xff1a; 输入&…

《工具箱-SVN》SVN安装、备份、迁移教程

文章目录 一、服务器搭建SVN1.检查SVN是否存在2.安装SVN3.创建版本库4.创建版本库存放文件地址5.修改配置文件5.1 vim authz5.2 vim passwd5.3 vim svnserve.conf 6.启动并查看SVN7.SVN Checkout8.SVN Update9.SVN Commit 二、SVN-无法连接主机&#xff0c;目标计算机积极拒绝&…

案例 | 电源自动检测测试系统为某电子科技公司定制电源测试解决方案

一、测试背景 陕西某电子科技公司是一家专业生产设计军品电源、集成电路以及电子元器件的高新技术企业&#xff0c;公司虽有一套半自动ATE测试系统&#xff0c;但使用过程繁琐复杂且无法满足日益增长的测试需求&#xff0c;因此公司现需要一套更加优秀的全自动电源测试系统来应…

工具系列:PyCaret介绍_多分类代码示例

&#x1f44b; 工具系列&#xff1a;PyCaret介绍_多分类代码示例 PyCaret 介绍 PyCaret是一个开源的、低代码的Python机器学习库&#xff0c;可以自动化机器学习工作流程。它是一个端到端的机器学习和模型管理工具&#xff0c;可以大大加快实验周期并提高生产效率。 与其他开…

HDFS NFS Gateway(环境配置,超级详细!!)

&#x1f42e;博主syst1m 带你 acquire knowledge&#xff01; ✨博客首页——syst1m的博客&#x1f498; &#x1f618;《CTF专栏》超级详细的解析&#xff0c;宝宝级教学让你从蹒跚学步到健步如飞&#x1f648; &#x1f60e;《大数据专栏》大数据从0到秃头&#x1f47d;&…

【论文阅读】FreeU: Free Lunch in Diffusion U-Net

FreeU: 无需训练直接提升扩散模型生成效果。 paper&#xff1a;https://arxiv.org/abs/2309.11497 code&#xff1a;GitHub - ChenyangSi/FreeU: FreeU: Free Lunch in Diffusion U-Net 1. 介绍 贡献&#xff1a; •研究并揭示了U-Net架构在扩散模型中去噪的潜力&#xff0…

Redis单机、主从、哨兵、集群配置

单机配置启动 Redis安装 下载地址&#xff1a;Download | Redis 安装步骤&#xff1a; 1: 安装gcc编译器&#xff1a;yum install gcc 2: 将下载好的redis‐5.0.3.tar.gz文件放置在/usr/local文件夹下&#xff0c;并解压redis‐5.0.3.tar.gz文件 wget http://download.re…

react生命周期详解,代码示例(新生命周期,与旧生命周期对比)

旧生命周期&#xff1a;https://blog.csdn.net/kkkys_kkk/article/details/135130549?spm1001.2014.3001.5501 目录 React 生命周期中常见的坑 为什么要移除 “will” 相关生命周期方法呢&#xff1f; Fiber是什么 新生命周期图示 新增生命周期与功能变化 完整生命周期…

C语言操作符详解+运算符优先级表格

目录 前言 一、操作符是什么&#xff1f; 二、操作符的分类 三、算术操作符 四、逻辑操作符 五、比较操作符 六、位操作符 七、赋值操作符 八、其他操作符 九、运算符优先级表格 总结 前言 在编写程序时&#xff0c;最常用到的就是操作符&#xff0c;本文将详细的介绍…

Golang 的内存管理

文章目录 1.内存管理角色1.常见的内存分配方法线性分配器空闲链表分配器TCMalloc 2.Go 内存管理组件mspanmcache初始化替换微分配器 mcentralmheap 3.内存分配4.内存管理思想参考文献 1.内存管理角色 内存管理一般包含三个不同的组件&#xff0c;分别是用户程序&#xff08;Mu…

【C语言】指针详解(三)

1.指针运算 指针的基本运算有三种&#xff0c;分别是:⭐指针-整数 ⭐指针-指针 ⭐指针的关系运算 1.1指针 - 整数 因为数组在内存中是连续存放的&#xff0c;只要知道第一个元素的地址&#xff0c;顺藤摸瓜就能找到后面的所有元素。 int arr[10]{1,2,3,4,5,6,7,8,9,10} #inc…

劈窗算法反演地表温度

目录 摘要操作步骤提取热红外单波段提取NDVI同步像元分辨率与个数劈窗算法地表温度反演制图 摘要 主要使用HJ-2&#xff08;环境减灾二号卫星&#xff09;的IRS传感器的两个热红外波段&#xff0c;以及红波段与近红波段计算得到的NDVI&#xff0c;使用劈窗算法&#xff0c;得到…

贪吃蛇(五)蛇撞墙

上节我们实现了蛇身向右移动的功能&#xff0c;原理就是增加一个节点&#xff0c;删除一个节点。 本节我们处理蛇撞墙重置的功能 实现原理 在移动函数中检查蛇头&#xff08;链表尾节点&#xff09;是否达到墙边的坐标&#xff0c;这里有四种撞墙的情况&#xff1a; 上墙&am…

使用Docker-镜像命令

镜像名称一般分两部分组成:[repository]:[tag] 在没有指定tag时&#xff0c;默认是latest&#xff0c;代表最新版本的镜像 案例一&#xff1a;从DockerHub中拉取一个nginx镜像并查看 1.1. 首先去镜像仓库搜索nginx镜像&#xff0c;比如DockerHub 点击nginx 复制拉取命令 1.2.…

MySQL中替换字符串中的指定部分之REPLACE函数

REPLACE函数是用来替换字符串中的指定部分内容的。在本文中&#xff0c;将介绍如何在MySQL中使用REPLACE函数进行字符串替换 REPLACE函数的语法&#xff1a; REPLACE(str, search_str, replace_str) 其中&#xff0c;str是要进行替换操作的字符串&#xff0c;search_str是要搜…

使用Mosquitto/python3进行MQTT连接

一、简介 MQTT(消息队列遥测传输)是ISO 标准(ISO/IEC PRF 20922)下基于发布/订阅范式的消息协议。它工作在 TCP/IP协议族上&#xff0c;是为硬件性能低下的远程设备以及网络状况糟糕的情况下而设计的发布/订阅型消息协议&#xff0c;为此&#xff0c;它需要一个消息中间件。 …

【CMake保姆级教程】制作动静态链接库、指定动静态库输出路径

文章目录 前言一、动静态链接库的介绍1.1 动态链接库 (DLL)1.2 静态链接库 (LIB) 二、制作静态库三、制作动态库四、指定动静态库输出路径4.1 方式1 - 适用于动态库4.2 方式2 - 都适用 总结 前言 在软件开发中&#xff0c;我们经常听到动态链接库&#xff08;Dynamic Link Lib…