数据结构与算法--图型结构的建立与搜索

本文介绍了图数据结构的三种存储方式:邻接矩阵、邻接表和邻接多重表,并实现了各自的建立与搜索算法。此外,还探讨了不同存储结构间的相互转换,包括时间复杂度分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

课程名称:数据结构与算法
课程类型:必修
实验项目:图型结构的建立与搜索
实验题目:图的存储结构的建立与搜索
实验日期: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\n");
        printf("0:初始化邻接矩阵(MTGraph)\n");
        printf("1:深度优先递归邻接矩阵(MTGraph)\n");
        printf("2:广度优先递归邻接矩阵(MTGraph)\n");
        printf("3:深度优先非递归邻接矩阵(MTGraph)\n");
        printf("4:邻接矩阵到邻接多重表的转换(MTGraph)\n");
        printf("5:邻接矩阵到邻接表的转换(MTGraph)\n");
        printf("6:初始化邻接表(AdjGraph)\n");
        printf("7:深度优先递归邻接表(AdjGraph)\n");
        printf("8:广度优先递归邻接表(AdjGraph)\n");
        printf("9:深度优先非递归邻接表(AdjGraph)\n");
        printf("10:邻接表到邻接矩阵的转换(AdjGraph)\n");
        printf("11:邻接表到邻接多重表的转换(AdjGraph)\n");
        printf("12:初始化邻接多重表(AMLGraph)\n");
        printf("13:深度优先递归邻接多重表(AMLGraph)\n");
        printf("14:广度优先递归邻接多重表(AMLGraph)\n");
        printf("15:深度优先非递归邻接多重表(AMLGraph)\n");
        printf("16:邻接多重表到邻接矩阵的转换(AMLGraph)\n");
        printf("17:邻接多重表到邻接表的转换(AMLGraph)\n");
        printf("INPUT 18 to exit\n");
        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<<G→vexlist[i].vertex; 
 visited[i]=TRUE; 
 dfn[i]=count++; 
 p=G→vexlist[i].firstedge; 
 while( p ) { 
 if( !visited[ p→adjvex ] ) 
 DFS1(G, p→adjvex); 
 p=p→next; 
 } 
}

bfs搜索的时间复杂度分析:
邻接表:O(n+e) ;邻接矩阵:O(n2);多重邻接表O(n+e)
bfs遍历的大致流程如下图:

bool visited[NumVertices]; //访问标记数组是全局变量
int dfn[NumVertices]; //顶点的先深编号
void BFSTraverse (AdjGraph G) //主算法
/* 先广搜索一邻接表表示的图G;而以邻接矩阵表示G时,算法
完全相同 */
{ int count = 1;
 for ( int i = 0; i < G.n; i++ ) 
 visited [i] =FALSE; //标志数组初始化
 for ( int i = 0; i < G.n; i++ ) 
 if ( ! visited[i] ) 
 BFSX ( G, i ); //从顶点 i 出发的一次搜索,DFSX (G, i )
}

邻接矩阵的三个遍历函数:

void MTGraphSquareDFS(MTGraphSquare *G, int i)//以vi为出发点对邻接矩阵表示的图G进行深度优先搜索
{
    int j;
    cout<<G->vertex[i]<<" "; //访问定点vi
    visited[i]=true; //标记vi已访问
    for( j=0; j<G->n; j++ ) //依次搜索vi的邻接点
    {
        //cout<<"\t"<<j;
        if ( (G->edge[i][j] >= 1)&&!visited[j] ) //若vj尚未访问
        {
            MTGraphSquareDFS(G,j);
        }
    }

}

void MTGraphSquareDFSTravel(MTGraphSquare *G)
{
    int i;
    for(i=0; i<G->n; i++)
        visited[i]=false;
    for(i=0; i<G->n; i++)
    {
        if(visited[i]==false)
        {
            MTGraphSquareDFS(G,i);
        }
    }
    printf("\n");

}
/************************************************************************/
/* 广度优先遍历(广度优先搜索)                                         */
/************************************************************************/

