数据结构 实验四 图

数据结构 实验四  图

 

这次给出图论部分的数据结构相关代码,由于图结构不像树结构那样具有明显的层次性,较实验三的二叉树来说会复杂一些;在图的存储结构中,邻接矩阵的存储方式较为简单明了,但是在实际开发中往往由于其会导致占用大量的内存空间而被舍弃,但邻接表这样的链式结构就解决了这一的问题,所以对邻接表的掌握较为重要。

 

下面放出图的相关代码:

 

#include <stdio.h>
#include <stdlib.h>

/*包含数据结构的预定义常量和类型P10 */
#include "Datahead.h"

/* P161 图的数组(邻接矩阵)存储表示*/
#define INFINITY INT_MAX    /*无穷大 */
#define INT_MAX 999            /*最大整数 */
#define MAX_VERTEX_NUM 20    /*图的最大顶点数*/

typedef enum{DG,DN,UDG,UDN} GraphKind;        /*有向图,有向网,无向图,无向网*/

typedef int VRType;                            /*网络权值暂定为整数型*/
typedef char InfoType;                        /*备用*/
typedef char VertexType;                    /*顶点名称,字符型*/

typedef struct ArcCell{
  VRType adj;                /*顶点关系类型:无向图,用0或1表示是否相邻;对于带权图,则为权值类型*/
  InfoType *info;            /*该弧相关信息的指针*/
}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];


typedef struct{
  VertexType vexs[MAX_VERTEX_NUM];        /*顶点向量*/
  AdjMatrix arcs;                        /*邻接矩阵*/
  int vexnum,arcnum;                    /*图的当前顶点数和弧数*/
  GraphKind kind;                        /*图的种类标志*/
}MGraph;


/*P163 图的邻接表存储表示*/
typedef struct ArcNode{
  int adjvex;
  struct ArcNode *nextarc;
  InfoType       *info;
}ArcNode;

typedef struct VNode{
  VertexType data;
  ArcNode    *firstarc;
}VNode,AdjList[MAX_VERTEX_NUM];

typedef struct{
  AdjList vertices;
  int vexnum,arcnum;
  int kind;
}ALGraph;


/*算法7.4 7.5 深度遍历图*/
/* --- 算法7.4和7.5使用的全局变量 --- */
bool visited[MAX_VERTEX_NUM];        /*  访问标志数组 */
Status (* VisitFunc)(int v);        /*  函数变量 */

/*p61队列定义*/
typedef struct QNode{
    int data;                    /*图中结点用结点数组中的位置表示,为整数*/
    struct QNode *next;
}QNode, *QueuePtr;

typedef struct{
    QueuePtr front;
    QueuePtr rear;
}LinkQueue;


/*函数原型声明*/
Status CreateGraph(MGraph *G);
Status CreateDG(MGraph *G);
Status CreateDN(MGraph *G);
Status CreateUDG(MGraph *G);
Status CreateUDN(MGraph *G);
void OutputMG(MGraph G);
int LocateVex(MGraph G, VertexType v1);

Status CreateALGraph(MGraph *M, ALGraph *AL);
void OutputAL(ALGraph AL);
void DFSTraverse(ALGraph G, Status (*Visit)(int v));
void DFS(ALGraph G, int v);
int FirstAdjVex(ALGraph G, int v);
int NextAdjVex(ALGraph G, int v, int w);
Status PrintInt(int e);   /*Visit 函数*/

void BFSTraverse(ALGraph G, Status (*Visit)(int v )); /*   算法7.6 */
Status InitQueue(LinkQueue *Q);
Status EnQueue(LinkQueue *Q,int e);
Status DeQueue(LinkQueue *Q,int *e);
Status QueueEmpty(LinkQueue Q);


MGraph *p;
MGraph G;        /*全局变量  图G*/
ALGraph *A,AL;    /*邻接表变量*/

// 主函数
void main()
{
    p=&G;
    system("graftabl 936");/*调用MS_DOS中文支持*/
    printf("\n**********************图**********************\n\n");

    if ( CreateGraph(p) ) OutputMG(G);
    A=&AL;
    if ( CreateALGraph(p, A) ) OutputAL(AL);

    printf("\n深度遍历为:");
    DFSTraverse(AL, PrintInt);
    printf("\n广度遍历为:");
    BFSTraverse (AL, PrintInt );
    getchar();
}

