您的位置:首页 > 其它

图的邻接表表示及深度优先搜索和广度优先搜索 prim求最小生成树

2016-12-15 17:11 351 查看
       邻接表表示图的基本思想是只存储相关信息,适合存储稀疏图,由表头结点表和边表两部分组成。对图中的每个顶点建立一个带头结点的边链表,每个边链表的头结点又构成一个表头结点表,具体结构如下





以下为存储结构

typedef char ElemType;
//边表结点
typedef struct ArcNode{
int adjvex;  //该弧指向定点的位置
struct ArcNode *nextarc; //指向下一弧的指针
int info;//权值
}ArcNode;
//表头结点
typedef struct VertexNode{
ElemType data;//顶点数据
ArcNode *firstarc;//指向该顶点第一条弧的指针
}VertexNode;
//表头结点表
typedef struct{
VertexNode vertex
;
int vexnum,arcnum;//图的顶点数和弧数
int kind;//图的种类标志 0表示无向图
}AdjList;


深度优先搜索是指按照深度方向搜索,基本思想是

1、从图中某个顶点v0出发,首先访问v0

2、找出刚访问过的顶点v0的第一个未被访问的邻接点,然后访问该顶点,以该顶点为新的顶点,重复此步骤,直到刚访问过的顶点没有未被访问的邻接点为止。

3、返回前一个访问过的且仍有未被访问的邻接点的顶点,找出该顶点的下一个未被访问的邻接点,访问该顶点;然后执行步骤2

相关函数如下

//深度优先搜索
void DepthFirstSearch(AdjList *L,int V[],int n){
printf("V%d ",n);
V
=1;
ArcNode *p=L->vertex
.firstarc;
while(p!=NULL){
if(V[p->adjvex]==0){
DepthFirstSearch(L,V,p->adjvex);
}
p=p->nextarc;
}
}

广度优先搜索是指按照广度方向搜索,基本思想是

1、从图中某个顶点v0出发,首先访问v0;

2、依次访问v0到各个未被访问的邻接点;

3、分别从这些邻接点出发,依次访问它们的各个未被访问的邻接点

相关函数如下,

//定义队列
typedef struct{
int Q[M];
int front;
int rear;
}Queue;
//初始化队列
void InitQueue(Queue *Q){
Q->front=Q->rear=0;
}
//入队
void EnterQueue(Queue *Q,int n){
if((Q->rear+1)%M==Q->front){
printf("入队出错\n");
}else{
Q->Q[Q->rear]=n;
Q->rear=(Q->rear+1)%M;
}
}
//判断队列是否为空
int EmptyQueue(Queue *Q){
if(Q==NULL||Q->front==Q->rear){
return 0;
}
return 1;
}
//出队
int DeleteQueue(Queue *Q){
int g;
if(Q->rear==Q->front){
printf("队列为空");
return 0;
}
g=Q->Q[Q->front];
Q->front=(Q->front+1)%M;
return g;
}
//广度优先搜索
void BreadthFirstSearch(AdjList *L,int V[],int n){
int k;
ArcNode *p;
printf("V%d ",n);
V
=1;
Queue *Q=(Queue *)malloc(sizeof(Queue));
InitQueue(Q);
EnterQueue(Q,n);
while(EmptyQueue(Q)==1){
n=DeleteQueue(Q);
if(n==0){
return 0;
}
p=L->vertex
.firstarc;
k=p->adjvex;
while(k>0){
if(V[k]==0){
printf("V%d ",k);
V[k]=1;
EnterQueue(Q,k);
}
p=p->nextarc;
if(p!=NULL){
k=p->adjvex;
}else{
k=0;
}
}
}
}

在一个连通网中,各边的代价之和最小的生成树称为最小生成树,prim算法便是求最小生成树的算法之一。基本思想是
1、将顶点分为两个集合U,V;U为已加入最小生成树的顶点集合,初始为v0,V为除U外的顶点集合,表示尚未加入最小生成树的顶点集合

2、在所有的U和V的集合中各选一点(u,v),并且两点之间的边代价最小,则将v并入U;

3、重复步骤2,直到U=V为止

相关函数如下

//普里姆算法求最小生成树
int MiniTree_prim(AdjList *L,int V[],int n){
int k,B
,l=-1,i;
Side e;
ArcNode *p;
V
=1;
l++;B[l]=n;//
while(l<M-1){
e.f=100;
e.j=0;
e.i=0;
for(i=0;i<=l;i++){
n=B[i];
if(n==0){
return 0;
}
p=L->vertex
.firstarc;
k=p->adjvex;
while(k>0){
if(V[k]==0){
if(p->info<e.f){
e.f=p->info;
e.i=n;
e.j=k;
}
}

p=p->nextarc;
if(p!=NULL){
k=p->adjvex;
}else{
k=0;
}
}
}
if(e.j>0){
V[e.j]=1;
printf("%d %d %d\n",e.i,e.j,e.f);
l++;
B[l]=e.j;
}else{
return 0;
}
}
}

下面为测试用例图及代码



/*图的邻接表表示法和遍历算法的实现 */
#include<stdio.h>
#define N 20 //最多顶点的个数
#define M 7 //