//广度优先遍历
//v的第一个邻接点
int MTGraphSquareFirstAdjVex(MTGraphSquare *G, int v)
{
    for (int i = 0; i < G->n; i++)
    {
        if (G->edge[v][i] != 0)
        {
            return i;
        }
    }
    return -1;
}


//v相对于w的下一个邻接点
int MTGraphSquareNextAdjVex(MTGraphSquare *G, int v, int w)
{
    for (int i = w + 1; i < G->n; i++)
    {
        if (G->edge[v][i] != 0)
        {
            return i;
        }
    }
    return -1;
}

int MTGraphSquareLocateVex(MTGraphSquare *G, char name[5])
{
    for (int i = 0; i < G->n; i++)
    {
        if (0 == strcmp(G->vertex[i], name))
        {
            return i;
        }
    }
    return -1;
}

void MTGraphSquareBFSTraverse(MTGraphSquare *G, char vName[5])
{
    int pos = MTGraphSquareLocateVex(G, vName);
    for (int v = 0; v < G->n; v++)
    {
        visited[v] = false;
    }
    queue<int> q;
    if (!visited[pos])
    {
        cout<<G->vertex[pos]<<'\t';
        visited[pos] = true;
    }
    q.push(pos);
    while (!q.empty())
    {
        int v = q.front();
        q.pop();
        for (int w = MTGraphSquareFirstAdjVex(G, v); w >= 0; w = MTGraphSquareNextAdjVex(G, v, w))
        {
            if (!visited[w])
            {
                cout<<G->vertex[w]<<'\t';
                visited[w] = true;
                q.push(w);
            }
        }
    }
    cout<<endl;
}

void MTGraphSquareDFS2(MTGraphSquare *G, int i)
{
    int j;
    stack<int> S;
    S.push(i);
    printf("%s",G->vertex[i]);
    printf("\t");
    visited[0] = 1;

    while(!S.empty())
    {

        S.pop();

        for(j = 0; j < G->n; j ++)
        {
            if(G->edge[i][j] && !visited[j])
            {
                S.push(j);
                printf("%s",G->vertex[j]);
                printf("\t");
                visited[j] = 1;
                i = j;
                j = 0;
            }
        }

        if(!S.empty())
        {
            S.pop();
        }
    }
}

void MTGraphSquareDFSTraverse2(MTGraphSquare *G)
{
    int i;
    for(i = 0; i < G->n; i ++)
        visited[i] = 0;
    for(i = 0; i < G->n; i ++)
    {
        if(!visited[i])
            MTGraphSquareDFS2(G,i);
    }
    printf("\n");
}

void AdjGraphDFS1(AdjGraph *G,int i)
{
    EdgeNode *p;
    cout<<G->vexlist[i].vertex<<endl;
    visited[i] = true;
    p = G->vexlist[i].firstedge;
    while(p)
    {
        if(!visited[p->adjvex])
            AdjGraphDFS1(G,p->adjvex);
        p = p->next;
    }
}


//深度优先遍历主程序
void AdjGraphDFSTraverse(AdjGraph *G)
{
    int i ;
    for(i=0; i<G->n; i++)
        visited[i]=false;
    for(i=0; i<G->n; i++)
        if(!visited[i])
            AdjGraphDFS1(G,i);
}

邻接表的三个遍历函数:

//广度优先遍历 (递归)
//缺点递归最大为G.numv次
int r=0;
int f=0;
int q[100];
void AdjGraphBFS(AdjGraph *G,int s)
{
    if(!visited[s])
    {
        printf("%s",G->vexlist[s].vertex);
        cout<<" ";
        visited[s] = 1;
        EdgeNode* p = G->vexlist[s].firstedge;
        while(p != NULL)
        {
            if(!visited[p->adjvex])
                q[r++] = p->adjvex;
            p = p->next;
        }
    }
    while(f < r)
    {
        AdjGraphBFS(G,q[f++]);
    }
}

