第五章.图基本算法

一.图的存储结构

1. 邻接矩阵(顺序存储结构)

typedef struct
{
	int no; //顶点编号
	char info; //顶点其他信息
}VertexType; //顶点类型
typedef struct
{
	int edges[maxSize][maxSize]; //邻接矩阵定义
	int n,e; //分别为顶点数和边数
	VertexType vex[maxSize]; //存放结点信息
}MGraph; //图的邻接矩阵类型

2. 邻接表(链式存储结构)

typedef struct ArcNode
{ //边结点表
	int adjvex; //该边所指向的结点的位置
	struct ArcNode *nextarc; //指向下一条边的指针
	int info; //该边的相关信息
}ArcNode;
typedef struct
{ //顶点表
	char data; //顶点信息
	ArcNode *firstarc; //指向第一条边的指针
}VNode;
typedef struct
{
	VNode adjlist[maxSize]; //邻接表
	int n,e; //顶点数和边数
}AGraph; //图的邻接表类型

二.图的遍历算法

1. DFS深度优先搜索遍历
算法执行过程:任取一个顶点,访问之,然后检查这个顶点的所有邻接顶点,递归访问其中未被访问过的顶点。

int visit[maxSize];
/* v是起点编号,visit[]是一个全局数组,作为顶点的访问标记,初始时所有元素*/
/* 均为0,表示所有顶点都未被访问过。因图中可能存在回路,当前经过的顶点在将*/
/* 来还可能再次经过,所以要对每个顶点进行标记,以免重复访问*/
void DFS(AGraph *G,int v)
{
	ArcNode *p;
	visit[v] = 1; //置已访问标记
	Visit(v); 
	p = G->adjlist[v].firstarc; //p指向顶点v的第一条边
	while(p != NULL)
	{
		if(visit[p->adjvex] == 0) //若顶点未访问,则递归访问它
			DFS(G,p->adjvex);
		p = p->nextarc; //p指向顶点v的下一条边的终点
	}
}

2. BFS广度优先搜索遍历
算法执行过程:
1). 任取图中一个顶点访问,入队,并将这个顶点标记为已访问
2). 当队列不空时循环执行:出队,依次检查出队结点的所有邻接顶点,访问没有被访问过的邻接顶点并将其入队
3). 当队列为空时跳出循环,广度优先搜索即完成

void BFS(AGraph *G,int v,int visit[maxSize])
{ //visit[]数组被初始化为全0
	ArcNode *p;
	int que[maxSize];
	int front = 0,rear = 0;
	int j;
	Visit(v);
	visit[v] = 1;
	rear = (rear + 1) % maxSize;
	que[rear] = v;
	while(front != rear) //队空的时候说明遍历完成
	{
		front = (front + 1) % maxSize; //顶点出队
		j = que[front];
		p = G->adjlist[j].firstarc; //p指向出队顶点j的第一条边
		while(p != NULL)
		{
			if(visit[p->adjvex] == 0) //当前邻接顶点未被访问,则入队
			{
				Visit(p->adjvex);
				visit[p->adjvex] = 1;
				rear = (rear + 1) % maxSize; //该顶点入队
				que[rear] = p->adjvex;
			}
			p = p->nextarc; //p指向j的下一条边
		}
	}
}

3.
在这里插入图片描述
在这里插入图片描述

int BFS(AGraph *G,int v)
{
	/*本题用邻接表作为图的存储结构*/
	ArcNode *p;
	int que[maxSize],front = 0,rear = 0;
	int visit[maxSize];
	int i,j;
	for(i=0;i<G->n;++i)
		visit[i] = 0; //将visit数组全部初始化为0
	rear = (rear + 1) % maxSize;
	que[rear] = v;
	visit[v] = 1;
	while(front != rear)
	{
		front = (front + 1) % maxSize;
		j = que[front];
		p = G->adjlist[j].firstarc;
		while(p != NULL)
		{
			if(visit[p->adjvex] == 0)
			{
				visit[p->adjvex] = 1;
				rear = (rear + 1) % maxSize;
				que[rear] = p->adjvex;
			}
			p = p->nextarc;
		}
	}
	return j; //队空时,j保存了遍历过程中的最后一个顶点
}

