四 图的基本操作

来源:互联网 发布:360抢购软件神器 编辑:程序博客网 时间:2024/06/05 16:49

 实验四

一、实验目的 

1、掌握图的存储思想及其存储实现。

2、掌握图的深度、广度优先遍历算法思想及其程序实现。

   3、掌握图的常见应用算法的思想及其程序实现。

二、实验仪器及环境:

    PC计算机;windows XP操作系统Visual C++6.0

三、实验内容及结果(按照具体实验题目,按照如下格式书写)

1、键盘输入数据,建立一个有向图的邻接表。

2、输出该邻接表。

3、在有向图的邻接表的基础上计算各顶点的度,并输出。

4、以有向图的邻接表为基础实现输出它的拓扑排序序列。

5、采用邻接表存储实现有向图的深度优先递归遍历。

   *6、采用邻接表存储实现有向图的广度优先遍历(利用队列实现)。

  7、编写一个主函数,调试上述算法。

  #include <iostream>#include <stdio.h>#include <stdlib.h>using namespace std;#define MAXVNUM  10  //顶点最大个数#define MAX 20typedef struct Node{   int   adjvex;struct Node *nextarc; int weight; //边的权}ArcNode; //表结点 #define VertexType int //顶点元素类型typedef struct{ int outdegree,indegree;//顶点的度,入度int vetex;VertexType data;ArcNode *firstarc;}VNode/*头结点*/; typedef struct{      VNode vertices[MAXVNUM];int vexnum,arcnum;//顶点的实际数,边的实际数 }ALGraph;  void CreatAdjList( ALGraph &G ) //建立有向图的邻接表存储结构 {  int n,m=0,i,j; cout<<"输入顶点个数"<<endl;   scanf("%d",&n);      //输入顶点个数   cout<<"输入顶点信息\n";   for ( i=1;i<=n;i++)     //输入顶点信息   { scanf("%d",&G.vertices[i].vetex);         G.vertices[i].firstarc=NULL;       }       cout<<"输入弧(0 0表示输入停止)\n";   scanf("%d%d",&i,&j);    //输入弧while(i!=0 && j!=0)      //两顶点之一为0表示结{       ArcNode *p=(ArcNode*)malloc(sizeof(ArcNode));  p->adjvex=j;       p->nextarc=G.vertices[i].firstarc;       G.vertices[i]. firstarc=p;       m++;  //弧的个数加1        cout<<"输入弧(0 0表示输入停止)\n";    scanf("%d%d",&i,&j);     }      G.vexnum=n; G.arcnum=m;    ArcNode *p=(ArcNode*)malloc(sizeof(ArcNode));    for(i=1;i<=G.vexnum;i++)  ///初始化入度出度    {        G.vertices[i].indegree=G.vertices[i].outdegree=0;    }    for(i=1;i<=G.vexnum;i++)  ///计算入度出度    {        p=G.vertices[i].firstarc;        while(p!=NULL)        {            G.vertices[p->adjvex].indegree++;            G.vertices[i].outdegree++;            p=p->nextarc;        }    }}int visited[MAXVNUM] ;// 访问标志数组 int GraphFirstAdj(ALGraph g,int v)//得到v的第一个邻结点{    if(g.vertices[v].firstarc!=NULL)    return g.vertices[v].firstarc->adjvex;    else return 0;}int GraphNextAdj(ALGraph g,int v,int w)//返回v的(相对于w的)下一个邻接点,若w是v的最后一个邻接点,则返回0{    ArcNode *p= (ArcNode*)malloc(sizeof(ArcNode));    p=g.vertices[v].firstarc;    while(p)    {        if(p->adjvex==w&&p->nextarc!=NULL)            return p->nextarc->adjvex;        p=p->nextarc;    }    return 0;}void DFS(ALGraph G, int v)  { // 从 顶点v出发递归地深度优先遍历图 G    cout<<G.vertices[v].vetex<<endl;visited[v]=1; // 访问v顶点(输出v)   for(int w=GraphFirstAdj(G, v); w ; w=GraphNextAdj(G,v,w))     if(!visited[w]) DFS(G, w);  } void DFSTraverse(ALGraph G)    //深度优先遍历图G  { int v;      for(v=1;v<G.vexnum;v++)  visited[v]=0;  // 初始访问数组置未访问标志    for(v=1;v<G.vexnum;v++)      if(!visited[v])DFS(G,v);  // 对未访问过的顶点调用 DFS  }typedef int ElemType;  typedef struct ///定义队列{    ElemType base[MAX];    int front,rear;///队头,队尾}SqQueue;  SqQueue SqQueueInit()///初始化队列{     SqQueue Q;    Q.front=Q.rear=0;    return Q;} int SqQueueEmpty(SqQueue Q)///判断队列是否为空{     if (Q.front==Q.rear)        return 1;    else  return 0;} SqQueue SqQueueIn(SqQueue Q,ElemType x)///入队{     if ((Q.rear+1)%MAX==Q.front)    {        printf("队满\n"); return Q;    }  ///队满,退出运行     Q.base[Q.rear]=x;    Q.rear=(Q.rear+1)%MAX;    return Q;} ElemType SqQueueGetTop(SqQueue Q)///若队非空返回对头元素的值{    return (Q.base[Q.front]);} SqQueue SqQueueOut(SqQueue Q,ElemType &x)///出队{    if(Q.front==Q.rear)    {        printf("队空\n"); return Q;    }  ///队已空,退出运行    x=Q.base[Q.front];    Q.front=(Q.front+1)%MAX;    return Q;} void BFSTraverse(ALGraph g)//图的bfs遍历{    for(int i=1;i<=g.vexnum;i++)visited[i]=0;// 初始访问数组    SqQueue q=SqQueueInit();    for(int i=1;i<=g.vexnum;i++)    {        if(!visited[i])        {            q=SqQueueIn(q,i);            visited[i]=1;            cout<<g.vertices[i].vetex<<endl;            while(!SqQueueEmpty(q))            {                int v = SqQueueGetTop(q);//对头元素出队列并置为v                q=SqQueueOut(q,v);                for(int w=GraphFirstAdj(g,v);w!=0;w=GraphNextAdj(g,v,w))//遍历v的邻结点                {                    if(!visited[w])                    {                        q=SqQueueIn(q,w);//v的尚未访问的邻接顶点w入队列Q                        visited[w]=1;                        cout<<g.vertices[w].vetex<<endl;                    }                }            }        }     }}void PrintA(ALGraph G) ///输出邻接表{    int i;    ArcNode *p;    printf("\n***输出邻接表:***\n");    for(i=1;i<=G.vexnum;i++)    {        p=G.vertices[i].firstarc;        printf("%d",G.vertices[i].vetex);        while(p!=NULL)        {            printf(" -> %d",p->adjvex);            p=p->nextarc;        }        printf("\n");    }    printf("\n");}void PrintDegree(ALGraph A) ///顶点的度{    int i;    for(i=1;i<=A.vexnum;i++)    {        printf("顶点 %2d 的入度是:  %2d  出度是:  %2d  \n",i,A.vertices[i].indegree,A.vertices[i].outdegree);    }    printf("\n");}void PrintTuopu(ALGraph A)    ///计算拓扑序列{    int t[MAXVNUM][2];    int flag=1,i,j;    ArcNode *p=NULL;    memset(t,0,sizeof(t));    if(p==NULL)printf("***输出拓扑序列***\n");    for(i=1;i<=A.vexnum;i++)    {        t[i][0]=A.vertices[i].indegree;        t[i][1]=A.vertices[i].outdegree;    }    for(i=1;i<=A.vexnum&&flag==1;i++)    {        flag==0;        for(j=1;j<=A.vexnum;j++)        {            if(t[j][0]==0)            {                t[j][0]=-1;                flag==1;                break;            }        }        if(flag==1)        {            p=A.vertices[j].firstarc;            printf("%d  ",A.vertices[j].vetex);            while(p!=NULL)            {                t[p->adjvex][0]--;                p=p->nextarc;            }        }        else        {            printf("此图有环\n");            return;        }    }    printf("\n");}int main(){    ALGraph G;    CreatAdjList(G);    PrintA(G);    PrintDegree(G);    cout<<"\n深度优先遍历\n";    DFSTraverse(G);    cout<<"\n广度优先遍历\n";    BFSTraverse(G);    printf("拓扑序\n");    PrintTuopu(G);    return 0;}


四、实验心得体会:(包括遇到的问题及解决办法)

    图的算法对于多对多的关系的存储和处理都很实用,在今后的学习生活中可能会经常遇到,所以要加强对于此部分的理解。