Status CreateGraph(MGraph *G){  /*  算法7.1 */
    /*  采用数组(邻接矩阵)表示法,构造图G*/

    int k;   
    printf("请选择创建图的类型 \t1:有向图DG;\n\t\t\t2:有向网DN;\n\t\t\t3:无向图UDG;\n\t\t\t4:无向网UDN.\n");
    scanf("%d", &k);
    switch(k){
        case  1: return CreateDG(G);   /*  构造有向图G */
        case  2: return CreateDN(G);   /*  构造有向网G */
        case  3: return CreateUDG(G);  /*  构造无向图G */
        case  4: return CreateUDN(G);  /*  构造无向网G,算法7.2 */
        default   : return ERROR;
    }
} /*  CreateGraph */

Status CreateDG(MGraph *G) {/*   改造自算法 7.2 */
  /*  采用数组(邻接矩阵)表示法,构造有向图 */
  int i,j,k,w; 
  VertexType  v1,v2; 
  printf("请输入顶点个数G->vexnum :" );  scanf("%d",&G->vexnum);
  printf("请输入弧的条数G->arcnum :");   scanf("%d",&G->arcnum);
  getchar();  /*** 加上此句getchar()!!! ***/
  /*  scanf("%d,%d,%d",&G.vexnum, &G.arcnum, &IncInfo);       */
  for (i=0; i<G->vexnum; i++ ) {
    printf("请输入顶点G->vexs[%d]的名称(字符型):",i);
    scanf("%c",&G->vexs[i]);
    getchar();
  } /*  构造顶点向量 */
  for (i=0; i<G->vexnum; ++i )  /*  初始化邻接矩阵 ,全部赋值为0*/
    for (j=0; j<G->vexnum; ++j ) {
      G->arcs[i][j].adj = 0; /* {adj,info} */
      G->arcs[i][j].info= NULL;
    }
  for (k=0; k<G->arcnum; ++k ) {  /*  构造邻接矩阵
    printf("v1 (char) : ");  scanf("%c", &v1);getchar();
    printf("v2 (char) : ");  scanf("%c", &v2);getchar();
    printf("w (int) : " );   scanf("%d", &w); getchar();    */
    printf("请依次输入弧尾、弧头顶点名称(如,a b):" );
    scanf("%c %c", &v1,&v2);getchar();
                             /*  输入一条边依附的顶点及权值 */
    i = LocateVex(*G, v1);  j = LocateVex(*G, v2);
          /*  确定v1和v2在G中位置 */
    G->arcs[i][j].adj = 1;                /*  弧<v1,v2>的权值为1,表示两点相邻接 */
    /*  if (IncInfo) scanf(G.arcs[i][j].info); /*  输入弧含有相关信息 */ 

  }
  G->kind=DG;
  return OK;
} /*  CreateDG */

Status CreateDN(MGraph *G) {/*   改造自算法 7.2 */
  /*  采用数组(邻接矩阵)表示法,构造有向图 */
  int i,j,k,w; 
  VertexType  v1,v2; 
  printf("请输入顶点个数G->vexnum :" );  scanf("%d",&G->vexnum);
  printf("请输入弧的条数G->arcnum :");   scanf("%d",&G->arcnum);
  getchar();  /*** 加上此句getchar()!!! ***/
  /*  scanf("%d,%d,%d",&G.vexnum, &G.arcnum, &IncInfo);       */
  for (i=0; i<G->vexnum; i++ ) {
    printf("请输入顶点G->vexs[%d]的名称(字符型):",i);
    scanf("%c",&G->vexs[i]);
    getchar();
  } /*  构造顶点向量 */
  for (i=0; i<G->vexnum; ++i )  /*  初始化邻接矩阵 ,全部赋值为0*/
    for (j=0; j<G->vexnum; ++j ) {
      G->arcs[i][j].adj = 0; /* {adj,info} */
      G->arcs[i][j].info= NULL;
    }
  for (k=0; k<G->arcnum; ++k ) {  /*  构造邻接矩阵*/
        printf(" 请依次输入第%d条边依附的两个顶点,以及该边的权值:", k+1);
        scanf("%c %c %d", &v1, &v2, &w);
        getchar();
        i = LocateVex(*G, v1);    
        j = LocateVex(*G, v2);
        G->arcs[i][j].adj = w;
    /*  if (IncInfo) scanf(G.arcs[i][j].info); /*  输入弧含有相关信息 */ 
  }
  G->kind=DN;
  return OK;
} /*  CreateDN */