//深度优先(非递归)
//LGraph: 邻接表
//InitVertex: 遍历起始顶点
void AdjGraphDFS2(AdjGraph *LGraph, int InitVertex)
{
    int stack[25];        //栈
    int top = -1;

    EdgeNode* pEdge = NULL;
    int Pre[25];
    int index = -1;        //Pre数组的下标

    visited[InitVertex] = true;            //起始顶点标记已访问
    cout << InitVertex << " ";            //输出起始顶点

    //把所有与起始顶点关联的顶点存入Per数组中
    pEdge = LGraph->vexlist[InitVertex].firstedge;
    while (NULL != pEdge)
    {
        Pre[++index] = pEdge->adjvex;
        pEdge = pEdge->next;
    }
    //逆序把Pre数组中的顶点加入栈中
    for (int i = index; i >= 0; i--)
    {
        top++;
        stack[top] = Pre[i];
        visited[Pre[i]] = 1;        //入栈的顶点标记已访问
    }

    while (top > -1)
    {
        int TopVertex = stack[top];
        top--;
        cout << TopVertex << " ";        //输出栈顶节点

        pEdge = LGraph->vexlist[TopVertex].firstedge;        //把所有与栈底顶点关联且未访问过的顶点入栈
        index = -1;    //重置Pre数组下标
        while (NULL != pEdge)
        {
            if (visited[pEdge->adjvex] == 0)
                Pre[++index] = pEdge->adjvex;
            pEdge = pEdge->next;
        }
        for (int i = index; i >= 0; i--)        //逆序把Pre数组中的顶点加入到栈中
        {
            top++;
            stack[top] = Pre[i];
            visited[Pre[i]] = 1;
        }
    }//end while(top > -1)
}


/*void AdjGraphDFS(AdjGraph  *T, int v)
{
    visited[v] = true;
    cout << T.vexlist[v].vertex << " ";
    EBox* p= T.vexlist[v].firstedge;
    while (p)
    {
        if (!visited[p->adjvex])
            DFSAdjGraph(T, p->adjvex);
        p = p->next;
    }
}

void AdjGraphDFSTraverse(AdjGraph *T)
{
    for (int i = 0; i < T.vexNum; i++)//初始化访问标志数组
        visited[i] = false;

    for (int i = 0; i < T.vexNum; i++)
    {
        if (!visited[i])//如果没有访问
            DFSAdjGraph(T, i);
    }
*/




void AMLGraphDFS(AMLGraph *G,int v)
{
    int j;
    EBox *p;
    printf("%s\t",G->adjmulist[v].data);
    visited[v]=true;
    p=G->adjmulist[v].firstedge;
    while(p)
    {
        j=p->ivex==v?p->jvex:p->ivex;
        if(!visited[j])
            AMLGraphDFS(G,j);
        p=p->ivex==v?p->ilink:p->jlink;
    }
}


void AMLGraphDFSTraverse(AMLGraph *G)
{
    /* 初始条件: 图G存在,Visit是顶点的应用函数。算法7.4 */
    /* 操作结果: 从第1个顶点起,深度优先遍历图G,并对每个顶点调用函数Visit */
    /*           一次且仅一次。一旦Visit()失败,则操作失败 */
    int v;
    for(v=0; v<G->vexnum; v++)
        if(!visited[v])
            AMLGraphDFS(G,v);
    printf("\n");
}


int FirstAdjVex(AMLGraph *G,VertexData v)//寻找v的第一个邻接顶点
{
    int i;
    i=LocateVex(G,v);
    if(i<0)
        return -1;
    if(G->adjmulist[i].firstedge)//v有邻接顶点
        if(G->adjmulist[i].firstedge->ivex==i)
            return G->adjmulist[i].firstedge->jvex;
        else
            return G->adjmulist[i].firstedge->ivex;
    else
        return -1;
}

