大话数据结构-7.图(中)

7.3.4 邻接多重表

对于无向图,邻接表关注的重点是顶点,如果用来操作边,比较麻烦,例如删除某条边需要删除两个边表结点,如图:
在这里插入图片描述

因此仿照十字链表,改造边表结构定义了邻接多重表,结构如下:
在这里插入图片描述

ivex和jvex是与某条边依附的两个顶点在定点表中的下标。
ilink指向依附顶点ivex的下一条边。
jlink指向依附顶点jvex的下一条边。

  • 构造过程
    在这里插入图片描述

①先画顶点和边;
在这里插入图片描述

②用顶点的firstedge指向第一条边;
③用ilink或jlink指向下一条边;

  • 与邻接表的差别:
    同一条边邻接表用两个结点表示,而邻接多重表只用一个节点。

7.3.5 边集数组

  • 边集数组由两个一维数组构成。一个存储顶点信息,另一个存储边的信息,这个边数组每个数据元素由一条边的起点下标(begin)、终点下标(end)和权(weight)组成。
    在这里插入图片描述

在这里插入图片描述

  • 边集数组关注的是边的集合。在边集数组中查找顶点的度需要扫描整个边集数组,效率不高。
  • 具体内容见7.5.2克鲁斯卡尔(Kruskal)算法。

7.4 图的遍历

7.4.1 深度优先遍历(递归)

适合目标比较明确,已找到目标位主要目的

在这里插入图片描述

  • 邻接矩阵,深度优先遍历代码如下:
    在这里插入图片描述
 typedef int Boolean; /*Boolean是布尔类型,其值是TRUE或FALSE*/
 Boolean visitied[MAX]; /*访问标志的数组*/
 /*邻接矩阵的深度优先递归算法*/
 void DFS(MGraph G,int i)
 {
	 int j;
	 visited[i]= TRUE;
	 printf("%c",G.vexs[i]); /*打印顶点,也可以其他操作*/
	                         /*从图结构G的顶点数组(vexs)中取出第i个元素并打印出来*/for(j=0;j<G.numVertexes;j++)  /*j从0到图中的顶点数(numVertexes)加1*/if (G.arc[i][j]== 1 && !visited[j]) /*在邻接矩阵arc中值为1表示有边,值为0表示无边*/DFS(G,j); /*对未访问的邻接顶点递归调用,注意这里使用的是*/
			           /*下一个未访问的邻接顶点j而不是i。*/
 }
 /*邻接矩阵的深度遍历操作*/
 void DFSTracerse(MGraph G)
 {
	 int i;
	 for (i= 0;i<G.numVertexes;i++)
		 visited[i]=FALSE; /*初始所有顶点状态都是未访问过状态*/
	 for(i = 0;i<G.numVertexes;i++)
		 if (!visited[i]) /*对未访问过的顶点调用DFS,若是连通图,只会执行一次*/
			 DFS(G,i);
 }
  • 邻接表结构,深度优先遍历代码如下:
    在这里插入图片描述
typedef int Boolean; /*Boolean是布尔类型,其值是TRUE或FALSE*/
 Boolean visitied[MAX]; /*访问标志的数组*/
/*邻接表的深度优先递归算法*/
void Dfs(GraphAdjList GL,int i)
{
	EdgeNode *p;  /*定义了一个EdgeNode类型的指针p*/
	visited[i]=TRUE;
	printf("%c",GL->adjlist[i].data);/*打印顶点,也可以其他操作*/
						/*GL->adjlist[i].data指的是在邻接表中的第i个顶点的数据*/
	p=GL->adjList[i].firstedge;
				       /*将指针p设置为指向邻接表GL中第i个顶点的第一个边*/
	while(p)
	{if (!visited[p->adjvex]) /*adjvex为邻接点域,存储顶点对应的下标*/DFS(GL,p->adjvex);/*对未访问的邻接顶点递归调用*/
核		p=p->next;
	}
}
/*邻接表的深度遍历操作*/
void DFSTraverse(GraphAdjList GL)
{
	int i;
	for(i=0;i<GL->numVertexes;i++)
		visited[i]=FALSE;/*初始所有顶点状态都是未访问过状态*/
	for(i=0;i<GL->numVertexes;i++)
		if (!visited[i])/*对未访问过的顶点调用DFS,若是连通图,只会执行一次*/
			DFS(GL,i);
}
  • 邻接矩阵 O [ n 2 ] O[n^2] O[n2],邻接表 O [ n ] O[n] O[n]
  • GraphAdjList是"Graph Adjacency List"的缩写。

