【数据结构】图的操作算法

【数据结构】图的操作算法


实验内容

  1. 编写一个程序,输出下面带权有向图的邻接表,并根据该邻接表,实现图的遍历运算,具体要求如下:
    (1)从顶点0开始的深度优先遍历序列(递归算法)
    (2)从顶点0开始的广度优先遍历序列
    在这里插入图片描述
    具体效果如下:
    在这里插入图片描述
  2. 采用狄克斯特拉算法(Dijkstra),输出下面有向带权图G中从顶点0到其它各顶点的最短路径和最短路径长度。
    在这里插入图片描述
    具体效果如下:
    在这里插入图片描述

设计思路

任务一
(一)在graph.h中创建图的邻接表存储结构:
1.首先定义邻接表类型中的边结点类型ArcNode;
2.然后定义邻接表头结点类型VNode;
3.接着定义完整的图邻接表类型AdjGraph。
(二)在graph.h中创建队列的存储结构:
1.首先定义队列SqQueue
2.完成队列的基本算法
初始化InitQueue(SqQueue *&q)
判断是否为空QueueEmpty(SqQueue *q)
进队列enQueue(SqQueue *&q,int e)
出队列deQueue(SqQueue *&q,int &e)
(三)在main.cpp中完成图的基本运算算法:
1. 创建图的邻接表CreateAdj(AdjGraph *&G,int A[MAXV][MAXV],int n,int e)2. 输出邻接表G DispAdj(AdjGraph G)3. 销毁图的邻接表DestroyAdj(AdjGraph *&G)4. 定义全局函数visited[MAXV]5. 递归深度优先算法DFS(AdjGraph *G,int v)6. 非递归深度优先算法DFS1(AdjGraph *G,int v)7. 非递归广度优先算法BFS(AdjGraph *G,int v)8.主函数 main()根据问题依次调用基本操作函数并编写通俗易懂的语句输出。

任务二
(一)在Dijkstra.h中创建图的邻接表存储结构:
1.首先定义邻接表类型中的边结点类型ArcNode;
2.然后定义邻接表头结点类型VNode;
3.接着定义完整的图邻接表类型AdjGraph。
(二)在main.cpp中完成图的基本运算算法:
1. 创建图的邻接表CreateAdj(AdjGraph *&G,int A[MAXV][MAXV],int n,int e)2.  Dijkstra算法Dijkstra(MatGraph g,int v)3. 输出从顶点v出发的所有最短路径Dispath(MatGraph g,int dist[],int path[],int S[],int v)

实验代码

#include <iostream>
#include<bits/stdc++.h>
#define MAXV 100
#define MaxSize 100
#define INF 327676
using namespace std;
typedef char InfoType;
typedef char ElemType;

//以下定义邻接表类型
typedef struct ANode
{
    int adjvex;					//该边的邻接点编号
    struct ANode *nextarc;		//指向下一条边的指针
    int weight;					//该边的相关信息,如权值(用整型表示)
} ArcNode;						//边结点类型
typedef struct Vnode
{
    InfoType info;				//顶点其他信息
    int count;					//存放顶点入度,仅仅用于拓扑排序
    ArcNode *firstarc;			//指向第一条边
} VNode;						//邻接表头结点类型
typedef struct
{
    VNode adjlist[MAXV];		//邻接表头结点数组
    int n,e;					//图中顶点数n和边数e
} AdjGraph;						//完整的图邻接表类型
//队列定义
typedef struct SqQueue
{
    ElemType data[MaxSize];
    int front,rear;
} SqQueue;
//初始化
void InitQueue(SqQueue *&q)
{
    q=(SqQueue *)malloc(sizeof(SqQueue));
    q->front=q->rear=-1;
}
//判断是否为空
bool QueueEmpty(SqQueue *q)
{
    return(q->front==q->rear);
}
//进队列
bool enQueue(SqQueue *&q,int e)
{
    if(q->rear==MaxSize-1)
        return false;
    q->rear++;
    q->data[q->rear]=e;
    return true;
}
//出队列
bool deQueue(SqQueue *&q,int &e)
{
    if(q->front==q->rear)
        return false;
    q->front++;
    e=q->data[q->front];
    return true;
}