4.
在这里插入图片描述

void DFS(AGraph *G,int v,int &vn,int &en)
{
	ArcNode *p;
	visit[v] = 1;
	++vn; //本题中对当前顶点的访问即为vn计数器自增1
	p = G->adjlist[v].firstarc;
	while(p != NULL)
	{
		++en; //边数自增1
		if(visit[p->adjvex] == 0)
			DFS(G,p->adjvex,vn,en);
		p = p->nextarc;
	}
}
int GisTree(AGraph *G)
{
	int vn = 0,en = 0;
	for(i=0;i<G->n;++i)
		visit[i] = 0;
	DFS(G,1,vn,en);
	if(vn == G->n && (G->n-1) == en/2) //在每次来到一个新顶点,en累加了当前访问顶点的所有边,也就是说每条边访问了两次
	/*如果遍历过程中访问过的顶点数和图中的顶点数相等,且边数等于顶点数减1,则证明是树*/
		return 1;
	else
		return 0;
}

5.
在这里插入图片描述

int DFSTrave(AGraph *G,int i,int j)
{
	int k;
	for(k=0;k<G->n;++k)
		visit[k] = 0;
	DFS(G,i);
	if(visit[j] == 1) //visit[j]等于1则证明访问过程中遇到了j
		return 1;
	else
		return 0;
}

三.最小生成树

1.普里姆算法
在这里插入图片描述
在这里插入图片描述

void Prim(MGraph g,int v0,int &sum)
{
	int lowcost[maxSize],vset[maxSize],v;
	int i,j,k,min;
	v = v0;
	for(i=0;i<g.n;++i)
	{
		lowcost[i] = g.edges[v0][i]; //顶点v0到其余各定点的长度
		vset[i] = 0; //vset全部置为0
	}
	vset[v0] = 1; //将v0并入树中
	sum = 0; //sum清零用来累计树的权值
	for(i=0;i<g.n-1;++i) //循环n-1次
	{
		min = INF;
		/*下面这个循环用于选出侯选边中的最小值*/
		for(j=0;j<g.n;++j)
		{
			if(vset[j] == 0 && lowcost[j] < min) //选出当前生成树到其余各顶点最短边中的最短的一条
			{
				min = lowcost[j];
				k = j;
			}
		}
		vset[k] = 1;
		v = k;
		sum += min; //这里用sum记录了最小生成树的权值
		/*下面这个循环以刚并入的顶点v为媒介更新候选边*/
		for(j=0;j<g.n;++j)
		{
			if(vset[j] == 0 && g.edges[v][j] < lowcost[j]) //并入生成树的顶点无需更新
				lowcost[j] = g.edges[v][j];
		}
	}
}

2.克鲁斯卡尔算法

typedef struct
{
	int a,b; //a,b为一条边所连的两个顶点
	int w; //边的权值
}Road;
Road road[maxSize];
int v[maxSize]; //定义并查集数组
int getRoot(int a)
{
	while(a != v[a])
		a = v[a];
	return a;
}
void Kruskal(MGraph g,int &sum,Road road[])
{
	int i;
	int N,E,a,b;
	N = g.n; //顶点数
	E = g.e; //边数
	sum = 0;
	for(i=0;i<N;++i)
		v[i] = i;
	sort(road,E); //对road数组中的E条边按其权值从小到大排序
	for(i=0;i<E;++i)
	{
		a = getRoot(road[i].a);
		b = getRoot(road[i].b);
		if(a != b)
		{
			v[a] = b; //把b赋值给a,即将b作为a的父结点
			sum += road[i].w;
		}
	}
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值