int NextAdjVex(AMLGraph *G,VertexData v,VertexData w)//返回v的(相对于w的)下一个邻接顶点
{
    int i,j;
    EBox *p;
    i=LocateVex(G,v);//i是顶点v的序号
    j=LocateVex(G,w); //j是顶点w的序号
    if(i<0||j<0)//v或w不是G的顶点
        return -1;
    p=G->adjmulist[i].firstedge; //p指向顶点v的第1条边
    while(p)
        if(p->ivex==i && p->jvex!=j) //不是邻接顶点w(情况1)
            p=p->ilink; //找下一个邻接顶点
        else if(p->jvex==i && p->ivex!=j) //不是邻接顶点w(情况2)
            p=p->jlink; //找下一个邻接顶点
        else //是邻接顶点w
            break;
    if(p&&p->ivex==i&&p->jvex==j) //找到邻接顶点w(情况1)
    {
        p=p->ilink;
        if(p&&p->ivex==i)
            return p->jvex;
        else if(p&&p->jvex==i)
            return p->ivex;
    }
    if(p&&p->ivex==j&&p->jvex==i)//找到邻接顶点w(情况2)
    {
        p=p->jlink;
        if(p&&p->ivex==i)
            return p->jvex;
        else if(p&&p->jvex==i)
            return p->ivex;
    }
    return -1;
}
邻接多重表的三个遍历函数:
void AMLGraphBFSTraverse(AMLGraph *G)
{
    /* 初始条件: 图G存在,Visit是顶点的应用函数。算法7.6 */
    /* 操作结果: 从第1个顶点起,按广度优先非递归遍历图G,并对每个顶点调用函数 */
    /*           Visit一次且仅一次。一旦Visit()失败,则操作失败。 */
    /*           使用辅助队列Q和访问标志数组visite */
    int v=0,u=0,w=0;
    VertexData w1,u1;
    queue<int> Q;
    for(v=0; v<G->vexnum; v++)
        if(!visited[v]) /* v尚未访问 */
        {
            visited[v]=true; /* 设置访问标志为TRUE(已访问) */
            printf("%s\t",G->adjmulist[v].data);
            Q.push(v);/* v入队列 */
            while(!Q.empty()) /* 队列不空 */
            {
                Q.pop(); /* 队头元素出队并置为u */
                strcpy(u1,G->adjmulist[u].data);
                for(w=FirstAdjVex(G,u1); w>=0; w=NextAdjVex(G,u1,strcpy(w1,G->adjmulist[w].data)))
                    if(!visited[w]) /* w为u的尚未访问的邻接顶点的序号 */
                    {
                        visited[w]=true;
                        printf("%s\t",G->adjmulist[w].data);
                        Q.push(w);
                    }
            }
        }
    printf("\n");
}

//still someBUG
void AMLGraphDFSTraverseFeidiguiBUG(AMLGraph *LGraph, int InitVertex)
{
    int stack[25];        //栈
    int top = -1;
    EBox * pEdge = NULL;
    int Pre[25];
    int index = -1;        //Pre数组的下标

    visited[InitVertex] = true;            //起始顶点标记已访问
    cout << InitVertex << " ";            //输出起始顶点

    //把所有与起始顶点关联的顶点存入Per数组中
    pEdge = LGraph->adjmulist[InitVertex].firstedge;
    while (NULL != pEdge)
    {
        Pre[++index] = pEdge->ivex;
        pEdge = pEdge->ilink;
    }
    //逆序把Pre数组中的顶点加入栈中
    for (int i = index; i >= 0; i--)
    {
        top++;
        stack[top] = Pre[i];
        visited[Pre[i]] = 1;        //入栈的顶点标记已访问
    }

    while (top > -1)
    {
        int TopVertex = stack[top];
        top--;
        cout << TopVertex << " ";        //输出栈顶节点

        pEdge = LGraph->adjmulist[TopVertex].firstedge;        //把所有与栈底顶点关联且未访问过的顶点入栈
        index = -1;    //重置Pre数组下标
        while (NULL != pEdge)
        {
            if (visited[pEdge->ivex] == 0)
                Pre[++index] = pEdge->ivex;
            pEdge = pEdge->ilink;
        }
        for (int i = index; i >= 0; i--)        //逆序把Pre数组中的顶点加入到栈中
        {
            top++;
            stack[top] = Pre[i];
            visited[Pre[i]] = 1;
        }
    }//end while(top > -1)
}

