7.8总结与提高

本文深入探讨了图的理论及其在信息技术中的应用,包括图的存储结构如邻接矩阵和邻接表,以及图的遍历算法如深度优先遍历(DFS)和广度优先遍历(BFS)。通过实例展示了如何利用BFS寻找特定长度的最短路径,以及如何使用DFS找到包含所有顶点的简单路径。此外,还讨论了在实际问题中,如何利用图的算法解决最小运输成本问题,即寻找图的中心顶点。这些算法在图论和计算机科学中具有广泛的应用价值。

7.8总结与提高

主要知识点

  • (1)基本概念
    图中顶点间的关系可以任意的,因此图是最复杂的非线性结构,它的表达力强。
    图具有有向图、无向图、连通图、强连通图、完全图、赋权图等多种类型。
  • (2)图的存储结构
    图的存储方式一般有两类,用边的集合方式有邻接矩阵,链接方式有邻接表、 十字链表、邻接多重表。
    邻接矩阵和邻接表是两种常用的存储结构,适用于有向图(网)和无向图(网) 表示与处理。
  • (3)图的基本操作
    由于图中结点间可以是多对多的关系,为实现图的遍历必须设置访问标志数 组,以防止走回路或未访问到。 图的遍历规律有两种:深度优先遍历 DFS 和广度优先遍历 BFS。可用用邻 接矩阵和邻接表实现深度优先遍历和广度优先遍历算法。
    深度优先遍历算法是以递归技术为支持,而广度优先遍历算法是以队列技术为支持。
  • (4)图的应用: 图的遍历算法是图应用的重要基础。求解生成树、最小生成树、连通分量, 拓扑排序、关键路径、单源最短路径及所有顶点之间的最短路径的重要算法应用。

典型题例

例 1 求距离顶点 v0 的最短路径长度为 k 的所有顶点 已知无向图 g,设计算法求距离顶点 v0 的最短路径长度为 K 的所有顶点,要求尽可能节省时间

问题分析】由于题目要求找出最短路径长度为 k 的所有顶点,故从顶点 v0 开 始进行广度优先搜索,将一步可达的、两步可达的…直至 k 步可达的所有顶点记 录下来,同时用一个队列记录每个结点的层号,输出第 K+1 层的所有结点即为所求。

算法描述

void bfsKLevel(Graph  g,  int  v0,  int  K) 
{ 
	InitQueue( Q1);              /* Q1 是存放已访问顶点的队列 */ 
	InitQueue( Q2);              /* Q2 是存放已访问顶点层号的队列 */ 
	for ( i=0; i < g .vexnum; i++)   
		visited[i]=FALSE;         /* 初始化访问标志数组 */ 
	visited[v0]=TRUE;  
	Level=1; 
	EnterQueue( Q1, v0); 
	EnterQueue( Q2, Level); 
	while (! IsEmpty( Q1) && Level<K+1) 
	{ 
		v=DeleteQueue( Q1);          /* 取出已访问的顶点号 */ 
		Level=DeleteQueue( Q2);       /* 取出已访问顶点的层号 */ 
		w=FirstAdjVertex(g, v);         /* 找第一个邻接点 */ 
		while ( w!=-1 ) 
		{ 
			if (! visited[w] ) 
			{ 
				if  (Level==K)  
					printf(%d”, w);    /* 输出符合条件的结点 */ 
				visited[w]=TRUE; 
				EnterQueue( Q1,  w); 
				EnterQueue( Q2,  Level+1);    
			} 
			w=NextAdjVertex(g, v, w);         /* 找下一个邻接点 */ 
		} 
	} 
} 

例 2 设计算法在图 g 中找出一条包含所有顶点的简单路径

问题分析】从任一顶点开始进行深度优先搜索,同时记录当前路径结点序列和 当前路径结点数目。当递归进层时结点数目加 1,当递归退层时结点数目减 1, 当结点数目等于结点总数时,输出当前路径结点序列,成功返回。

算法描述