7.4.2 广度优先遍历(队列)

核心是层序遍历,更适合在不断扩大遍历范围时找到相对最优解的情况。
在这里插入图片描述

在这里插入图片描述

  • 邻接矩阵结构,广度优先遍历代码如下:

    /*邻接矩阵的广度遍历算法*/
    void BFSTraverse(MGraph G)
    {
    	int i,j;
    	Queue Q;
    	for (i=0;i<G.numVertexes;i++)
    		visited[i]=FALSE;
    	InitQueue(&Q); /*初始化一辅助用的队列*/
    	for(i=0;i<G.numVertexes;i++) /*对每一个顶点做循环*/
    	{
    		if(!visited[i]) /*若是未访问过就处理*/
    		{
    			visited[i]=TRUE; /*设置当前顶点访问过*/
    			printf("%c",G.vexs[i]); /*打印顶点,也可以其他操作*/
    			EnQueue(&Q,i); /*将此顶点入队列*/
    			while(!QueueEmpty(Q)) /*若当前队列不为空*/
    			{
    				DeQueue(&Q,&i); /*将队中元素出队列,赋值给i*/
    				for(j=0;j<G.numVertexes;j++)
    				{
    					/*判断其他顶点若与当前顶点存在边且未访问过*/
    					if(G.arc[i][j]==1&&!visited[j])
    					{
    						visited[j]=TRUE; /*将找到的此顶点标记为已访问*/
    						printf("%c",G.vexs[j]); /*打印顶点*/
    						EnQueue(&Q,j); /*将找到的此顶点入队列*/
    					}
    				}
    			}
    		}
    	}
    }
    
    上述代码逻辑如下:
    1.定义一个名为BFSTraverse的函数,它接受一个名为G的图作为参数。这个图应该包含顶点数numVertexes、顶点数组vexs和邻接矩阵arc。
    2.初始化一个队列Q和一个访问状态数组visited,所有元素初始化为FALSE。
    3.通过循环,遍历图中的每一个顶点。
    4.对于每个未被访问过的顶点,做以下操作:
        标记该顶点为已访问。
        打印该顶点的名称或数据。
        将该顶点加入队列Q。
    5.当队列不为空时,进行以下循环:
        从队列中删除并返回队首元素,并将删除的元素的索引赋值给i。
        遍历所有顶点,对于每个与当前顶点i存在边且未被访问过的顶点j,做以下操作:
    	    标记顶点j为已访问。
    	    打印顶点j的名称或数据。
    	    将顶点j加入队列Q。
    6.重复步骤5,直到队列为空。
    7.结束函数定义。
    总的来说,这个函数实现了基于邻接矩阵的图的广度优先搜索算法。首先,它初始化所有顶点为未访问状态,然后对于每个未访问的顶点,将其标记为已访问并打印其名称或数据,并将其加入队列中。然后,依次处理队列中的顶点,对于每个顶点,将其未访问的相邻顶点标记为已访问并打印其名称或数据,并将其加入队列中。重复此过程,直到队列为空。
    
  • 邻接表结构,广度优先遍历代码如下:
    在这里插入图片描述

/*邻接表的广度遍历算法*/
void BFSTraverse (GraphAdjList GL)
{
	int i;
	EdgeNode *p;
	Queue Q;
	for(i=0;i<GL->numvertexes;i++)
		visited[i]= FALSE;
	InitQueue(&Q);
	for(i=0;i<GL->numvertexes;i++)
	{
		if(!visited[i])
		{
			visited[i]=TRUE;
			printf("%c",GL->adjList[i].data); /*打印顶点,也可以其他操作*/
			EnQueue(&Q,i);
			while(!QueueEmpy(Q))
			{
				DeQueueEmpty(&Q,&i);
				p=GL->adjList[i].firstedge; /*找到当前顶点边表链表表头指针*/
				while(p)
				{
					if(!visited[p->adjvex]) /*若此顶点未被访问*/
					{
						visited[p->adjvex]=TRUE;
						printf("%c",GL->adjList[p->adjvex].data);
						EnQueue(&Q,p->adjvex); /*将此顶点入队列*/
					}
					p=p->next; /*指针指向下一个邻接点*/
				}
			}
		}
	}
}

  • 20
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值