zoukankan      html  css  js  c++  java
  • 数据结构与算法--图型结构的建立与搜索

    **课程名称:数据结构与算法
    课程类型:必修
    实验项目:图型结构的建立与搜索
    实验题目:图的存储结构的建立与搜索
    实验日期:2017/12/3**


    一、实验目的

    图的搜索(遍历)算法是图型结构相关算法的基础,本实验要求编写程序演示无向图三种典型存储结构的建立和搜索(遍历)过程。让我们在这个过程中熟悉这些操作之间的关系和内在联系。

    二、实验要求及实验环境

    1.分别实现无向图的邻接矩阵、邻接表和邻接多重表存储结构的建立算法,分析和比较各建立算法的时间复杂度以及存储结构的空间占用情况;
    2.实现无向图的邻接矩阵、邻接表和邻接多重表三种存储结构的相互转换的算法;
    3.在上述三种存储结构上,分别实现无向图的深度优先搜索(递归和非递归)和广度优先搜索算法。并以适当的方式存储和显示相应的搜索结果(深度优先或广度优先生成森林(或生成树)、深度优先或广度优先序列和编号);
    4.分析搜索算法的时间复杂度;
    5.以文件形式输入图的顶点和边,并显示相应的结果。要求顶点不少于 10 个,边不少于 13 个;
    6.软件功能结构安排合理,界面友好,便于使用。

    实验环境:

    Win10/code blocks

    三、设计思想

    (本程序中的用到的所有数据类型的定义,主程序的流程图及各程序模块之间的调用关系)

    1.逻辑设计

    define NumVertices 25//顶点数目最大值
    //using namespace std;
    /*
    无向图的邻接矩阵
    */
    typedef char VertexData[5];//保存顶点名称数组
    typedef int EdgeData;//保存该点的值
    typedef struct
    {
    VertexData vertex[NumVertices];//顶点表,里面是所有顶点名称
    EdgeData edge[NumVertices][NumVertices]; //邻接矩阵—边表, 可视为顶点之间的关系
    int n, e; //图的顶点数与边数
    } MTGraphSquare;

    /*
    无向图的邻接表
    */
    typedef struct node //边表结点
    {
    int adjvex; //邻接点域(下标)
    EdgeData cost; //边上的权值
    struct node *next; //下一边链接指针
    } EdgeNode;
    typedef struct //顶点表结点
    {
    VertexData vertex; //顶点数据域
    EdgeNode *firstedge;//边链表头指针
    } VertexNode;
    typedef struct //图的邻接表
    {
    VertexNode vexlist[NumVertices];// 顶点表,里面是所有顶点名称
    int n, e; //顶点个数与边数
    } AdjGraph;
    typedef bool VisitIf;//是否访问过
    typedef struct InfoType//信息域
    {
    VertexData vertex1;
    VertexData vertex;
    int weight;
    } InfoType;
    typedef struct EBox//节点box
    {
    VisitIf mark; //边访问标记
    int ivex, jvex; //该边依附的两个顶点的位置
    struct EBox * ilink, * jlink; //分别指向依附这两个顶点的下一条边
    InfoType info; //该边信息指针
    } EBox;
    typedef struct VexBox//顶点box
    {
    VertexData data;
    EBox * firstedge; //指向第一条依附于该顶点的边
    } VexBox;
    typedef struct
    {
    VexBox adjmulist[MAX_VERTEX_NUM];
    int vexnum,edgenum; //无向图的当前顶点数和边数
    } AMLGraph;
    bool visited[50]= {false}; //是否进行过访问

    下面是相应的图示。

    2.物理设计

    int AMLGraphDFSTraverseFeidiguiBUG2(AMLGraph *G,VertexData start)//从start顶点起,深度优先遍历图G(非递归算法)
    int AMLGraphDFSTraverseFeidiguiBUG3(AMLGraph *G,VertexData start)//从start顶点起,深度优先遍历图G(非递归算法)
    Status AMLGraphDFSTraverseFeidigui(AMLGraph *G,VertexData start)//从start顶点起,深度优先遍历图G(非递归算法)
    void AMLGraphBFSTraverse(AMLGraph *G)
    int NextAdjVex(AMLGraph *G,VertexData v,VertexData w)//返回v的(相对于w的)下一个邻接顶点
    int FirstAdjVex(AMLGraph *G,VertexData v)//寻找v的第一个邻接顶点
    void AMLGraphDFSTraverse(AMLGraph *G)
    void AMLGraphDFS(AMLGraph *G,int v)
    //深度优先(非递归)
    //LGraph: 邻接表
    //InitVertex: 遍历起始顶点
    void AdjGraphDFS2(AdjGraph *LGraph, int InitVertex)
    void AdjGraphBFS(AdjGraph *G,int s)
    //广度优先遍历 (递归)
    //缺点递归最大为G.numv次
    //深度优先遍历主程序
    void AdjGraphDFSTraverse(AdjGraph *G)
    void AdjGraphDFS1(AdjGraph *G,int i)
    void MTGraphSquareDFSTraverse2(MTGraphSquare *G)
    void MTGraphSquareDFS2(MTGraphSquare *G, int i)
    void MTGraphSquareBFSTraverse(MTGraphSquare *G, char vName[5])
    int MTGraphSquareLocateVex(MTGraphSquare *G, char name[5])
    //v相对于w的下一个邻接点
    int MTGraphSquareNextAdjVex(MTGraphSquare *G, int v, int w)
    //广度优先遍历
    //v的第一个邻接点
    int MTGraphSquareFirstAdjVex(MTGraphSquare *G, int v)
    void MTGraphSquareDFSTravel(MTGraphSquare *G)
    void MTGraphSquareDFS(MTGraphSquare *G, int i)//以vi为出发点对邻接矩阵表示的图G进行深度优先搜索
    //总而言之,就是对于表的遍历和建立两个联合起来。
    AdjGraph TransAMLraphSquareToAdjGraph(AMLGraph *T)
    MTGraphSquare TransAMLGraphSquareToMTGraph(AMLGraph *G)
    AMLGraph TransMTGraphSquareToAMLGraph(MTGraphSquare *T)
    AMLGraph TransAdjGraphSquareToAMLGraph(AdjGraph *T)
    MTGraphSquare TransAdjGraphSquareToMTGraph(AdjGraph *G)
    AdjGraph TransMTGraphSquareToAdjGraph(MTGraphSquare *T)//邻接矩阵初始化
    void PrintInitUDGAMLFalse(AMLGraph *G)//无法逆向访问
    void PrintInitUDGAMLTrue(AMLGraph *G)
    void InitUDGAML(AMLGraph *G) //用邻接多重表存储,构造无向图G
    void DisplayAML(AMLGraph *G)
    void MarkUnvizitedAML(AMLGraph *G)
    /* bo7-4.c 无向图的邻接多重表存储(存储结构由c7-4.h定义)的基本函数类型(16个) */
    int LocateVex(AMLGraph *G,VertexData u)
    void PrintAdjGraph (AdjGraph *G)
    void CreateAdjGraph (AdjGraph *G)//邻接表初始化
    void PrintMTGraphSquare(MTGraphSquare *T)//邻接矩阵打印
    void InitMTGraphSquare(MTGraphSquare *T)//邻接矩阵初始

    从main函数开始启动程序,根据输入的choice来判断要进入哪一个函数。根据界面的提示:
    printf(“Please input your choice.INPUT 18 to exit ”);
    printf(“0:初始化邻接矩阵(MTGraph) ”);
    printf(“1:深度优先递归邻接矩阵(MTGraph) ”);
    printf(“2:广度优先递归邻接矩阵(MTGraph) ”);
    printf(“3:深度优先非递归邻接矩阵(MTGraph) ”);
    printf(“4:邻接矩阵到邻接多重表的转换(MTGraph) ”);
    printf(“5:邻接矩阵到邻接表的转换(MTGraph) ”);
    printf(“6:初始化邻接表(AdjGraph) ”);
    printf(“7:深度优先递归邻接表(AdjGraph) ”);
    printf(“8:广度优先递归邻接表(AdjGraph) ”);
    printf(“9:深度优先非递归邻接表(AdjGraph) ”);
    printf(“10:邻接表到邻接矩阵的转换(AdjGraph) ”);
    printf(“11:邻接表到邻接多重表的转换(AdjGraph) ”);
    printf(“12:初始化邻接多重表(AMLGraph) ”);
    printf(“13:深度优先递归邻接多重表(AMLGraph) ”);
    printf(“14:广度优先递归邻接多重表(AMLGraph) ”);
    printf(“15:深度优先非递归邻接多重表(AMLGraph) ”);
    printf(“16:邻接多重表到邻接矩阵的转换(AMLGraph) ”);
    printf(“17:邻接多重表到邻接表的转换(AMLGraph) ”);
    printf(“INPUT 18 to exit ”);
    scanf(“%d”,&choice);
    getchar();
    这些函数互相直接几乎没有调用关系,但是每次开始都会清除一次bool visited[]数组,使得全为false。便于访问表的时候记录是否访问过该位置。
    其实这些存储结构之间的转换都是很相似的,访问方式和顺序也是相似的,但是具体的存储结构的不同,要具体去写还是会在实际中遇到很多问题。六个表之间的转换其实步骤都是相似的,只是把数据都给读出来,然后按照相应的表储存。
    示例数据保存的图如下面的图表示。

    dfs搜索的时间复杂度分析:
    邻接表:O(n+e) ;邻接矩阵:O(n2);多重邻接表O(n+e)
    dfs遍历的大致流程如下图:
    void DFS1 (AdjGraph* G, int i)
    //以vi为出发点时对邻接表表示的图G进行先深搜索
    { EdgeNode *p;
    cout<

    define OK 1

    define TRUE 1

    define ERROR 0

    define FALSE

    typedef int SElemType;
    typedef int QElemType;
    typedef struct//栈结构
    {
    SElemType *base;
    SElemType *top;
    int stacksize;
    }SqStack;
    Status InitStack(SqStack &S)
    {
    S.base=(SElemType *)malloc(100*sizeof(SElemType));
    if(!S.base)
    exit(0);
    S.top=S.base;
    S.stacksize=100;
    return OK;
    }
    Status DestroyStack(SqStack &S)
    {
    free(S.base);
    S.base=NULL;
    S.top=NULL;
    S.stacksize=0;
    return OK;
    }
    Status Push(SqStack &S,SElemType e)
    {
    if(S.top-S.base>=S.stacksize)
    {
    S.base=(SElemType*)realloc(S.base,(S.stacksize+100)*sizeof(SElemType));
    if(!S.base)
    exit(0);
    S.top=S.base+S.stacksize;
    S.stacksize+=100;
    }
    *S.top++=e;
    return OK;
    }
    Status Pop(SqStack &S,SElemType &e)
    {
    if(S.top==S.base)
    return ERROR;
    e=*–S.top;
    return OK;
    }
    Status StackEmpty(SqStack S)
    {
    if(S.top==S.base)
    return OK;
    else
    return ERROR;
    }

    Status AMLGraphDFSTraverseFeidigui(AMLGraph *G,VertexData start)//从start顶点起,深度优先遍历图G(非递归算法)
    {
    int v,w,u;
    SqStack S,S2;
    InitStack(S);
    InitStack(S2);
    w=LocateVex(G,start);
    for(v=0;vvexnum;v++)
    visited[v]=0;
    for(v=0;vvexnum;v++)
    if(!visited[(v+w)%G->vexnum])
    {
    Push(S,(v+w)%G->vexnum);
    while(!StackEmpty(S))
    {
    Pop(S,u);
    if(!visited[u])
    {
    visited[u]=1;
    printf(“%s ”,G->adjmulist[u].data);
    for(w=FirstAdjVex(G,G->adjmulist[u].data);w>=0;
    w=NextAdjVex(G,G->adjmulist[u].data,G->adjmulist[w].data))
    if(!visited[w])
    Push(S2,w);
    while(!StackEmpty(S2))
    {
    Pop(S2,u);
    Push(S,u);
    }
    }
    }
    }
    return OK;
    }

    int AMLGraphDFSTraverseFeidiguiBUG3(AMLGraph *G,VertexData start)//从start顶点起,深度优先遍历图G(非递归算法)
    {
    /*test

    */
    int v=0,w=0,u=0;
    stack<int> S,S2;
    w=LocateVex(G,start);
    printf("-----%d-----
    ",w);
    for(v=0; v<G->vexnum; v++)
        if(!visited[(v+w)%G->vexnum])
        {
            printf("??%d??	",(v+w)%G->vexnum);
            printf("-----looping-----
    ");
            S.push((v+w)%G->vexnum);
            while(!S.empty())
            {
                printf("u:%d 
    ",u);
                S.pop();
                if(!visited[u])
                {
                    printf("#####looping####
    ");
                    visited[u]=true;
                    printf("%s",G->adjmulist[u].data);
                    for(w=FirstAdjVex(G,G->adjmulist[u].data); w>=0;
                            w=NextAdjVex(G,G->adjmulist[u].data,G->adjmulist[w].data))
                        if(!visited[w])
                        {
                             S2.push(w);
                             printf("Panduan
    ");
                        }
    
                    while(!S2.empty())
                    {
                        printf("#####S2####
    ");
                        S2.pop();
                        S.push(u);
                    }
                }
            }
        }
    return 1;
    

    }
    int AMLGraphDFSTraverseFeidiguiBUG2(AMLGraph *G,VertexData start)//从start顶点起,深度优先遍历图G(非递归算法)
    {

    int v=0,w=0;
    stack<int> S;
    w=LocateVex(G,start);
    printf("-----%d-----
    ",w);
    EBox *p;
    for(v=0; v<G->vexnum; v++)
    {
        p=G->adjmulist[w].firstedge;
        S.push(w);
        visited[w]=true;
        if(!visited[w])
            printf("%s",G->adjmulist[w].data);
        for(int i=0;visited[p->ivex]!=false;i++)
        {
    
        }
        while(p!=NULL)
        {
            w=p->ivex;
        }
    }
    
    return 1;
    

    }
    访问每个图的函数分别为:
    1:邻接矩阵:
    void PrintMTGraphSquare(MTGraphSquare *T)//邻接矩阵打印
    {
    int i,j;
    printf(“邻接矩阵打印(PrintMTGraphSquare) ”);
    for(i=0; in; i++)
    printf(“%d “,i);
    printf(“ ”);
    for(i=0; in; i++)
    {
    printf(“%d ”,i);
    for(j=0; jn; j++)
    {
    if(T->edge[i][j]!=0||T->edge[j][i]!=0)
    //cout<vertex[i];
    printf(“1 “);
    else
    printf(“0 “);
    }
    printf(“ ”);
    }
    return;
    }
    2.邻接表:
    void PrintAdjGraph (AdjGraph *G)
    {
    printf(“邻接表打印(PrintAdjGraph) ”);
    int flag[11][11]= {0};
    int i=0;
    EdgeNode p=(EdgeNode)malloc(sizeof(EdgeNode));
    for(i=0; in; i++)
    {
    p=G->vexlist[i].firstedge;
    while(p!=NULL)
    {
    if(flag[i][p->adjvex]==0&&flag[p->adjvex][i]==0)
    {
    printf(“v%d->v%d:(%d,%d):%d ”,i,p->adjvex,i,p->adjvex,p->cost);
    flag[i][p->adjvex]=1;
    flag[p->adjvex][i]=1;
    }
    p=p->next;
    }
    }
    //cout<vertex[i];
    }
    3.邻接多重表:
    void PrintInitUDGAMLTrue(AMLGraph *G)
    {
    printf(“输出无向图的邻接多重表G(PrintInitUDGAMLTrue) ”);
    int i;
    EBox p=(EBox)malloc(sizeof(EBox));
    for(i=0; ivexnum; i++)
    {
    p=G->adjmulist[i].firstedge;
    //printf(“%s : ”,G->adjmulist[i].data);
    while(p!=NULL)
    {
    if(p->mark==0)
    {
    printf(“(%s,%s):%d ”,G->adjmulist[i].data,p->info.vertex,p->info.weight);
    p->mark=1;
    }
    p=p->ilink;
    }
    }
    for(i=0; ivexnum; i++)
    {
    p=G->adjmulist[i].firstedge;
    while(p!=NULL)
    {
    if(p->mark==1)
    p->mark=0;
    p=p->ilink;
    }
    }
    return;
    }
    邻接矩阵到邻接表的转换:
    AdjGraph TransMTGraphSquareToAdjGraph(MTGraphSquare *T)//邻接矩阵初始化
    {
    printf(“邻接矩阵到邻接表的转换(TransMTGraphSquareToAdjGraph) ”);
    //PrintMTGraphSquare(T);
    int flag[11][11]= {0};
    AdjGraph G;
    int tail,head,weight;
    int j,k;
    G.n=T->n;
    G.e=T->e;//输入顶点个数和边数
    for ( int i = 0; i < G.n; i++) //建立顶点表
    {
    strcpy(G.vexlist[i].vertex,T->vertex[i]); //输入顶点信息
    G.vexlist[i].firstedge = NULL;
    } //边表置为空表
    //逐条边输入,建立边表

    for(j=0; j<G.n; j++)
    {
        for(k=0; k<G.n; k++)
        {
            if(T->edge[j][k]!=0&&flag[j][k]==0)
            {
                tail=k;
                head=j;
                weight=T->edge[j][k];
                flag[j][k]=1;
                flag[k][j]=1;
                EdgeNode *p = (EdgeNode*)malloc(sizeof(EdgeNode)); //建立边结点
                p->adjvex = head;
                p->cost = weight; //3.3设置边结点
                p->next = G.vexlist[tail].firstedge; //链入第 tail 号链表的前端
                G.vexlist[tail].firstedge = p;
                p = (EdgeNode*)malloc(sizeof(EdgeNode));
                p->adjvex = tail;
                p->cost = weight;
                p->next = G.vexlist[head].firstedge; //链入第 head 号链表的前端
                G.vexlist[head].firstedge = p;
                //printf("(%d,%d):%d
    ",tail,head,weight);
                //printf("%d,%d,%d
    ",head,tail,weight);
            }
        }//输入
    }
    
    PrintAdjGraph(&G);
    return G;
    

    }
    接表到邻接矩阵的转换:
    MTGraphSquare TransAdjGraphSquareToMTGraph(AdjGraph *G)
    {
    printf(“邻接表到邻接矩阵的转换(TransAdjGraphSquareToMTGraph) ”);
    MTGraphSquare T;
    int i,j,k,w;
    T.n=G->n;
    T.e=G->e;
    for(i=0; i

    五、经验体会与不足

    其实这些存储结构之间的转换都是很相似的,访问方式和顺序也是相似的,但是具体的存储结构的不同,要具体去写还是会在实际中遇到很多问题。六个表之间的转换其实步骤都是相似的,只是把数据都给读出来,然后按照相应的表储存。
    这次的实验中,遇到了一些问题,比如说bfs和dfs用非递归来写,我觉得这个部分对我来说最难,这个过程很难理解,但是最后在室友的帮助下,我顺利解决了这个问题。

  • 相关阅读:
    Expression Blend4经验分享:自适应布局浅析
    Expression Blend4经验分享:制作一个简单的图片按钮样式
    Expression Blend4经验分享:制作一个简单的文字按钮样式
    24.Unity手势操作(转自宣雨松博客)一
    1.关于Unity -Vuforia -Android 开发 ,平台的搭建(极品菜鸟完整版)
    26. Kinect + Unity 体感及增强现实开发历程一
    25.Unity3D手机中Input类touch详解-Unity触屏事件解析到底(Twisted Fate)
    23.Unity+Metaio SDK 开发笔记
    徐CC , Unity +C# 自学笔记2
    unity3d中的http通信
  • 原文地址:https://www.cnblogs.com/hitWTJ/p/9865433.html
Copyright © 2011-2022 走看看