Status CreateUDG(MGraph *G) {/*   改造自算法 7.2 */
  /*  采用数组(邻接矩阵)表示法,构造无向图 */
  int i,j,k;
  VertexType  v1,v2; 
  printf("请输入顶点个数G->vexnum :" );  scanf("%d",&G->vexnum);
  printf("请输入弧的条数G->arcnum :");   scanf("%d",&G->arcnum);
  getchar();  /*** 加上此句getchar()!!! ***/
  /*  scanf("%d,%d,%d",&G.vexnum, &G.arcnum, &IncInfo);       */
  for (i=0; i<G->vexnum; i++ ) {
    printf("请输入顶点G->vexs[%d]的名称(字符型):",i);
    scanf("%c",&G->vexs[i]);
    getchar();
  } /*  构造顶点向量 */
  for (i=0; i<G->vexnum; ++i )  /*  初始化邻接矩阵 ,全部赋值为0*/
    for (j=0; j<G->vexnum; ++j ) {
      G->arcs[i][j].adj = 0; /* {adj,info} */
      G->arcs[i][j].info= NULL;
    }
  for (k=0; k<G->arcnum; ++k ) {  /*  构造邻接矩阵
    printf("v1 (char) : ");  scanf("%c", &v1);getchar();
    printf("v2 (char) : ");  scanf("%c", &v2);getchar();
    printf("w (int) : " );   scanf("%d", &w); getchar();    */
    printf("请依次输入弧尾、弧头顶点名称(如,a b):" );
    scanf("%c %c", &v1,&v2);getchar();
                             /*  输入一条边依附的顶点及权值 */
    i = LocateVex(*G, v1);  j = LocateVex(*G, v2);
          /*  确定v1和v2在G中位置 */
    G->arcs[i][j].adj = 1;                /*  弧<v1,v2>的权值为1,表示两点相邻接 */
    /*  if (IncInfo) scanf(G.arcs[i][j].info); /*  输入弧含有相关信息 */ 
    G->arcs[j][i].adj = G->arcs[i][j].adj; /*  置<v1,v2>的对称弧<v2,v1> */
  }
  G->kind=UDG;
  return OK;
} /*  CreateUDG */


Status CreateUDN(MGraph *G) {/*   算法 7.2 */
  /*  采用数组(邻接矩阵)表示法 */
    int i, j, k;
    VRType w;
    VertexType  v1, v2; 
    printf("请输入顶点个数G->vexnum :" );  scanf("%d", &G->vexnum);
    printf("请输入弧的条数G->arcnum :");   scanf("%d", &G->arcnum);
    getchar();
    // 构造顶点向量
    for( i = 0; i < G->vexnum; i++ )
    {
        printf("请输入顶点G->vexs[%d]的名称(字符型):", i);
        scanf("%c", &G->vexs[i]);
        getchar();
    }
    // 初始化邻接矩阵
    for( i = 0; i < G->vexnum; i++ )
    {
        for( j = 0; j < G->vexnum; j++ )
        {
            G->arcs[i][j].adj = 0;
            G->arcs[i][j].info = NULL;
        }
    }
    // 构造邻接矩阵
    for( k = 0; k < G->arcnum; ++k )
    {
        printf(" 请依次输入第%d条边依附的两个顶点,以及该边的权值:", k+1);
        scanf("%c %c %d", &v1, &v2, &w);
        getchar();
        i = LocateVex(*G, v1);    
        j = LocateVex(*G, v2);
        G->arcs[i][j].adj = w;
        G->arcs[j][i] = G->arcs[i][j];
    }
    G->kind = ::UDN;
    return OK;
}

int LocateVex(MGraph G,VertexType v1){
    int i;
    for (i = 0;i <= G.vexnum; i++) {
      if (v1 == G.vexs[i]) return i;
    }
    return 0;
}

/*建立无向图邻接矩阵*/

/*输出邻接矩阵*/
void OutputMG(MGraph G)
{
    int i,j;
    printf("\n邻接矩阵为:");
    for(i=0;i<G.vexnum;i++)
    {
        printf("\n");
        for(j=0;j<G.vexnum;j++) printf("%5d",G.arcs[i][j]);
    }
}

/*创建邻接表,数据来源于已知的邻接矩阵*/
Status CreateALGraph(MGraph *M, ALGraph *AL){
  int i,j;
  ArcNode *head,*p;
  AL->vexnum=M->vexnum;
  AL->arcnum=M->arcnum;
  AL->kind=M->kind;
  for (i=0;i<M->vexnum;i++) AL->vertices[i].data=M->vexs[i];
  head = (ArcNode *)malloc(sizeof(ArcNode)); /*单链表 头指针*/
  for (i=0;i<M->vexnum;i++)
    {head->nextarc=NULL;
     for (j=0;j<M->vexnum;j++)
      {
       if ((M->arcs[i][j].adj!=INFINITY) &&(M->arcs[i][j].adj!=0))
         {p = (ArcNode *)malloc(sizeof(ArcNode));
          p->info=M->arcs[i][j].info;
          p->nextarc=head->nextarc;
          p->adjvex=j;/*j顶点*/
          head->nextarc=p;   /*逆序插入各弧*/
         }
      }
    AL->vertices[i].firstarc = head->nextarc;
  }
  free(head);
  return OK;
}

