第四章图的建立和应用

相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。


graph pointer;
pointer=head->next;
/*指针指向首结点
while (pointer!=NULL)

printf("[%d]",pointer->vertex);
pointer=pointer->next;

41
printf("\n");

void main()
{int i;
int
node[20][2]={{1,2},{2,1},{1,3},{3,1},{2,4},{4,2},{2,5} {5,2},{3
,6},{6,3},{3,7}, {7,3},{4,8},{8,4},{5,8},{8,5},{6,8},{ ,6},{7,8},{8,7}};
/*图 G3 的所有结点的邻接点的邻接表*/
Vertex1 Vertex2 Weight
Next
2. 定义一个一维数组 Tree,用于当前存贮生成树集合的顶点是否产生回路。且用 1 表示生成树的顶点,0 表示非生成树的顶点,若新加入的邻接边中两个顶点都在 生成树集合中,表示会产生回路,这样该边落在同一个连通分量上,应该舍去。
3. 在利用克鲁斯卡尔算法之前建立的链表来加入生成树的邻接边,直到产生 N-1 条 边。
{new->next=pointer->next;
pointer->next=new;
break;

pointer=pointer->next;

return head;

void free_edge(edge head)
while (pointer!=NULL)
{if (visited[pointer->vertex]==0)
dfs(pointer->vertex);
/*递归调用*/
pointer=pointer->next;
/*下一个邻接点*/


void create_graph(int vertex1,int vertex2)/*建立邻接顶点到邻接表内*/
第四章 图的建立和应用
【实验目的】
1.熟练掌握图的邻接矩阵和邻接表的存储方式;
2.实现图的一些基本运算,特别是深度遍历和广度遍历;
3.掌握以图为基础的一些常用算法,如最小生成树、拓扑排序、最短路径等。
【实验学时】:4 学时
第一节 图的遍历
【问题描述】从图中某一个顶点出发访问图中其余顶点,每个顶点被且仅被访问一 次的过程。称为图的遍历,又称为图的搜索。它是求解图的连通性问题、拓扑排序 和求关键路径等算法的基础。 【算法描述】 适合于无向/有向图的两种常用遍历图的方法是: 1. 深度优先搜索过程(DFS) (1) 基本思想:假设初始状态是图中所有顶点未曾被访问,则深度优先搜索可以
从图中某个顶点 v 出发,访问此顶点,然后依次从 v 的未被访问的邻接点出 发深度优先遍历图,直至图中所有和 v 有路径相通的顶点都被访问到,则另 选图中一个未曾被访问的顶点做始点,重复上述过程,直至图中所有顶点都 被访问到为止。 (2) 由于深度优先搜索时,可选择同一深度邻接点中任何一个继续进行邻接点深 度优先搜索,故其遍历序列不是唯一的。我们以邻接表作为图的存储结构。 2. 广度优先搜索(BFS) 基本思想:假设从图中某个顶点 v 出发,在访问了 v 之后依次访问 v 的未被访问的 邻接点,然后分别从这些邻接点出发一次访问它们的邻接点,并使“先访问的顶点 的邻接点”先于“后访问的顶点的邻接点”被访问,直至图中所有已被访问的顶点 的邻接点都被访问到。如果此时图中还有顶点未被访问到,则另选图中一个未曾被 访问的顶点做始点,重复上述过程,直至图中所有顶点都被访问到为止。我们以深 度优先搜索为例来写源程序。 【C 源程序】 #include <stdlib.h> #define vertexnum 9 /*定义顶点数*/
/*设为顶点数组之首结点*/
while (pointer->next!=NULL)
pointer=pointer->next;
/*下一个结点*/
pointer->next=new;
/*串在链尾*/


void print_graph(struct node *head)
/*输入出邻接表数据*/
printf("graph\n");
for (i=1;i<vertexnum;i++)
{printf("vertex[%d]: ",i);
print_graph(&head[I]);

printf("the depth of the graph is:\n");
printf(" [开始]==> ");

void priΒιβλιοθήκη Baidut_edge(edge head)
/*输出链表数据*/
44
{edge pointer;
pointer=head;
while( pointer!=NULL)
/*当结点为 NULL 时结束循环*/
{printf("[%d,%d] ",pointer->vertex1,pointer->vertex2);
{ graph pointer,new;
new=(graph)malloc(sizeof(struct node));/*配置内存*/
if (new!=NULL)/*成功*/

new->vertex=vertex2;
/*邻近接点*/
new->next=NULL;
pointer=&(head[vertex1]);
代价最小的边,直至T中所有顶点都在同一连通分量上为止。该算法的时间复杂
度为 O(eloge)。
以图 G3 进行描述:首先,将图形中的所有边按递增排列如下:
邻接 边
(4,5) (3,4) (1,4) (1,3) (1,2) (2,4) (2,5) (3,5) (1,5) (2,3)
权值








void kruskal(edge head)
{edge pointer;
int edgenum=0;
/*已连结边的数目*/
int weight=0;
pointer=head;
while(edgenum!=(vertexnum-1))/*当边的数目为顶点数少 1 时,结束循环*/
{if (visited[pointer->vertex1]==0||visited[pointer->vertex2]==0)
type Node *edge;
int
edges[10][3]={{1,2,7},{1,3,6},{1,4,5},{1,5,12},{2,3,14 ,{2,4,8},{2,5,8},
{3,4,3}{3,5,9},{4,5,2}}; /*针对图 G3 的结点数据以及权值*/
int visited[vertexnum];
printf("(%d) ",pointer->weight);/*输出权值*/
pointer=pointer->next;

printf("\n");

edge insert_edge(edge head,edge new)/*插入邻接边到链表内*/
{edge pointer;
pointer=head;
/*设为已访问*/
visited[pointer->vertex2]=1;

pointer=pointer->next;
/*下一个结点*/
if(pointer==NULL)
{printf("no tree\n");
break;


printf("\ntotal weight is %d",weight);/*输出加权值总和*/
决该问题有两个经典的算法:普里姆算法和克鲁斯卡尔算法。 【算法描述】 1. 普里姆(Prim)算法:它的思想是每次加入一个邻接边来建立最小生成树,直到
42
N-1 条边为止。设 G=(V,E)是连通网,TE 是 G 上最小生成树中边的集合,初 值为空,U 为顶点集合,初值 U=(U0)重复执行:在所有 u U,v V-U 的边(u, v) E 中找一条代价最小的边(U0, V0)并入 TE,同时,V0 并入 U。直到 U=V, 此时最小生成树=(V,TE)。该算法的时间复杂度为 O(n2)。
/*pointer 设为首结点
*/
while(1)

if (new->weight<head->weight)/*新的加权值比首结点值小*/
{new->next=head;
/*插入在首结点之前*/
head=new;
break;

if(new->weight>=pointer->weight&&new->weight<pointer->next->weight)
40
struct node
/*图顶点结构:用邻接表存储*/

int vertex;
/*邻接顶点数据*/
struct node *next;
/*下一个邻接顶点*/
};
typedef struct node *graph;
/*定义图结构*/
struct node head[vertexnum];
for (i=0;i<vertexnum;i++)
{ head[i].vertex=i;
head[i].next=NULL;

for (i=0;i<vertexnum;i++) /*配置所有结点均未访问*/
visited[i]=0;
for (i=0;i<20;i++)
create_graph(node[i][0],node[i][1]);/*建立邻接表*/
dfs(1);
/*首先从结点 1 开始*/
printf(" [结束] ");

【实验题】
1. 试设计一个广度优先搜索法来遍历一个图程序。
2. 将邻接表换成邻接矩阵来存储图,改写上面的深度优先搜索算法。
第二节 图的最小生成树实验
【问题描述】 最小生成树问题:在网上,选择一棵生成树,使树上各边的代价之和为最小。解
int visited[vertexnum];
/*用于标记结点是否已访问*/
void dfs(int vertex)
/*深度优先搜索法*/
{graph pointer;
visited[vertex]=1;
/*标记此结点已访问*/
printf("[%d]==>",vertex);
pointer=head[vertex].next;

4

5
1


5

7 1
6
28
4 14 5
32 8 12
5

9
图 5-1 G3 的最小生成树
图 5-2 图 G3
2. 克鲁斯卡尔(Kruskal):设G=(V,E)是连通网。令最小生成树T的初始状
态为:T=(V,φ)重复在E中选择代价最小的边,若该边依附的顶点落在T
中不同的连通分量上,则将此边加入到T的边集中,否则舍去此边而选择下一条
{printf("==>[%d,%d] ",pointer->vertex1,pointer->vertex2);
printf("(%d)",pointer->weight);
weight+=pointer->weight;
edgenum++;
visited[pointer->vertex1]=1;
43
【C 源程序】
#include<stdlib.h>
#define max 10
#define vertexnum 5
struct list
/*结构定义*/

int vertex1;
int vertex2;
int weight;
struct list *next;
};
typedef struct list Node; /*定义邻接边的结点*/
12
14
step 1:首先从上表中选择最小权值的边(4,5)加到生成树中。 Step2:依次取出第二条边(3,4)加到生成树中。 Step 3 将(1,4)边加入到生成树中。 Step 4 因加入(1,3)边,会产生回路,因此加入(1,2)边。有 5 个结点, 而有 4 条边,因此整个生成树建立过程结束。 这两种算法的角度不同,适合于针对不同的图,对稀疏图来说,顶点多而边少, 采用克鲁斯卡尔算法较好;而对稠密图来说,顶点少而边多,最好用普里姆算法。 我们以克鲁斯卡尔算法为例讨论最小生成树的算法。 【数据描述】 1. 先将所有邻接边依加权值递增用链表链接起来。节点结构:
相关文档
最新文档