typedef int Status;
#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;v<G->vexnum;v++)
  visited[v]=0;
 for(v=0;v<G->vexnum;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\t",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-----\n",w);
    for(v=0; v<G->vexnum; v++)
        if(!visited[(v+w)%G->vexnum])
        {
            printf("??%d??\t",(v+w)%G->vexnum);
            printf("-----looping-----\n");
            S.push((v+w)%G->vexnum);
            while(!S.empty())
            {
                printf("u:%d \n",u);
                S.pop();
                if(!visited[u])
                {
                    printf("#####looping####\n");
                    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\n");
                        }

                    while(!S2.empty())
                    {
                        printf("#####S2####\n");
                        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-----\n",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)\n  \t");
    for(i=0; i<T->n; i++)
        printf("%d ",i);
    printf("\n");
    for(i=0; i<T->n; i++)
    {
        printf("%d\t",i);
        for(j=0; j<T->n; j++)
        {
            if(T->edge[i][j]!=0||T->edge[j][i]!=0)
                //cout<<T->vertex[i];
                printf("1 ");
            else
                printf("0 ");
        }
        printf("\n");
    }
    return;
}

2.邻接表:

void PrintAdjGraph (AdjGraph *G)
{
    printf("邻接表打印(PrintAdjGraph)\n");
    int flag[11][11]= {0};
    int i=0;
    EdgeNode *p=(EdgeNode*)malloc(sizeof(EdgeNode));
    for(i=0; i<G->n; 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\n",i,p->adjvex,i,p->adjvex,p->cost);
                flag[i][p->adjvex]=1;
                flag[p->adjvex][i]=1;
            }
            p=p->next;
        }
    }
    //cout<<T->vertex[i];
}

3.邻接多重表:

void PrintInitUDGAMLTrue(AMLGraph *G)
{
    printf("输出无向图的邻接多重表G(PrintInitUDGAMLTrue)\n");
    int i;
    EBox *p=(EBox*)malloc(sizeof(EBox));
    for(i=0; i<G->vexnum; i++)
    {
        p=G->adjmulist[i].firstedge;
        //printf("%s :\n",G->adjmulist[i].data);
        while(p!=NULL)
        {
            if(p->mark==0)
            {
                printf("(%s,%s):%d\n",G->adjmulist[i].data,p->info.vertex,p->info.weight);
                p->mark=1;
            }
            p=p->ilink;
        }
    }
    for(i=0; i<G->vexnum; 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)\n");
    //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\n",tail,head,weight);
                //printf("%d,%d,%d\n",head,tail,weight);
            }
        }//输入
    }

    PrintAdjGraph(&G);
    return G;
}

接表到邻接矩阵的转换:

MTGraphSquare TransAdjGraphSquareToMTGraph(AdjGraph *G)
{
    printf("邻接表到邻接矩阵的转换(TransAdjGraphSquareToMTGraph)\n");
    MTGraphSquare T;
    int i,j,k,w;
    T.n=G->n;
    T.e=G->e;
    for(i=0; i<T.n; i++)
    {
        strcpy(T.vertex[i],G->vexlist->vertex);
    }
    for(i=0; i<T.n; i++)
        for(j=0; j<T.n; j++)
            T.edge[i][j]=0;
    EdgeNode *p;
    for(k=0; k<T.n; k++)
    {
        p=G->vexlist[k].firstedge;
        while(p!=NULL)
        {
            i=p->adjvex;
            j=k;
            w=p->cost;
            T.edge[i][j]=w;
            p=p->next;
        }//printf("v%d->v%d:(%d,%d):%d\n",i,j,i,j,T->edge[i][j]);
    }

    PrintMTGraphSquare(&T);
    return T;
}

邻接表到邻接多重表的转换:

