[Algorithm]图
一.图的算法
邻接矩阵表示的数据结构
1 #define INFINITY INT_MAX // 无穷大
2 #define MAX_VERTEX_NUM 20 // 限制顶点最大数值为20个
3 #define MAX_ARC_NUM MAX_VERTEX_NUM * (MAX_VERTEX_NUM - 1) // 由n个顶点,最多可以确定n(n-2)/2条直线,有向图为2倍
4 #define MAX_INFO 20 // 用户输入的弧信息,最多20个字符
5
6 /*数组表示法*/
7 typedef int VRType;
8 typedef char InfoType;
9 typedef char VertexType[5];
10 typedef enum {DG, DN, UDG, UDN} GraphKind;
11
12 typedef struct ArcCell {
13 VRType adj;
14 InfoType *info;
15 }ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
16
17 typedef struct {
18 VertexType vexs[MAX_VERTEX_NUM];
19 AdjMatrix arcs;
20 int vexnum, arcnum;
21 }MGraph;
邻接表表示的数据结构
1 /*邻接表表示法*/
2 typedef struct ArcNode
3 {
4 int adjvex;
5 int w; // 存储权值,书中的程序没有表示权值的数据成员(书中说用info来存储权值,但是上面的程序又是单独用的adj存权值,为了一致性,info还是用来存储其他信息算了)
6 struct ArcNode *nextarc;
7 InfoType *info; // 用来存储权值以外的有关弧的信息
8 }ArcNode;
9
10 typedef struct VNode
11 {
12 VertexType data;
13 ArcNode *firstarc;
14 }VNode, AdjList[MAX_VERTEX_NUM];
15
16 typedef struct
17 {
18 AdjList vertices;
19 int vexnum, arcnum;
20 int kind;
21 }ALGraph;
1.写出从图的邻接表表示转换成邻接矩阵表示的算法
1 void Convert( ALGraph G, int arcs[][10] )
2 {
3 for ( int v = 0; v < G.vexnum; v++ )
4 for ( ArcNode* p = G.vertices[v].firstarc; p; p->nextarc )
5 arcs[v][p->adjvex] = 1;
6 }
二.图的遍历
说明: 以下图的算法既可以使用邻接矩阵的方式也可以使用邻接表存储的方式,因此每种算法都可以换成另一种存储形式,只需要把MGraph(邻接矩阵存储)换成ALGraph(邻接表存储)即可
基本数据结构:
邻接矩阵下,通用找邻接的函数:
1 // 第一个邻居
2 int FirstNeighbor( MGraph G, int v)
3 {
4 for ( int i = 0; i < G.vexnum; i++ )
5 if ( G.arcs[v][i] == 1 )
6 return i;
7 return -1;
8 }
9 // 当前的下一个邻居
10 int NextNeighbor( MGraph G, int v, int w )
11 {
12 for (int i = w+1; i < G.vexnum; i++ )
13 if ( G.arcs[v][i] == 1 )
14 return i;
15 return -1;
16 }
邻接表下,通用找邻接的函数:
1 /*全局变量*/
2 bool Visited[MAX_VERTEX_NUM]; // 记录每个顶点是否被访问过
3
4 // 找到第一个v相邻的顶点,返回它的下标
5 int FirstAdjVex(ALGraph &AL, int v)
6 {
7 ArcNode *p = NULL;
8 p = AL.vertices[v].firstarc;
9 if (p == NULL)
10 return -1;
11 else
12 return p->adjvex;
13 }
14
15 // 找到下一个与v相邻的顶点,返回它的下标
16 int NextAdjVex(ALGraph &AL, int v, int w)
17 {
18 ArcNode *p = NULL;
19 p = AL.vertices[v].firstarc;
20 while (p->adjvex != w) // 找到下标为w的结点
21 p = p->nextarc;
22 p = p->nextarc; // 指针指向下标为w的结点的后面一个结点
23 if (p == NULL)
24 return -1;
25 else
26 return p->adjvex;
27 }
1.广度优先搜索(Breadth-First-Search, BFS)
法一:采用邻接矩阵
1 bool visited[MAX_VERTEX_NUM] = { false };
2 void BFS( MGraph G, int v );
3
4 void BFSTraverse( MGraph G )
5 {
6 int Q[MAXSIZE];
7 int front = -1, rear = -1;
8 for (int v = 0; v < G.vexnum; v++ )
9 if ( !visited[v] )
10 BFS( G, v );
11 }
12
13 void BFS( MGraph G, int v )
14 {
15 int Q[MAXSIZE];
16 int front = -1, rear = -1;
17 // BFS顶点三连
18 visit( v );
19 visited[v] = true;
20 Q[++rear] = v;
21
22 while ( front != rear )
23 {
24 v = Q[++front];
25 for ( int w = FirstNeighbor( G, v ); w >= 0; w = NextNeighbor( G, v, w ) )
26 {
27 if (!visited[w])
28 {
29 // BFS顶点三连
30 visit( w );
31 visited[w] = true;
32 Q[++rear] = w;
33 }
34 }
35 }
36 }
法二:采用邻接表
1 bool visited[MAX_VERTEX_NUM] = { false };
2 void BFS( ALGraph G, int v );
3
4 void BFSTraverse( ALGraph G )
5 {
6 int Q[MAXSIZE];
7 int front = -1, rear = -1;
8 for (int v = 0; v < G.vexnum; v++ )
9 if ( !visited[v] )
10 BFS( G, v );
11 }
12
13 void BFS( ALGraph G, int v )
14 {
15 int Q[MAXSIZE];
16 int front = -1, rear = -1;
17 // BFS顶点三连
18 visit( v );
19 visited[v] = true;
20 Q[++rear] = v;
21
22 while ( front != rear )
23 {
24 v = Q[++front];
25 for ( int w = FirstNeighbor( G, v ); w >= 0; w = NextNeighbor( G, v, w ) )
26 {
27 if (!visited[w])
28 {
29 // BFS顶点三连
30 visit( w );
31 visited[w] = true;
32 Q[++rear] = w;
33 }
34 }
35 }
36 }
2.BFS算法求解单源最短路径问题
1 bool visited[MAXSIZE] = { false };
2 unsigned int d[MAXSIZE] = { INFINITE };
3 void BFS_MIN_Distance( ALGraph G, int u )
4 {
5 BiTree Q[MAXSIZE];
6 int front = -1, rear = -1, v, w;
7 // BFS路径三连
8 d[u] = 0;
9 visited[u] = true;
10 Q[++rear] = u;
11
12 while ( front != rear )
13 {
14 v = Q[++front];
15 for ( w = FirstNeighbor( G, v ); w >= 0; w = NextNeighbor( G, v, w ) )
16 {
17 if (!visited[w])
18 {
19 // BFS路径三连
20 d[w] = d[v] + 1;
21 visited[w] = true;
22 Q[++rear] = w;
23 }
24 }
25 }
26 }
3.深度优先搜索(Depth-First-Search, DFS)
1 bool visited[MAX_VERTEX_NUM] = { false };
2 void DFS( ALGraph &G, int v );
3
4 void DFSTraverse( ALGraph &G )
5 {
6 for ( int v = 0; v < G.vexnum; v++ )
7 if ( !visited[v] )
8 DFS( G, v );
9 }
10
11 void DFS( ALGraph &G, int v )
12 {
13 visit( v );
14 visited[v] = true;
15 for ( int w = FirstNeighbor( G, v ); w >= 0; w = NextNeighbor( G, v, w ) )
16 if ( !visited[w] )
17 DFS( G, w );
18 }
4.设计一个算法,判断一个无向图G是否为一棵树
1 int visited[MAXSIZE] = { 0 };
2 void DFS( MGraph G, int v, int& Vnum, int& TD );
3
4 bool IsTree( MGraph G )
5 {
6 int Vnum = 0, TD = 0; // TD=total degree总度数
7 DFS( G, 0, Vnum, TD ); // 从第一个顶点开始遍历
8 if ( Vnum == G.vexnum&&TD == 2 * ( G.vexnum - 1 ) )
9 return true;
10 return false;
11 }
12
13 void DFS( MGraph G, int v, int& Vnum, int& TD )
14 {
15 visited[v] = true; Vnum++;
16 for ( int w = FirstNeighbor( G, v ); w >= 0; w = NextNeighbor( G, v, w ) )
17 if ( !visited[w] )
18 DFS( G, w, Vnum, TD );
19 }
5.写出图的深度优先搜索DFS算法的非递归算法
1 bool visited[MAXSIZE] = { false };
2 void DFS_NON_RC( MGraph G, int v )
3 {
4 int S[MAXSIZE];
5 int top = -1;
6 for ( int i = 0; i < G.vexnum; i++ )
7 visited[i] = false;
8 // 顶点二连
9 visited[v] = true;
10 S[++top] = v;
11
12 while ( top != -1 )
13 {
14 v = S[top--]; visit( v );
15 for ( int w = FirstNeighbor( G, v ); w >= 0; w = NextNeighbor( G, v, w ) )
16 if ( !visited[w] )
17 {
18 // 顶点二连
19 visited[w] = true;
20 S[++top] = w;
21 }
22 }
23 }
6.分别采用基于广度优先遍历和深度优先遍历算法判别以邻接表或邻接矩阵存储的有向图中是否存在由顶点v到顶点u的路径($v\neq u$)
// 采用BFS的方法
bool visited[MAXSIZE] = { false };
bool Exist_Path_BFS( MGraph G, int v, int u )
{
int Q[MAXSIZE];
int front = -1, rear = -1;
visited[v] = true;
Q[++rear] = v;
while ( front != rear )
{
v = Q[++front];
for ( int w = FirstNeighbor( G, v ); w >= 0; w = NextNeighbor( G, v, w ) )
{
if (!visited[w])
{
if ( w == u ) return true;
visited[w] = true;
Q[++rear] = w;
}
}
}
return false;
}
1 // 采用DFS的方法
2 bool visited[MAXSIZE] = { false };
3 bool Exist_Path_DFS( MGraph G, int v, int u )
4 {
5 if ( v == u ) return true;
6 visited[v] = true;
7 for ( int w = FirstNeighbor( G, v ); w >= 0; w = NextNeighbor( G, v, w ) )
8 {
9 if ( !visited[w] )
10 {
11 if ( Exist_Path_DFS( G, w, u ) ) return true;
12 }
13 }
14 return false;
15 }
7.拓扑排序:判断并输出有向图的拓扑序列
1 bool Topological( MGraph G, int indegree[] )
2 {
3 int S[MAXSIZE];
4 int top = -1, Vnum = 0, v = 0;
5 for ( v = 0; v < G.vexnum; v++ )
6 {
7 if ( indegree[v] == 0 )
8 {
9 visit( v );
10 Vnum++;
11 S[++top] = v;
12 }
13 }
14 while ( top != -1 )
15 {
16 v = S[top--];
17 for ( int w = FirstNeighbor( G, v ); w >= 0; w = NextNeighbor( G, v, w ) )
18 {
19 indegree[w]--;
20 if ( indegree[w] == 0 )
21 {
22 visit( w );
23 Vnum++;
24 S[++top] = w;
25 }
26 }
27 }
28 if ( Vnum == G.vexnum )
29 return true;
30 return false;
31 }
2.拓扑排序(DFS):有向无环图的拓扑排序
1 bool visited[MAXSIZE] = { false };
2 int time = 0, finishTime[MAXSIZE] = { 0 };
3 void DFS( MGraph G, int v );
4
5 void Topological_DFS( MGraph G )
6 {
7 for ( int v = 0; v < G.vexnum; v++ )
8 if ( !visited[v] )
9 DFS( G, v );
10 for ( int t = time - 1; t >= 0; t-- )
11 visit( finishTime[t] );
12 }
13
14 void DFS( MGraph G, int v )
15 {
16 visited[v] = true;
17 for ( int w = FirstNeighbor( G, v ); w >= 0; w = NextNeighbor( G, v, w ) )
18 if ( !visited[w] )
19 DFS( G, w );
20 finishTime[time++] = v;
21 }
[Algorithm]图的更多相关文章
- 最短路径--SPFA 算法
适用范围:给定的图存在负权边,这时类似Dijkstra等算法便没有了用武之地,而Bellman-Ford算法的复杂度又过高,SPFA算法便派上用场了. 我们约定有向加权图G不存在负权回路,即最短路径一 ...
- 图论——最短路:Floyd,Dijkstra,Bellman-Ford,SPFA算法及最小环问题
一.Floyd算法 用于计算任意两个节点之间的最短路径. 参考了five20的博客 Floyd算法的基本思想如下:从任意节点A到任意节点B的最短路径不外乎2种可能,1是直接从A到B,2是从A经过若干个 ...
- [转]带花树,Edmonds's matching algorithm,一般图最大匹配
看了两篇博客,觉得写得不错,便收藏之.. 首先是第一篇,转自某Final牛 带花树……其实这个算法很容易理解,但是实现起来非常奇葩(至少对我而言). 除了wiki和amber的程序我找到的资料看着都不 ...
- 从Random Walk谈到Bacterial foraging optimization algorithm(BFOA),再谈到Ramdom Walk Graph Segmentation图分割算法
1. 从细菌的趋化性谈起 0x1:物质化学浓度梯度 类似于概率分布中概率密度的概念.在溶液中存在不同的浓度区域. 如放一颗糖在水盆里,糖慢慢溶于水,糖附近的水含糖量比远离糖的水含糖量要高,也就是糖附近 ...
- 机器人路径规划其一 Dijkstra Algorithm【附动态图源码】
首先要说明的是,机器人路径规划与轨迹规划属于两个不同的概念,一般而言,轨迹规划针对的对象为机器人末端坐标系或者某个关节的位置速度加速度在时域的规划,常用的方法为多项式样条插值,梯形轨迹等等,而路径规划 ...
- 机器人路径规划其二 A-Star Algorithm【附动态图源码】
首先要说明的是,机器人路径规划与轨迹规划属于两个不同的概念,一般而言,轨迹规划针对的对象为机器人末端坐标系或者某个关节的位置速度加速度在时域的规划,常用的方法为多项式样条插值,梯形轨迹等等,而路径规划 ...
- Geeks Union-Find Algorithm Union By Rank and Path Compression 图环算法
相同是查找一个图是否有环的算法,可是这个算法非常牛逼,构造树的时候能够达到O(lgn)时间效率.n代表顶点数 原因是依据须要缩减了树的高度,也叫压缩路径(Path compression),名字非常高 ...
- Augmenting Path Algorithm : 一般图最大匹配
算法原理详见 http://www.csie.ntnu.edu.tw/~u91029/Matching.html orz 带花树很神奇,挖坑最大权匹配 #include <iostream> ...
- 挑子学习笔记:两步聚类算法(TwoStep Cluster Algorithm)——改进的BIRCH算法
转载请标明出处:http://www.cnblogs.com/tiaozistudy/p/twostep_cluster_algorithm.html 两步聚类算法是在SPSS Modeler中使用的 ...
随机推荐
- SQL Server 2008怎么自动备份数据库
在SQL Server 2008数据库中.为了防止数据的丢失我们就需要按时的来备份数据库了.要是每天都要备份的话,人工备份会很麻烦的,自动备份的话就不需要那么麻烦了,只 要设置好了,数据库就会自动在你 ...
- 循序渐进Python3(十三) --0-- django之form表单
django为我们提供了form表单验证功能,下面来学习一下: 武sir博客:http://www.cnblogs.com/wupeiqi/articles/5246483.html 创建了djan ...
- php SqlServer 中文汉字乱码
php SqlServer 中文汉字乱码,用iconv函数转换 查询显示的时候,从GB转换为UTF8 <?php echo iconv('GB2312','UTF-8',$row['Name'] ...
- chart左侧
左侧单位 Chart1.Axes.Left.Minimum := ; Chart1.Axes.Left.Maximum := Series1.YValues.MaxValue * ; Chart1.A ...
- mysql如何进行以=分割的字符串的拆分
SUBSTRING_INDEX(str, delim, count) str: 要处理的字符串 delim: 分割符 count: 计数 如果为正数,则从左开始数,如果为负数,则从右开始数 使用示例: ...
- 【原创】10. MYSQL++ 之 DbDriver
1. 综述 DbDriver只是对于MYSQL C API的一个非常简单的封装,作者原句是This class does as little as possible to adapt between ...
- Leetcode:Merge k Sorted Lists分析和实现
题目大意是传入一个链表数组lists,每个链表都由若干个链接的链表结点组成,并且每个链表结点记录一个整数.题目保证传入的链表中的整数按从小到大进行排序. 题目要求我们输出一个新的链表,这个链表中应该包 ...
- Java,Calendar -- 获取当前日期、当月月初日期、月末日期
public class CalendarTest { public static void main(String[] args) { // 获取当前年份.月份.日期 Calendar cale = ...
- LoadRunner简明教程
LoadRunner是什么 LoadRunner是一个性能测试工具,它最初是Mercury公司的产品,后背HP收购. LoadRunner常用来做什么 l 验证某系统在某环境下是否满足性能需求. l ...
- c++策略模式(Strategy Method)
别人的博客再讲策略模式时都会讲三国,策略类就是赵云的锦囊,锦囊里装着若干妙计.在打仗时想要用什么妙计,直接从锦囊里去取. 锦囊类: class context { public: context(IS ...