//Main.cpp
#include <iostream>
#define MAXV 100
#define MaxSize 100
#define INF 327676
#include "graph.h"
//----创建图的邻接表G----------------------------------
void CreateAdj(AdjGraph *&G,int A[MAXV][MAXV],int n,int e) //创建图的邻接表
{
    int i,j;
    ArcNode *p;
    G=(AdjGraph *)malloc(sizeof(AdjGraph));
    for (i=0; i<n; i++)								//给邻接表中所有头结点的指针域置初值
        G->adjlist[i].firstarc=NULL;
    for (i=0; i<n; i++)								//检查邻接矩阵中每个元素
        for (j=n-1; j>=0; j--)
            if (A[i][j]!=0 && A[i][j]!=INF)			//存在一条边
            {
                p=(ArcNode *)malloc(sizeof(ArcNode));	//创建一个结点p
                p->adjvex=j;
                p->weight=A[i][j];
                p->nextarc=G->adjlist[i].f
                           irstarc;	//采用头插法插入结点p
                G->adjlist[i].firstarc=p;
            }
    G->n=n;
    G->e=n;
}
//----输出邻接表G----------------------------------
void DispAdj(AdjGraph *G)
{
    int i;
    ArcNode *p;
    for (i=0; i<G->n; i++)
    {
        p=G->adjlist[i].firstarc;
        printf("%3d: ",i);
        while (p!=NULL)
        {
            printf("%3d(%d) ",p->adjvex,p->weight);
            p=p->nextarc;
        }
        printf("\n");
    }
}
//----销毁图的邻接表----------------------------------
void DestroyAdj(AdjGraph *&G)
{
    int i;
    ArcNode *pre,*p;
    for (i=0; i<G->n; i++)			//扫描所有的单链表
    {
        pre=G->adjlist[i].firstarc;	//p指向第i个单链表的首结点
        if (pre!=NULL)
        {
            p=pre->nextarc;
            while (p!=NULL)			//释放第i个单链表的所有边结点
            {
                free(pre);
                pre=p;
                p=p->nextarc;
            }
            free(pre);
        }
    }
    free(G);						//释放头结点数组
}
//----深度优先递归算法----------------------------------
int visited[MAXV];						//全局数组
void DFS(AdjGraph *G,int v)   //递归深度优先算法
{
    ArcNode *p;
    visited[v]=1;                   	//置已访问标记
    printf("%3d",v); 					//输出被访问顶点的编号
    p=G->adjlist[v].firstarc;      		//p指向顶点v的第一条弧的弧头结点
    while (p!=NULL)
    {
        if (visited[p->adjvex]==0)		//若p->adjvex顶点未访问,递归访问它
            DFS(G,p->adjvex);
        p=p->nextarc;              		//p指向顶点v的下一条弧的弧头结点
    }
}
//----深度优先非递归算法----------------------------------
void DFS1(AdjGraph *G,int v)   //非递归深度优先算法
{
    ArcNode *p;
    ArcNode *St[MAXV];
    int top=-1,w,i;
    for (i=0; i<G->n; i++)
        visited[i]=0;		//顶点访问标志均置成0
    printf("%3d",v);        //访问顶点v
    visited[v]=1;
    top++;                  //将顶点v的第一个相邻顶点进栈
    St[top]=G->adjlist[v].firstarc;
    while (top>-1)          //栈不空循环
    {
        p=St[top];
        top--;   //出栈一个顶点作为当前顶点
        while (p!=NULL)     //查找当前顶点的第一个未访问的顶点
        {
            w=p->adjvex;
            if (visited[w]==0)
            {
                printf("%3d",w); //访问w
                visited[w]=1;
                top++;           //将顶点w的第一个顶点进栈
                St[top]=G->adjlist[w].firstarc;
                break;           //退出循环
            }
            p=p->nextarc;        //找下一个相邻顶点
        }
    }
}
//BFS非递归算法
void BFS(AdjGraph *G,int v)
{
    int w,i;
    ArcNode *p;
    SqQueue *qu;
    InitQueue(qu);
    int visited[MAXV];
    for(i=0; i<G->n; i++)
        visited[i]=0;
    printf("%3d",v);
    visited[v]=1;
    enQueue(qu,v);
    while(!QueueEmpty(qu))
    {
        deQueue(qu,w);
        p=G->adjlist[w].firstarc;
        while(p!=NULL)
        {
            if(visited[p->adjvex]==0)
            {
                printf("%3d",p->adjvex);
                visited[p->adjvex]=1;
                enQueue(qu,p->adjvex);
            }
            p=p->nextarc;
        }
    }
    printf("\n");
}