typedef char ElemType; //边表结点 typedef struct ArcNode{ int adjvex; //该弧指向定点的位置 struct ArcNode *nextarc; //指向下一弧的指针 int info;//权值 }ArcNode; //表头结点 typedef struct VertexNode{ ElemType data;//顶点数据 ArcNode *firstarc;//指向该顶点第一条弧的指针 }VertexNode; //表头结点表 typedef struct{ VertexNode vertex ; int vexnum,arcnum;//图的顶点数和弧数 int kind;//图的种类标志 0表示无向图 }AdjList;
//存储边信息
typedef struct{
int i;
int j;
int f;
}Side;
//定义队列
typedef struct{
int Q[M];
int front;
int rear;
}Queue;
//初始化队列
void InitQueue(Queue *Q){
Q->front=Q->rear=0;
}
//入队
void EnterQueue(Queue *Q,int n){
if((Q->rear+1)%M==Q->front){
printf("入队出错\n");
}else{
Q->Q[Q->rear]=n;
Q->rear=(Q->rear+1)%M;
}
}
//判断队列是否为空
int EmptyQueue(Queue *Q){
if(Q==NULL||Q->front==Q->rear){
return 0;
}
return 1;
}
//出队
int DeleteQueue(Queue *Q){
int g;
if(Q->rear==Q->front){
printf("队列为空");
return 0;
}
g=Q->Q[Q->front];
Q->front=(Q->front+1)%M;
return g;
}

//图的存储
void CreateALGrapah(AdjList *L,int A[],Side S[],int m){
int i=0,k,j=0,f=0;
ArcNode *s=NULL;
do{
L->vertex[i].data=A[i];
L->vertex[i].firstarc=NULL;
// printf("%d",A[i]);
i++;
}while(A[i]!=-1);
L->arcnum=m;
L->vexnum=i-1;
L->kind=0;
for(k=0;k<m;k++){
//头插法建边表
i=S[k].i;
j=S[k].j;
f=S[k].f;
//printf("\n%d-%d",i,j);
s=(ArcNode *)malloc(sizeof(ArcNode));
s->adjvex=j;
s->info=f;
s->nextarc=L->vertex[i].firstarc;
L->vertex[i].firstarc=s;
s=(ArcNode *)malloc(sizeof(ArcNode));
s->adjvex=i;
s->nextarc=L->vertex[j].firstarc;
s->info=f;
L->vertex[j].firstarc=s;
}
}
//输出邻接表存储
void PrintALGraph(AdjList *L){
ArcNode *p=NULL;
int i,k=0;
for(i=1;i<=L->vexnum;i++){
k=L->vertex[i].data;
printf("V%d",k);
p=L->vertex[k].firstarc;
while(p!=NULL){
printf(" ->%d",p->adjvex);
p=p->nextarc;
}
printf("\n");
}
}
//深度优先搜索 void DepthFirstSearch(AdjList *L,int V[],int n){ printf("V%d ",n); V =1; ArcNode *p=L->vertex .firstarc; while(p!=NULL){ if(V[p->adjvex]==0){ DepthFirstSearch(L,V,p->adjvex); } p=p->nextarc; } }
//广度优先搜索
void BreadthFirstSearch(AdjList *L,int V[],int n){
int k;
ArcNode *p;
printf("V%d ",n);
V
=1;
Queue *Q=(Queue *)malloc(sizeof(Queue));
InitQueue(Q);
EnterQueue(Q,n);
while(EmptyQueue(Q)==1){
n=DeleteQueue(Q);
if(n==0){
return 0;
}
p=L->vertex
.firstarc;
k=p->adjvex;
while(k>0){
if(V[k]==0){
printf("V%d ",k);
V[k]=1;
EnterQueue(Q,k);
}
p=p->nextarc;
if(p!=NULL){
k=p->adjvex;
}else{
k=0;
}
}
}
}
//普里姆算法求最小生成树
int MiniTree_prim(AdjList *L,int V[],int n){
int k,B
,l=-1,i;
Side e;
ArcNode *p;
V
=1;
l++;B[l]=n;//
while(l<M-1){
e.f=100;
e.j=0;
e.i=0;
for(i=0;i<=l;i++){
n=B[i];
if(n==0){
return 0;
}
p=L->vertex
.firstarc;
k=p->adjvex;
while(k>0){
if(V[k]==0){
if(p->info<e.f){
e.f=p->info;
e.i=n;
e.j=k;
}
}

p=p->nextarc;
if(p!=NULL){
k=p->adjvex;
}else{
k=0;
}
}
}
if(e.j>0){
V[e.j]=1;
printf("%d %d %d\n",e.i,e.j,e.f);
l++;
B[l]=e.j;
}else{
return 0;
}
}
}
int main(){
AdjList *L=(AdjList *)malloc(sizeof(AdjList));
int i=0,V[M];
//测试数据
Side S[9];
S[0].i=1;S[0].j=2;S[0].f=6;
S[1].i=1;S[1].j=3;S[1].f=1;
S[2].i=1;S[2].j=4;S[2].f=5;
S[3].i=2;S[3].j=3;S[3].f=5;
S[4].i=2;S[4].j=5;S[4].f=3;
S[5].i=3;S[5].j=4;S[5].f=5;
S[6].i=3;S[6].j=5;S[6].f=6;
S[7].i=3;S[7].j=6;S[7].f=4;
S[8].i=4;S[8].j=6;S[8].f=2;
S[9].i=5;S[9].j=6;S[9].f=6;
int A[8]={0,1,2,3,4,5,6,-1};//图的顶点信息 0为开始位 -1为结束
// printf("s1.j=%d\n",S[1].j);
CreateALGrapah(L,A,S,10);
PrintALGraph(L);
//深度优先搜索 V[]为访问记录是否被访问(0为访问)
printf("深度优先搜索\n");
for(i=1;i<M;i++){
V[i]=0;
}
DepthFirstSearch(L,V,1);
printf("\n广度优先搜索\n");
for(i=1;i<M;i++){
V[i]=0;
}
BreadthFirstSearch(L,V,1);
//
printf("\n普里姆算法求最小生成树\n");
for(i=1;i<M;i++){
V[i]=0;
}
MiniTree_prim(L,V,1);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: