实习四 图及其应用 (题目: 图遍历的演示 )

一、需求分析

1.问题描述:

   很多涉及图上操作的算法都是以图的遍历操作为基础的。试写一个程序,演示连通的无向图上行遍全部结点的操作。

2.基本要求:

    以邻接多重表为存储结构,实现连通无向图的深度优先和广度优先遍历。以用户指定的结点为起点,分别输出每种遍历下的结点访问序列

和相应生成树的边集。

    3.测试数据:

#include<stdio.h>
#include<malloc.h>
#define MAX 30
typedef struct ENode
{
 int ivex, jvex;               /*该边依附的两个顶点在数组中的序号*/
 struct ENode *ilink;         /*指向下一条依附于顶点ivex的边*/
 struct ENode *jlink;       /*指向下一条依附于顶点jvex的边*/
}ENode;
typedef struct VNode
{
 int mark;
 char data;               //顶点信息
 int number;                 //顶点编号
 ENode *firstedge;
}VNode;
typedef struct
{
 VNode amlist[MAX];
 int numberOfVerts; 
 int numberOfEerts;
}Graph;                  //图的信息 
typedef struct QENode
{
  int data;
  struct QENode *next;
}QENode;                  //队列结点 
typedef struct
{
 QENode *rear;
 QENode *front; 
}LinkQueue;               //队列 
void InitQueue(LinkQueue *Q)  //队列的初始化 
{
 Q->front =Q->rear =(QENode *)malloc(sizeof(QENode));
 Q->front ->next =NULL;
}
void QueueAppend(LinkQueue *Q,int v)//入队列 
{
 QENode *p;
 p=(QENode *)malloc(sizeof(QENode));
 p->data =v;
 p->next =NULL;
 Q->rear  ->next =p;
 Q->rear =p;
}
void QueueDelete(LinkQueue *Q,int *v)//出队列 
{
 QENode *p;
 if(Q->front ==Q->rear )
  return;
 p=Q->front ->next ;
 *v=p->data ;
 Q->front ->next =p->next ;
 if(Q->rear ==p)
  Q->rear =Q->front ;
 free(p);
}
void Initilized(Graph *graph)//图的初始化
{
 graph=(Graph  *)malloc (sizeof(Graph));
 graph->numberOfVerts =0;
 graph->numberOfEerts =0;
}
void CreateGraph(Graph *graph)//图的创建图
{
 ENode *p,*q,*e;
 int i;
 printf("请输入连通无向图的顶点数和边数 例如 3 3:\n");
 scanf("%d %d",&graph->numberOfVerts,&graph->numberOfEerts);
 for(i=1;i<=graph->numberOfVerts;i++)
 {
  printf("请输入第%d个顶点的信息:\n",i);
  scanf("%s",&graph->amlist [i].data );
 
   graph->amlist [i].number  =i;
  graph->amlist[i].firstedge=NULL;
   graph->amlist [i].mark =0;
 }
 for(i=1;i<=graph->numberOfEerts;i++)
 {
  p=(ENode *)malloc(sizeof(ENode));
  printf("请输入每条边的信息(编号小的在前 例如1 3回车1 2回车2 3)\n");
  scanf("%d %d",&p->ivex,&p->jvex); 
  p->ilink =p->jlink =NULL;
  if(graph->amlist [p->ivex ].firstedge==NULL )
   graph->amlist [p->ivex ].firstedge =p;
  else
  {
   q=graph->amlist [p->ivex ].firstedge ;
   while(q!=NULL)
   {
    e=q;
    if(q->ivex ==p->ivex )
     q=q->ilink ;
    else
     q=q->jlink ;
   }
   if(e->ivex ==p->ivex )
    e->ilink =p;
   else
    e->jlink =p;
  }
  if(graph->amlist [p->jvex ].firstedge==NULL )
   graph->amlist [p->jvex ].firstedge =p;
  else
  {
   q=graph->amlist [p->jvex ].firstedge ;
   while(q!=NULL)
   {
    e=q;
    if(q->ivex ==p->ivex )
     q=q->ilink ;
    else
     q=q->jlink ;
   }
   if(e->ivex ==p->ivex )
    e->ilink =p;
   else
    e->jlink =p;
  }
 }
}
void SetMark(Graph *graph)//设置访问标记
{
 int i;
 for(i=1;i<=graph->numberOfVerts ;i++)
  graph->amlist [i].mark =0;
}
void DFS(Graph *graph,int v)//深度遍历
{
 ENode *p;
 printf("%d            ",v);
 graph->amlist [v].mark =1;
 p=graph->amlist [v].firstedge ;
 while(p!=NULL)
 {
  if(p->ivex ==v)
  {
   if(graph->amlist [p->jvex ].mark ==0)
   {
    printf("<%d,%d>\n",p->ivex ,p->jvex );
    DFS(graph,p->jvex );
   }
   p=p->ilink ;
  }
  else
  {
   if(graph->amlist [p->ivex].mark ==0)
   {
    printf("<%d,%d>\n",p->jvex ,p->ivex );
    DFS(graph,p->ivex );
   }
   p=p->jlink ;
  }
 }
}
void BFS(Graph *graph,int u)//广度遍历
{
 LinkQueue Q;
 ENode *p;
 InitQueue(&Q);
 printf("%d            ",u);
 graph->amlist [u].mark =1;
 QueueAppend(&Q,u);
 while(Q.front !=Q.rear )
 {
  QueueDelete(&Q,&u);
  p=graph->amlist [u].firstedge ;
  while(p!=NULL)
  {
   if(p->ivex ==u)
   {
    if(graph->amlist [p->jvex ].mark ==0)
    {
     QueueAppend(&Q,p->jvex );
     graph->amlist [p->jvex ].mark =1;
     printf("<%d,%d>\n",p->ivex ,p->jvex );
     printf("%d            ",p->jvex );
    }
    p=p->ilink ;
   }
   else
   {
     if(graph->amlist [p->ivex ].mark ==0)
     {
      QueueAppend(&Q,p->ivex );
      graph->amlist [p->ivex ].mark =1;
      printf("<%d,%d>\n",p->jvex ,p->ivex );
      printf("%d            ",p->ivex );
     }
     p=p->jlink ;
   }
  }
 } 
}
int main()
{
   int v1,v2;
   Graph graph;
   char order;
   Initilized(&graph);
   CreateGraph(&graph);
   printf("\n输入深度广度遍历的起始点:\n"); 
   scanf("%d",&v2); 
   v1=v2;
   printf("\n深度遍历序列及相应的生成树:\n顶点序列: 生成树边集:\n");
   SetMark(&graph);
   DFS(&graph,v2); 
   printf("\n广度遍历序列及相应生成树:\n顶点序列:生成树边集:\n");
   SetMark(&graph);
   BFS(&graph,v1);
   return 0;  
} 

                                                                   实习四 图及其应用     

题目: 图遍历的演示                             实习时间:2012/11/20

一、需求分析

1.问题描述:

   很多涉及图上操作的算法都是以图的遍历操作为基础的。试写一个程序,演示连通的无向图上行遍全部结点的操作。

2.基本要求:

    以邻接多重表为存储结构,实现连通无向图的深度优先和广度优先遍历。以用户指定的结点为起点,分别输出每种遍历下的结点访问序列

和相应生成树的边集。

    3.测试数据:

 

                        

二、设计

      1. 设计思想

        (1)存储结构

             邻接多重表为存储结构

        (2)主要算法基本思想

        所有代码思想均由老师授课所得:

         深度优先搜索(Depth-first Search,DFS)

        ① 首先访问起始顶点v,再访问图中与v相邻接的且未被

             访问过的任一顶点w1;

        ② 再从w1出发,访问与w1相邻接的且未被访问过的任一

             顶点w2;

        ③ 从w2出发,重复与步骤②类似的访问,直至遇到一个

             所有邻接点均被访问过的顶点为止;

        ④ 沿刚才访问的次序,反向回到一个尚有邻接点未被访

             问过的顶点,再从该顶点出发,重复与步骤③相类似

             的访问,直到所有的被访问过的顶点的邻接顶点均被

             访问过为止。

广度优先搜索(Breadth-first Search,BFS)

        ① 访问起始顶点v后,依次访问与v相邻接的所有顶点

              w1, w2, …, wt;

        ② 再按w1, w2, …, wt的顺序,访问其中每一个顶点的

             所有未被访问过的邻接顶点;对w1为:w11, w12, …,

              w1m;…;对wt为:wt1, wt2, …, wtn等;

        ③ 再按w11, w12, …, w1m, w21, …, wt1, wt2, …, wtn的顺序,

             去访问它们各自的未被访问过的邻接顶点。依次类

             推,直到图中所有被访问过的顶点的邻接顶点都被

             访问过为止。

    2. 设计表示

        (1)函数调用关系图

          main→Initilized→CreateGraph→SetMark→DFS→BFS

     (2)函数接口规格说明    

void Initilized(Graph *graph)       // graph指向的图的初始化

void CreateGraph(Graph *graph)    //graph指向的图的创建图

void SetMark(Graph *graph)       //设置graph指向的图的顶点访问标记

void DFS(Graph *graph,int v)       //深度遍历graph指向的图的点amlist [v]

void BFS(Graph *graph,int u)       //广度遍历graph指向的图的点amlist [v]

3. 实现注释    (即各项功能的实现程度)

程序缺乏健壮性。     

4. 详细设计(主要函数)  

【1】void Initilized(Graph *graph)//图的初始化

{

 graph=(Graph  *)malloc (sizeof(Graph));

 graph->numberOfVerts =0;

 graph->numberOfEerts =0;

}

【2】void CreateGraph(Graph *graph)//图的创建图

{

 ENode *p,*q,*e;

 int i;

 printf("请输入连通无向图的顶点数和边数 例如 3 3:\n");

 scanf("%d %d",&graph->numberOfVerts,&graph->numberOfEerts);

 for(i=1;i<=graph->numberOfVerts;i++)

 {

  printf("请输入第%d个顶点的信息:\n",i);

  scanf("%s",&graph->amlist [i].data );

 

   graph->amlist [i].number  =i;

  graph->amlist[i].firstedge=NULL;

   graph->amlist [i].mark =0;

 }

 for(i=1;i<=graph->numberOfEerts;i++)

 {

  p=(ENode *)malloc(sizeof(ENode));

  printf("请输入每条边的信息(编号小的在前 例如1 3回车1 2回车2 3)\n");

  scanf("%d %d",&p->ivex,&p->jvex);

  p->ilink =p->jlink =NULL;

  if(graph->amlist [p->ivex ].firstedge==NULL )

   graph->amlist [p->ivex ].firstedge =p;

  else

  {

   q=graph->amlist [p->ivex ].firstedge ;

   while(q!=NULL)

   {

    e=q;

    if(q->ivex ==p->ivex )

     q=q->ilink ;

    else

     q=q->jlink ;

   }

   if(e->ivex ==p->ivex )

    e->ilink =p;

   else

    e->jlink =p;

  }

  if(graph->amlist [p->jvex ].firstedge==NULL )

   graph->amlist [p->jvex ].firstedge =p;

  else

  {

   q=graph->amlist [p->jvex ].firstedge ;

   while(q!=NULL)

   {

    e=q;

    if(q->ivex ==p->ivex )

     q=q->ilink ;

    else

     q=q->jlink ;

   }

   if(e->ivex ==p->ivex )

    e->ilink =p;

   else

    e->jlink =p;

  }

 }

}

【3】void SetMark(Graph *graph)//设置访问标记

{

 int i;

 for(i=1;i<=graph->numberOfVerts ;i++)

  graph->amlist [i].mark =0;

}

【4】void DFS(Graph *graph,int v)//深度遍历

{

 ENode *p;

 printf("%d            ",v);

 graph->amlist [v].mark =1;

 p=graph->amlist [v].firstedge ;

 while(p!=NULL)

 {

  if(p->ivex ==v)

  {

   if(graph->amlist [p->jvex ].mark ==0)

   {

    printf("<%d,%d>\n",p->ivex ,p->jvex );

    DFS(graph,p->jvex );

   }

   p=p->ilink ;

  }

  else

  {

   if(graph->amlist [p->ivex].mark ==0)

   {

    printf("<%d,%d>\n",p->jvex ,p->ivex );

    DFS(graph,p->ivex );

   }

   p=p->jlink ;

  }

 }

}

【5】void BFS(Graph *graph,int u)//广度遍历

{

 LinkQueue Q;

 ENode *p;

 InitQueue(&Q);

 printf("%d            ",u);

 graph->amlist [u].mark =1;

 QueueAppend(&Q,u);

 while(Q.front !=Q.rear )

 {

  QueueDelete(&Q,&u);

  p=graph->amlist [u].firstedge ;

  while(p!=NULL)

  {

   if(p->ivex ==u)

   {

    if(graph->amlist [p->jvex ].mark ==0)

    {

     QueueAppend(&Q,p->jvex );

     graph->amlist [p->jvex ].mark =1;

     printf("<%d,%d>\n",p->ivex ,p->jvex );

     printf("%d            ",p->jvex );

    }

    p=p->ilink ;

   }

   else

   {

     if(graph->amlist [p->ivex ].mark ==0)

     {

      QueueAppend(&Q,p->ivex );

      graph->amlist [p->ivex ].mark =1;

      printf("<%d,%d>\n",p->jvex ,p->ivex );

      printf("%d            ",p->ivex );

     }

     p=p->jlink ;

   }

  }

 }

}

 

三、调试分析

      1.调试过程中遇到的主要问题是如何解决的;

调试过程中存在少许C语言的基础语法错误,经独立仔细观察和调试修改正确,最大的难题是将图中的各类算法实践要运用上几章节的内容,实现时需不断的温习以前的知识,出现多次错误。终于在自己独立多次多天修改下,终于完成。     

2.对设计和编码的回顾讨论和分析;

总的来说,这个程序写的相当困难,虽然老师已经把大体算法思路都提到过。但是,由于算法和语法的知识掌握的太不牢固,对好多以前学的数据结构还不是特别熟悉,需要不断尝试与温习。所以,今后应该多温习多练习才好。

3.时间和空间复杂度的分析;

【1】:广度遍历算法 时间O(n),空间O(1)

       【2】:深度遍历算法 时间O(n),  空间O(1)

      4.改进设想;

       程序能实现预期功能,只是其中的改进空间可能较大

【1】:图的构造函数

       【2】:广度遍历算法

5.经验和体会等。

多动手编程,才能熟练灵活的掌握C语言基础知识,才能更好的理解掌握数据结构的精髓。从而避免基础语法错误,让代码变得更简洁高效。如此才能准确高效的解决问题。在今后的编程过程中要更注重代码的熟练掌握,多的温习代码思想,多的动手编程。

 

四、用户手册(即使用说明)

   仅需按照提示的例子输入即可。若出错,则重新来过。

 

五、运行结果

运行环境:C-free

测试数据:

 

 

 

 

六、源程序清单

#include<stdio.h>

#include<malloc.h>

#define MAX 30

typedef struct ENode

{

 int ivex, jvex;               /*该边依附的两个顶点在数组中的序号*/

 struct ENode *ilink;         /*指向下一条依附于顶点ivex的边*/

 struct ENode *jlink;       /*指向下一条依附于顶点jvex的边*/

}ENode;

typedef struct VNode

{

 int mark;

 char data;               //顶点信息

 int number;                 //顶点编号

 ENode *firstedge;

}VNode;

typedef struct

{

 VNode amlist[MAX];

 int numberOfVerts;

 int numberOfEerts;

}Graph;                  //图的信息

typedef struct QENode

{

  int data;

  struct QENode *next;

}QENode;                  //队列结点

typedef struct

{

 QENode *rear;

 QENode *front;

}LinkQueue;               //队列

void InitQueue(LinkQueue *Q)  //队列的初始化

{

 Q->front =Q->rear =(QENode *)malloc(sizeof(QENode));

 Q->front ->next =NULL;

}

void QueueAppend(LinkQueue *Q,int v)//入队列

{

 QENode *p;

 p=(QENode *)malloc(sizeof(QENode));

 p->data =v;

 p->next =NULL;

 Q->rear  ->next =p;

 Q->rear =p;

}

void QueueDelete(LinkQueue *Q,int *v)//出队列

{

 QENode *p;

 if(Q->front ==Q->rear )

  return;

 p=Q->front ->next ;

 *v=p->data ;

 Q->front ->next =p->next ;

 if(Q->rear ==p)

  Q->rear =Q->front ;

 free(p);

}

void Initilized(Graph *graph)//图的初始化

{

 graph=(Graph  *)malloc (sizeof(Graph));

 graph->numberOfVerts =0;

 graph->numberOfEerts =0;

}

void CreateGraph(Graph *graph)//图的创建图

{

 ENode *p,*q,*e;

 int i;

 printf("请输入连通无向图的顶点数和边数 例如 3 3:\n");

 scanf("%d %d",&graph->numberOfVerts,&graph->numberOfEerts);

 for(i=1;i<=graph->numberOfVerts;i++)

 {

  printf("请输入第%d个顶点的信息:\n",i);

  scanf("%s",&graph->amlist [i].data );

 

   graph->amlist [i].number  =i;

  graph->amlist[i].firstedge=NULL;

   graph->amlist [i].mark =0;

 }

 for(i=1;i<=graph->numberOfEerts;i++)

 {

  p=(ENode *)malloc(sizeof(ENode));

  printf("请输入每条边的信息(编号小的在前 例如1 3回车1 2回车2 3)\n");

  scanf("%d %d",&p->ivex,&p->jvex);

  p->ilink =p->jlink =NULL;

  if(graph->amlist [p->ivex ].firstedge==NULL )

   graph->amlist [p->ivex ].firstedge =p;

  else

  {

   q=graph->amlist [p->ivex ].firstedge ;

   while(q!=NULL)

   {

    e=q;

    if(q->ivex ==p->ivex )

     q=q->ilink ;

    else

     q=q->jlink ;

   }

   if(e->ivex ==p->ivex )

    e->ilink =p;

   else

    e->jlink =p;

  }

  if(graph->amlist [p->jvex ].firstedge==NULL )

   graph->amlist [p->jvex ].firstedge =p;

  else

  {

   q=graph->amlist [p->jvex ].firstedge ;

   while(q!=NULL)

   {

    e=q;

    if(q->ivex ==p->ivex )

     q=q->ilink ;

    else

     q=q->jlink ;

   }

   if(e->ivex ==p->ivex )

    e->ilink =p;

   else

    e->jlink =p;

  }

 }

}

void SetMark(Graph *graph)//设置访问标记

{

 int i;

 for(i=1;i<=graph->numberOfVerts ;i++)

  graph->amlist [i].mark =0;

}

void DFS(Graph *graph,int v)//深度遍历

{

 ENode *p;

 printf("%d            ",v);

 graph->amlist [v].mark =1;

 p=graph->amlist [v].firstedge ;

 while(p!=NULL)

 {

  if(p->ivex ==v)

  {

   if(graph->amlist [p->jvex ].mark ==0)

   {

    printf("<%d,%d>\n",p->ivex ,p->jvex );

    DFS(graph,p->jvex );

   }

   p=p->ilink ;

  }

  else

  {

   if(graph->amlist [p->ivex].mark ==0)

   {

    printf("<%d,%d>\n",p->jvex ,p->ivex );

    DFS(graph,p->ivex );

   }

   p=p->jlink ;

  }

 }

}

void BFS(Graph *graph,int u)//广度遍历

{

 LinkQueue Q;

 ENode *p;

 InitQueue(&Q);

 printf("%d            ",u);

 graph->amlist [u].mark =1;

 QueueAppend(&Q,u);

 while(Q.front !=Q.rear )

 {

  QueueDelete(&Q,&u);

  p=graph->amlist [u].firstedge ;

  while(p!=NULL)

  {

   if(p->ivex ==u)

   {

    if(graph->amlist [p->jvex ].mark ==0)

    {

     QueueAppend(&Q,p->jvex );

     graph->amlist [p->jvex ].mark =1;

     printf("<%d,%d>\n",p->ivex ,p->jvex );

     printf("%d            ",p->jvex );

    }

    p=p->ilink ;

   }

   else

   {

     if(graph->amlist [p->ivex ].mark ==0)

     {

      QueueAppend(&Q,p->ivex );

      graph->amlist [p->ivex ].mark =1;

      printf("<%d,%d>\n",p->jvex ,p->ivex );

      printf("%d            ",p->ivex );

     }

     p=p->jlink ;

   }

  }

 }

}

int main()

{

   int v1,v2;

   Graph graph;

   char order;

   Initilized(&graph);

   CreateGraph(&graph);

   printf("\n输入深度广度遍历的起始点:\n");

   scanf("%d",&v2);

   v1=v2;

   printf("\n深度遍历序列及相应的生成树:\n顶点序列: 生成树边集:\n");

   SetMark(&graph);

   DFS(&graph,v2);

   printf("\n广度遍历序列及相应生成树:\n顶点序列:生成树边集:\n");

   SetMark(&graph);

   BFS(&graph,v1);

   return 0; 

}

转载于:https://www.cnblogs.com/XDJjy/archive/2013/04/07/3006000.html

  • 11
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值