int main()
{
    AdjGraph *G;
    int A[MAXV][MAXV]=
    {
        {0,5,INF,7,INF,INF},
        {INF,0,4,INF,INF,INF},
        {8,INF,0,INF,INF,9},
        {INF,INF,5,0,INF,6},
        {INF,INF,INF,5,0,INF},
        {3,INF,INF,INF,1,0}
    };
    int n=6, e=10;
    CreateAdj(G,A,n,e);             //建立实验讲义中的邻接表
    printf("图G的邻接表:\n");
    DispAdj(G);                     //输出邻接表
    printf("从顶点0开始的DFS(递归算法):\n");
    DFS(G,0);
    printf("\n");
    printf("从顶点0开始的DFS(非递归算法):\n");
    DFS1(G,0);
    printf("\n");
    printf("从顶点0开始的BFS(非递归算法):\n");
    BFS(G,0);

}

#include "Dijkstra.h"
int count=0;
void Dispath(MatGraph g,int dist[],int path[],int S[],int v)
//输出从顶点v出发的所有最短路径
{
    int i,j,k;
    int apath[MAXV],d;					//存放一条最短路径(逆向)及其顶点个数
    for (i=0; i<g.n; i++)					//循环输出从顶点v到i的路径
        if (S[i]==1 && i!=v)
        {
            printf("  从顶点%d到顶点%d的路径长度为:%d\t路径为:",v,i,dist[i]);
            d=0;
            apath[d]=i;			//添加路径上的终点
            k=path[i];
            if (k==-1)					//没有路径的情况
                printf("无路径\n");
            else						//存在路径时输出该路径
            {
                while (k!=v)
                {
                    d++;
                    apath[d]=k;
                    k=path[k];
                }
                d++;
                apath[d]=v;		//添加路径上的起点
                printf("%d",apath[d]);	//先输出起点
                for (j=d-1; j>=0; j--)	//再输出其他顶点
                    printf(",%d",apath[j]);
                printf("\n");
            }
        }
}

void Dijkstra(MatGraph g,int v)	//Dijkstra算法
{
    int dist[MAXV],path[MAXV];
    int S[MAXV];				//S[i]=1表示顶点i在S中, S[i]=0表示顶点i在U中
    int Mindis,i,j,u;
    for (i=0; i<g.n; i++)
    {
        dist[i]=g.edges[v][i];	//距离初始化
        S[i]=0;					//S[]置空
        if (g.edges[v][i]<INF)	//路径初始化
            path[i]=v;			//顶点v到顶点i有边时,置顶点i的前一个顶点为v
        else
            path[i]=-1;			//顶点v到顶点i没边时,置顶点i的前一个顶点为-1
    }
    S[v]=1;
    path[v]=0;			//源点编号v放入S中
    for (i=0; i<g.n-1; i++)		//循环直到所有顶点的最短路径都求出
    {
        Mindis=INF;				//Mindis置最大长度初值
        for (j=0; j<g.n; j++)		//选取不在S中(即U中)且具有最小最短路径长度的顶点u
            if (S[j]==0 && dist[j]<Mindis)
            {
                u=j;
                Mindis=dist[j];
            }

        S[u]=1;					//顶点u加入S中

        for (j=0; j<g.n; j++)		//修改不在S中(即U中)的顶点的最短路径
            if (S[j]==0)
            {
                if (g.edges[u][j]<INF&&dist[u]+g.edges[u][j]<dist[j])
                {
                    dist[j]=dist[u]+g.edges[u][j];
                    path[j]=u;
                }
            }

    }
    Dispath(g,dist,path,S,v);	//输出最短路径
}

int main()
{
    MatGraph g;
    int A[MAXV][MAXV]=
    {
        {0,5,INF,7,INF,INF},
        {INF,0,4,INF,INF,INF},
        {8,INF,0,INF,INF,9},
        {INF,INF,5,0,INF,6},
        {INF,INF,INF,5,0,INF},
        {3,INF,INF,INF,1,0}
    };
    int n=6, e=8;
    CreateMat(g,A,n,e);			//建立图的邻接矩阵
    printf("图G的邻接矩阵:\n");
    DispMat(g);					//输出邻接矩阵
    int v=0;
    printf("从%d顶点出发的最短路径求解过程如下:\n",v);
    Dijkstra(g,v);
    return 1;
}

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

慢热型网友.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值