AMLGraph TransAdjGraphSquareToAMLGraph(AdjGraph *T)
{
    AMLGraph G;
    printf("邻接表到邻接多重表的转换(TransAdjGraphSquareToAMLGraph)\n");
    printf("输入无向图的邻接多重表G(InitUDGAML)\n");
    //char v1[5], v2[5];
    int v1,v2;
    char str[5]="v0";
    str[0]='v';
    int i, j, weight;
    int flag[12][12]= {1};
    G.vexnum=T->n;
    G.edgenum=T->e;
    //printf("debug1\n");

    for(i=0; i<12; i++)
        for(j=0; j<12; j++)
            flag[i][j]=1;
    for(i=0; i<G.vexnum; i++) //建立顶点表
    {
        strcpy(G.adjmulist[i].data,T->vexlist[i].vertex);
        G.adjmulist[i].firstedge=NULL;
    }
    EdgeNode *temp;
    //printf("debug2\n");
    for(i=0; i<G.vexnum; i++)
    {
        temp=T->vexlist[i].firstedge;
        while(temp!=NULL)
        {
            //printf("%d %d %d\n",i,temp->adjvex,temp->cost);
            if(flag[i][temp->adjvex]||flag[temp->adjvex][i])
            {
                flag[i][temp->adjvex]=0;
                flag[temp->adjvex][i]=0;
                v1=i;
                v2=temp->adjvex;
                weight=temp->cost;

                printf("%d %d %d\n",v1,v2,weight);//程序出错竟然是因为%d输出成了%s!!!小错误可能导致大bug!

                //i=LocateVex(G,v1);
                //j=LocateVex(G,v2);
                i=v1;
                j=v2;
                while(i<0|| i>G.vexnum-1 || j<0 || j>G.vexnum-1)
                {
                    cout<<"结点位置输入错误,重新输入: ";
                    v1=i;
                    v2=temp->adjvex;
                    i=v1;
                    j=v2;
                }
                EBox *p=(EBox*)malloc(sizeof(EBox));
                p->ivex=i;
                p->jvex=j;
                p->mark=0;
                str[2]='\0';
                if(j<10)
                    str[1]=j+48;
                else
                    strcpy(str,"v10");
                strcpy(p->info.vertex,str);
                p->ilink=G.adjmulist[i].firstedge;
                p->jlink=G.adjmulist[j].firstedge;
                p->info.weight=weight;
                G.adjmulist[i].firstedge=G.adjmulist[j].firstedge = p;
            }
            temp=temp->next;

        }
    }
    printf("\n");
    PrintInitUDGAMLTrue(&G);
    printf("\n");
    DisplayAML(&G);
    return G;
}
邻接矩阵到邻接多重表的转换:
AMLGraph TransMTGraphSquareToAMLGraph(MTGraphSquare *T)
{
    AMLGraph G;
    printf("邻接矩阵到邻接多重表的转换(TransMTGraphSquareToAMLGraph)\n");
    printf("输入无向图的邻接矩阵T(InitUDGAML)\n");
    //char v1[5], v2[5];
    int v1,v2;
    char str[5]="v0";
    str[0]='v';
    int i, j, k,x,weight;
    int flag[12][12]= {1};
    G.vexnum=T->n;
    G.edgenum=T->e;


    for(i=0; i<12; i++)
        for(j=0; j<12; j++)
            flag[i][j]=1;
    for(i=0; i<G.vexnum; i++) //建立顶点表
    {
        strcpy(G.adjmulist[i].data,T->vertex[i]);
        G.adjmulist[i].firstedge=NULL;
    }

    for(x=0; x<G.vexnum; x++)
        for(k=0; k<G.vexnum; k++)
        {
            if(T->edge[x][k]!=0&&flag[x][k]&&flag[k][x])
            {
                v1=x;
                v2=k;
                flag[x][k]=0;
                flag[k][x]=0;
                weight=T->edge[x][k];
                printf("%d %d %d\n",v1,v2,weight);//程序出错竟然是因为%d输出成了%s!!!小错误可能导致大bug!
                i=v1;
                j=v2;
                while(i<0|| i>G.vexnum-1 || j<0 || j>G.vexnum-1)
                {
                    cout<<"结点位置输入错误,重新输入: ";
                    if(T->edge[x][k]!=0&&flag[x][k]&&flag[k][x])
                    {
                        v1=x;
                        v2=k;
                        flag[x][k]=0;
                        flag[k][x]=0;
                        weight=T->edge[x][k];
                    }
                    i=v1;
                    j=v2;
                }
                EBox *p=(EBox*)malloc(sizeof(EBox));
                p->ivex=i;
                p->jvex=j;
                p->mark=0;
                str[2]='\0';
                if(j<10)
                    str[1]=j+48;
                else
                    strcpy(str,"v10");
                strcpy(p->info.vertex,str);
                p->ilink=G.adjmulist[i].firstedge;
                p->jlink=G.adjmulist[j].firstedge;
                p->info.weight=weight;
                G.adjmulist[i].firstedge=G.adjmulist[j].firstedge = p;
            }
        }
    printf("\n");
    PrintInitUDGAMLTrue(&G);
    printf("\n");
    DisplayAML(&G);
    return G;
}
邻接多重表到邻接矩阵的转换:
MTGraphSquare TransAMLGraphSquareToMTGraph(AMLGraph *G)
{
    printf("邻接多重表到邻接矩阵的转换(TransAMLGraphSquareToMTGraph)\n");
    int i,j,k,w;
    MTGraphSquare T;
    T.n=G->vexnum;
    T.e=G->edgenum;
    for(i=0; i<T.n; i++)
    {
        strcpy(T.vertex[i],G->adjmulist[i].data);
    }
    for(i=0; i<T.n; i++)
        for(j=0; j<T.n; j++)
            T.edge[i][j]=0;
    EBox *p=(EBox*)malloc(sizeof(EBox));
    for(i=0; i<G->vexnum; i++)
    {
        p=G->adjmulist[i].firstedge;
        //printf("%s :\n",G->adjmulist[i].data);
        while(p!=NULL)
        {
            //printf("In loop.\n");
            if(p->mark==0)
            {
                k=p->ivex;
                j=p->jvex;
                w=p->info.weight;
                //printf("%d,%d  :%d\n",k,j,w);
                T.edge[k][j]=w;
                p->mark=1;
            }
            p=p->ilink;
        }
    }
    for(i=0; i<G->vexnum; i++)
    {
        p=G->adjmulist[i].firstedge;
        while(p->ilink!=NULL)
        {
            if(p->mark==1)
                p->mark=0;
            p=p->ilink;
        }
    }
    PrintMTGraphSquare(&T);
    return T;
}
邻接多重表到邻接表的转换:
//总而言之,就是对于表的遍历和建立两个联合起来。
AdjGraph TransAMLraphSquareToAdjGraph(AMLGraph *T)
{
    printf("邻接多重表到邻接表的转换(TransAMLraphSquareToAdjGraph)\n");
    int i;
    int tail,head,weight;
    AdjGraph G;
    G.n=T->vexnum;
    G.e=T->edgenum;
    for(i=0; i<G.n; i++)//建立顶点表
    {
        strcpy(G.vexlist[i].vertex,T->adjmulist[i].data);//输入顶点信息
        G.vexlist[i].firstedge = NULL;//边表置为空表
    }
    EBox *p=(EBox*)malloc(sizeof(EBox));



    for(i=0; i<G.n; i++)
    {
        p=T->adjmulist[i].firstedge;
        //printf("%s :\n",G.adjmulist[i].data);
        while(p!=NULL)
        {
            //printf("In loop.\n");
            if(p->mark==0)
            {
                tail=p->ivex;
                head=p->jvex;
                weight=p->info.weight;
                //printf("%d,%d  :%d\n",k,j,w);
                p->mark=1;
                EdgeNode *q = (EdgeNode*)malloc(sizeof(EdgeNode)); //建立边结点
                q->adjvex = head;
                q->cost = weight; //3.3设置边结点
                q->next = G.vexlist[tail].firstedge; //链入第 tail 号链表的前端
                G.vexlist[tail].firstedge = q;
                q = (EdgeNode*)malloc(sizeof(EdgeNode));
                q->adjvex = tail;
                q->cost = weight;
                q->next = G.vexlist[head].firstedge; //链入第 head 号链表的前端
                G.vexlist[head].firstedge = q;
                printf("(%d,%d):%d\n",tail,head,weight);
            }
            p=p->ilink;

        }
    }
    PrintAdjGraph(&G);

    for(i=0; i<T->vexnum; i++)
    {
        p=T->adjmulist[i].firstedge;
        while(p!=NULL)
        {
            if(p->mark==1)
                p->mark=0;
            p=p->ilink;
        }
    }
    return G;
}

五、经验体会与不足

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值