void OutputAL(ALGraph AL){
  int i,j;
  ArcNode *p;
  printf("\n邻接表为:");
  for (i=0;i<AL.vexnum;i++)
  { printf("\n顶点%c->",AL.vertices[i].data);
    p=AL.vertices[i].firstarc;
    while(p)     /*输出单链表*/
     { printf("%5d",p->adjvex);
       p=p->nextarc;
     }
  }
}

void DFSTraverse(ALGraph G, Status (*Visit)(int v)) {  /*  算法7.4 */
 /*  对图G作深度优先遍历。     对尚未访问的顶点调用DFS */
    int v;
    VisitFunc = Visit;
    for( v = 0; v < G.vexnum; v++ )    visited[v] = FALSE;        // 初始化访问标记数组
    for( v = 0; v < G.vexnum; v++ )
    {
        if( !visited[v] )        
            DFS(G, v);            // 对尚未访问的顶点调用DFS
    }
}

void DFS(ALGraph G, int v) {  /*  算法7.5 */
   /*  从第v个顶点出发递归地深度优先遍历图G。*/
    visited[v] = TRUE;
    VisitFunc(v);
    int w;
    for( w = FirstAdjVex(G, v); w >= 0; w = NextAdjVex(G, v, w) )
    {
        if( !visited[w] )
            DFS(G, w);
    }
}

int FirstAdjVex(ALGraph G,int v){
    ArcNode *p;
    p = G.vertices[v].firstarc;
    if(p != NULL) return p->adjvex;
    else  return -1;/*p为空*/
}

int NextAdjVex(ALGraph G,int v,int w){
    ArcNode *p;
    p = G.vertices[v].firstarc;
    while(p){
      if ((p->adjvex == w)&&(p->nextarc != NULL)) return p->nextarc->adjvex;
      p = p->nextarc;
    }
    return -1;
}

// 此处改写了 Visit 函数,改为输出顶点名称,即data中的信息
Status PrintInt(int e){   /*Visit 函数*/
    //printf("  %d",e);           
    printf("  %c",AL.vertices[e].data);    //输出值,以强调visit函数
    return OK;
}


void BFSTraverse(ALGraph G, Status (*Visit)(int v )) {/*   算法7.6 */
  /*  按广度优先非递归遍历图G。使用辅助队列Q和访问标志数组visited。 */
    int v, u, w;
    LinkQueue Q, *pQ;
    pQ = &Q;
    for( v = 0; v < G.vexnum; v++ )    visited[v] = FALSE;        // 初始化访问标记数组
    InitQueue(&Q);                                            // 置空的辅助队列
    for( v = 0; v < G.vexnum; v++ )
    {
        if( !visited[v] )
        {
            visited[v] = TRUE;    Visit(v);
            EnQueue(&Q, v);
            while (!QueueEmpty(Q))
            {
                DeQueue(&Q, &u);
                for( w = FirstAdjVex(G, u); w >= 0; w = NextAdjVex(G, u, w) )
                    if( !visited[w] )
                    {
                        visited[w] = TRUE;
                        Visit(w);
                        EnQueue(&Q, w);
                    }
            }
        }
    }
} /*  BFSTraverse */

Status InitQueue(LinkQueue *Q){     /*生成头结点*/
    Q->front = Q->rear =(QueuePtr)malloc(sizeof(QNode));
    Q->front->next = NULL;
    return OK;
}

Status EnQueue(LinkQueue *Q, int e){
    QueuePtr p;
    p=(QueuePtr)malloc(sizeof(QNode));
    p->data=e;    p->next=NULL;
    Q->rear->next=p;
    Q->rear=p;
    return OK;
}

Status DeQueue(LinkQueue *Q,int *e){
    QueuePtr p;
    if (Q->front==Q->rear) return ERROR;
    p=Q->front->next;
    *e=p->data;
    Q->front->next=p->next;
    if (Q->rear==p) Q->rear=Q->front;
    free(p);
    return OK;
}

Status QueueEmpty(LinkQueue Q){
    if (Q.rear==Q.front) return TRUE;
    else return FALSE;
}

 

可以直接复制上述代码,也可也去我的网盘下载该cpp源文件(含”DataHead.h“头文件)

http://pan.baidu.com/s/1GJsZb

 

 

 

posted @ 2013-11-17 11:07  云端之上  阅读(875)  评论(0编辑  收藏  举报