int visited[MAX_VERTEX_NUM]; 
int path[MAX_VERTEX_NUM];             /* 记录路径上的顶点序列 */ 
int n;                                    /* 记录路径上的顶点数 */ 
int DepthFirstSearch(Graph  g ,  int  v0) /* 用递归的深度优先搜索法在图 g 中寻找一条包含所有顶点的简单路径。 从当前结点 v0 成功找到时返回 1,否则返回 0 */ 
{ 
	visited[v0]=TRUE;                   /* 设置访问标志 */ 
	n=n+1;           /* 递归进层时,路径上顶点数加 1 */ 
	path[n]=v0;       /* 保存路径上的顶点 */ 
	if (n==g .vexnum )   
	{ 
		Display(path);              /* 找到一条包含所有顶点的简单路径 */ 
		return 1;                       /* 成功返回 */ 
	} 
	w= FirstAdjVertex (g, v0);    /* 找第一个邻接点 */ 
	while (w!=-1) 
	{ 
		if (! visited[w] && DepthFirstSearch (g, w)==1)  
			return 1;  /* 从邻接点 w 往下搜索,且成功返回 */ 
		w=NextAdjVertex (g, v0, w);  /* 找下一个邻接点 */ 
	} 
	visited[v0]=FALSE;     /* 递归退层时,取消访问标志,以便重新遍历该顶点 */ 
	n=n-1;       /* 递归退层时,路径上顶点数减 1 */ 
	return  0;             /* 从当前结点v0出发,无法找到解路径,失败返回 */ 
} 
void Hamilton(Graph  g) 
{ 
	for ( i=0; i < g .vexnum; i++) 
		visited[i]=FALSE;       /* 初始化访问标志数组 */ 
	n=0;                    /* 初始化路径上的顶点数 */     
	for ( i=0; i < g .vexnum; i++) 
		if (DepthFirstSearch (g, i)==1)  
			return;/* 一旦找到一条简单路径则返回 */ 
} 

例 3 求图的中心顶点 假设有一个公司在某个地区有 n 个产品销售点,现根据业务需要打算在其中某个销售点上建立一个中心仓库,负责向其它销售点提供产品。由于运输线路不同,运输费用也不同。假定每天需要向每个销售点运输一次产品,那么应将中心 仓库建在哪个销售点上,才能使运输费用达到最低。

问题分析】这是一个求图的中心顶点的问题:即在一个带权图 G 中,求出这 样一个顶点 v,使得 v 到其余顶点的最短路径长度之和最小。首先用弗罗伊德算 法求出各个顶点之间的最短路径长度,然后再求出每个顶点到其余各顶点的最短 路径长度之和,从中选取一个最短路径长度之和最小的顶点。

算法描述

#define  MAXLEN   3E38        /*定义最大浮点数*/ 
#define  MAX   20              /*定义最大顶点数目*/ 
int CenterVex (AdjMatrix  G) 
{   /*在带权图 G 中求一个中心顶点,返回该顶点编号*/   
	int  i, j, k;   
	float  min, len;   
	float  A[MAX][ MAX];     /* A[i][j]存放 i 和 j 之间的最短路径长度*/ 			
	for (i=0; i<G.vexnum; i++)
	{       /* 初始化 A[i][j] */       
		for (j=0; j<G.vexnum; j++)            
			A[i][j]=G.arcs[i][j].adj;       
		A[i][i]=0;                  /* i 到 i 的路径长度为 0 */ }    
		for (k=0; i<G.vexnum; k++)      /*求出每一对顶点之间的最短路径长度*/      
			for (i=0; i<G.vexnum; i++) 
				for (j=0; j<G.vexnum; j++)            
					if (A[i][k]+A[k][j]<A[i][j])                 
						A[i][j]=A[i][k]+A[k][j];   
		min=MAXLEN;  
		k=0;   
		for (i=0; i<G.vexnum; i++)
		{        /*选择最短路径长度之和最小的顶点 vK*/       
			len=0;       
			for(j=0; j<G.vexnum; j++)      /*求 vi 到其余顶点最短路径长度之和*/              
				len=len+A[i][j];       
			if(len<min)
			{           
				k=i;           
				min=len;       
			}   
		} 
	return(k); 
} 
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值