数据结构之图
图#
逻辑结构与内存结构#
结构实现#
- 邻接矩阵实现
- 邻接表实现
typedef int VertexType;
typedef struct ArcNode
{
/*单链表中结点类型*/
int adjvex; //该边指向的顶点在顺序表中的位置
int* weight; //边的权重
struct ArcNode* next; //下一条边
}ArcNode;
typedef struct
{
VertexType data; //顶点中的数据信息
ArcNode* firstarc; //指向单链表,即第一条边
}VNode;
方法#
- 生成图
- 深度优先遍历
- 广度优先遍历
重要算法#
最小生成树算法
-
Kruskal算法(加边法)(用并查集实现)
-
并查集
-
Prim算法(加点法)
拓扑排序
- 拓扑排序算法
- 关键路径求解算法
最短路径算法
- 迪杰斯特拉算法
- 弗洛伊德算法
在这篇文章中我就只放上生成图以及深搜宽搜等算法,后面会专门上图的其他重要算法
基础生成等算法#
#include<iostream>
#include<queue>
using namespace std;
typedef int VertexType;
int visited[20];
typedef struct ArcNode
{
/*单链表中结点的类型*/
int adjvex; //邻接点在主顺序表中的下标
int weight; //与该邻接点形成的边的权值
struct ArcNode* next; //下一个邻接点 即边
}ArcNode;
typedef struct VNode
{
VertexType data; //该点所存储的数据
ArcNode* firstArc; //第一个邻接点
}VNode;
void CreateGraph(VNode G[], int n);
int FitstAdj(VNode G[], int v);
int NextAdj(VNode G[], int v);
void DFS_Travel(VNode G[], int v);
void DFS(VNode G[], int n);
void BFS(VNode G[], int v);
void BFS_Travle(VNode G[], int n);
//int main()
//{
// return 0;
//}
//生成图
void CreateGraph(VNode G[], int n)
{/*
图的生成算法有很多很多,一般都只需要根据题目输入要求进行改动就行了,这里是
按每个节点顺序来输入边的。
*/
for (int i = 0; i < n; i++)
{
G[i].data = i; //顶点i
G[i].firstArc = NULL; //初始化将邻边置NULL
ArcNode* p = NULL,*q = NULL;
int v; //输入邻接点 v
cin >> v;
while (v!=-1) //一次记录输入邻接点v,当输入-1时表明此顶点i已经录完所有的邻接点了
{
q = new ArcNode; //对邻接点v初始化数据
q->adjvex = v;
q->next = NULL;
q->weight = 0;
if (G[i].firstArc == NULL) //判断是否是第一个邻接点,如果是就连着顶点i的第一个位置
G[i].firstArc = q;
else //如果不是第一个就连着前一个邻接点的后面
p->next = q;
p = q; //p始终在邻接点q的前一个
cin >> v; //输入下一个邻接点,如果是-1将退出到下一个顶点的数据录入
}
}
}
//获得该点的首个邻接点的下标
int FitstAdj(VNode G[], int v)
{
if (G[v].firstArc != NULL) //获取顶点v的第一个邻接点
return G[v].firstArc->adjvex;
else
return -1; //说明该点无邻接点
}
//获得下一个未访问的邻接点
int NextAdj(VNode G[], int v)
{
if (G[v].firstArc == NULL) //说明顶点v无邻接点
return -1;
else
{
ArcNode* p = G[v].firstArc; //p标记为v的邻接点
while (p != NULL)
{
if (visited[p->adjvex] == 0)//如果该邻接点未被访问过
return p->adjvex; //返回该节点下标
else
p = p->next; //该邻接点被访问过 进入到下一个邻接点的判断
}
return -1; //说明所有的邻接点都被访问了,返回-1表明无邻接点了
}
}
//深度优先遍历实现
void DFS(VNode G[], int n)
{
for (int i = 0; i < n; i++)
{
visited[i] = 0; //将所有节点初始化为未访问状态
}
for (int i = 0; i < n; i++)
{
if (visited[i] == 0) //如果该节点i没有访问过就进行深度遍历
{
DFS_Travel(G, i);
}
}
}
//深度优先遍历
/*
深度优先遍历,对于一个节点v,会先访问它的一个邻接点,然后以这个邻接点为起点去访问这个邻接点的邻接点,这样
就渐渐的往下延申,当不能再延申的时候再往前回退一下,就像树根在土里往下延申一样,这是我的一点理解
*/
void DFS_Travel(VNode G[],int v)
{
cout << G[v].data << endl; //访问节点v的内容
visited[v] = 1; //将节点v的状态置为已经访问过
int w = FitstAdj(G, v); //获取节点v的第一个邻接点
while (w != -1) //如果存在邻接点
{
if (visited[w] == 0) //判断该邻接点是否访问过,没有访问则以该节点开始进行深度遍历
DFS_Travel(G, w);
w = NextAdj(G, v); //获得节点v的下一个邻接点
}
}
//广度优先实现
/*
广度优先:对于节点v 广度优先遍历会先访问v的所有邻接点,将v的邻接点访问完后就开始访问v的邻接点的所有邻接点,
这样就像在一圈一圈散出去,这是我比较值观的理解。
*/
void BFS(VNode G[], int v)
{
queue<int> q; //用队列来存储邻接点下标
cout << G[v].data << endl; //访问元素
visited[v] = 1; //访问状态置为已经访问
q.push(v); //入队列
int w; //标记邻接点
while (!q.empty()) //循环为队列非空
{
v = q.front(); //将队头元素出队列
q.pop();
w = FitstAdj(G, v); //获得首个邻接点
while (w != -1)
{
if (visited[w] == 0) //如果该节点没有访问过
{
cout << G[w].data << endl;//访问元素
visited[w] = 1; //访问状态置为已经访问
q.push(w); //将该节点入队列
}
w = NextAdj(G, v); //寻找下一个未访问的邻接点
}
}
}
//广度优先遍历
void BFS_Travle(VNode G[], int n)
{
for (int i = 0; i < n; i++) //将所有点都置为未访问过
visited[i] = 0;
for (int i = 0; i < n; i++)
{
if (visited[i] == 0) //对没有访问过的节点进行广度优先访问
BFS(G, i);
}
}```
作者:墨鱼-yyyl
出处:https://www.cnblogs.com/moyu-yyyl/p/18009720
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律