【数据结构】图的操作(深度优先,广度优先,Dijkstra算法)

内容:
1)采用邻接矩阵/邻接表建立图;
2)采用深度优先/广度优先搜索方式遍历图
3)编程实现Dijkstra最短路径算法

实现思路:
① 定义邻接矩阵和邻接表的数据类型
② 定义visited数组存储该点是否访问
③ 编写创建图的函数
④ 编写深度优先遍历,使用递归的方法(栈)
⑤ 编写广度优先遍历,使用队列的方法
⑥ 编写Dijkstra算法,使用D[]存储起始点到某点的距离,S[]存储点是否访问过,Path[]存储某点的前一点

程序代码:
1、定义队列头文件:sqqueue.h

#ifndef SQQUEUE
#define SQQUEUE

#define MAXQAIZE 100 //队列可能达到的最大长度
typedef char QElemType;

class SqQueue
{
public:
    QElemType *base; //存储空间的基地址
    int front;  //头指针
    int rear;   //尾指针
    void InitQueue(); //初始化
    void EnQueue(QElemType e);  //入队
    void DeQueue(QElemType &e);  //出队
    bool QueueEmpty(); //判空
};
#endif // SQQUEUE

2、头文件实现

#include "SqQueue.h"

#define MAXQAIZE 100 //队列可能达到的最大长度
typedef char QElemType;

void SqQueue::InitQueue() //初始化
{
    base=new QElemType[MAXQAIZE]; //为队列分配一个最大容量为MAXQSIZE的数组空间
    front=rear=0;  //头指针尾指针置为零,队列为空
}

void SqQueue::EnQueue(QElemType e)  //入队
{
    base[rear]=e;  //新元素插入队尾
    rear=(rear+1)%MAXQAIZE;  //尾指针后移一位
}

void SqQueue::DeQueue(QElemType &e)  //出队
{
    e=base[front];  //保存队头元素
    front=(front+1)%MAXQAIZE;  //队头指针后移一位
}

bool SqQueue::QueueEmpty()
{
    if(rear==front)
        return true;
    return false;
}

3、主要部分实现:main.cpp

#include <iostream>
#include <windows.h>
#include <algorithm>
#include "SqQueue.h"

using namespace std;

//图的邻接矩阵存储表示
#define MaxInt 32767 //表示极大值,即∞
#define MVNum 100 //最大顶点数
typedef char VerTextType; //顶点数据类型
typedef int ArcType; //边的权值的数据类型
typedef struct
{
    VerTextType vexs[MVNum]; //顶点表
    ArcType arcs[MVNum][MVNum]; //邻接矩阵表
    int vexnum,arcnum; //图的当前点数和边数
    bool visited[MVNum]; //访问标志数组,其处置为false
}AMGraph;

typedef struct ArcNode
{
    int adjvex;
    struct ArcNode *nextarc;
    ArcType info;
}ArcNode;
typedef   struct  VNode//顶点结构
{
     VerTextType   data; //顶点信息
     ArcNode   * firstarc; //指向依附该顶点的第一条弧的指针
}VNode, AdjList[MVNum];
typedef   struct //图结构
{
      AdjList vertics ; //邻接表
      int  vexnum, arcnum; //顶点数和弧数
      bool visited[MVNum];
}ALGraph;

int LocateVex_AM(AMGraph G,char v) //邻接矩阵方法定位顶点
{
    for(int i=0;i<G.vexnum;i++)
        if(v==G.vexs[i])
            return i;
    return -1;
}
int LocateVex_AL(ALGraph G,char c) //邻接表方法定位顶点
{
    for(int i=0;i<G.vexnum;i++)
    {
        if(c==G.vertics[i].data)
            return i;
    }
    return -1;
}

void CreateUDN_AM(AMGraph &G) //采用邻接矩阵创建无向网
{
    cout<<"请输入无向图的顶点数和边数:"<<endl;
    cin>>G.vexnum>>G.arcnum; //输入顶点数和边数

    cout<<"请输入这"<<G.vexnum<<"个顶点:"<<endl;
    for(int i=0;i<G.vexnum;i++) //初始化顶点
    {
        cin>>G.vexs[i];
        G.visited[i]=false;
    }


    for(int i=0;i<G.vexnum;i++) //初始化邻接矩阵,边的权值均设为最大值MaxInt
        for(int j=0;j<G.vexnum;j++)
            G.arcs[i][j]=MaxInt;

    cout<<"请依次输入这"<<G.arcnum<<"条边已依附的顶点及权值:"<<endl;
    for(int k=0;k<G.arcnum;k++) //构造邻接矩阵
    {
        char v1,v2;
        int w;
        cin>>v1>>v2>>w;
        int i=LocateVex_AM(G,v1);
        int j=LocateVex_AM(G,v2);
        G.arcs[i][j]=w;
        G.arcs[j][i]=G.arcs[i][j];
    }
}
void CreateUDN_AL(ALGraph &G) //采用邻接表创建无向网
{
    cout<<"请输入无向图的顶点数和边数:"<<endl;
    cin>>G.vexnum>>G.arcnum;      //输入总顶点数,总边数
    cout<<"请输入这"<<G.vexnum<<"个顶点:"<<endl;
    for(int i = 0; i<G.vexnum; ++i)
    {	//输入各点,构造头结点表
       cin>> G.vertics[i].data; 	//输入顶点值
       G.vertics[i].firstarc=NULL; //初始化表头结点的指针域为NULL
    }
    cout<<"请依次输入这"<<G.arcnum<<"条边已依附的顶点及权值:"<<endl;
    for(int k = 0; k<G.arcnum;++k)
    {
        char v1,v2;//输入各边,构造邻接表
        int w;
        cin>>v1>>v2>>w;                 			//输入一条边依附的两个顶点
        int i = LocateVex_AL(G, v1);
        int j = LocateVex_AL(G, v2);
        ArcNode *p1=new ArcNode; //生成一个新的边结点*p1
        p1->adjvex=j;
        p1->info=w;
        p1->nextarc= G.vertics[i].firstarc;
        G.vertics[i].firstarc=p1;
       //将新结点*p1插入顶点vi的边表头部
        ArcNode *p2=new ArcNode; //生成另一个对称的新的边结点*p2
        p2->adjvex=i;//邻接点序号为i
        p2->info=w;
        p2->nextarc= G.vertics[j].firstarc;
        G.vertics[j].firstarc=p2;
        //将新结点*p2插入顶点vj的边表头部
    }//for
}


void DFS_AM(AMGraph &G,int v_index) //深度优先遍历邻接矩阵
{
    cout<<G.vexs[v_index]<<" ";
    G.visited[v_index]=true;
    for(int i=0;i<G.vexnum;i++)
    {
        if((G.arcs[v_index][i]!=MaxInt) && G.visited[i]==false)
            DFS_AM(G,i);
    }
}
void DFS_AL(ALGraph &G,int v_index) //深度优先遍历邻接表
{
    cout<<G.vertics[v_index].data<<" ";
    G.visited[v_index]=true;
    ArcNode *p=G.vertics[v_index].firstarc;
    while(p!=NULL)
    {
        int w=p->adjvex;
        if(!G.visited[w])
            DFS_AL(G,w);
        p=p->nextarc;
    }
}

void BFS_AM(AMGraph G,int v_index)
{
    cout<<G.vexs[v_index]<<" ";
    G.visited[v_index]=true;
    SqQueue Q;
    Q.InitQueue();
    Q.EnQueue(G.vexs[v_index]);
    while(!Q.QueueEmpty())
    {
        char u;
        Q.DeQueue(u);
        int index=LocateVex_AM(G,u);
        for(int i=0;i<G.vexnum;i++)
        {
            if(!G.visited[i]&&G.arcs[index][i]!=MaxInt)
            {
                cout<<G.vexs[i]<<" ";
                G.visited[i]=true;
                Q.EnQueue(G.vexs[i]);
            }
        }
    }
}
int FirstAdjVex(ALGraph G,char u)
{
    int index=LocateVex_AL(G,u);
    ArcNode *p=G.vertics[index].firstarc;
    return p->adjvex;
}
int NextAdjVex(ALGraph G,char u,int w)
{
    int index=LocateVex_AL(G,u);
    ArcNode *p=G.vertics[index].firstarc;
    while(p->adjvex!=w)
    {
        p=p->nextarc;
    }
    if(p->nextarc==NULL)
        return -1;
    else
        return p->nextarc->adjvex;
}
void BFS_AL(ALGraph G,int v_index)
{
    cout<<G.vertics[v_index].data<<" ";
    G.visited[v_index]=true;
    SqQueue Q;
    Q.InitQueue();
    Q.EnQueue(G.vertics[v_index].data);
    while(!Q.QueueEmpty())
    {
        char u;
        Q.DeQueue(u);

        for(int w=FirstAdjVex(G,u);w>=0;w=NextAdjVex(G,u,w))
        {
            if(!G.visited[w])
            {
                cout<<G.vertics[w].data<<" ";
                G.visited[w]=true;
                Q.EnQueue(G.vertics[w].data);
            }

        }
    }
}

bool S[MVNum];
ArcType D[MVNum];
int Path[MVNum];

void ShorttestPath_DIJ_AM(AMGraph G,int v0)
{
    int n=G.vexnum;
    for(int i=0;i<n;i++)
    {
        S[i]=false;
        D[i]=G.arcs[v0][i];
        if(D[i]<MaxInt)
            Path[i]=v0;
        else
            Path[i]=-1;
    }
    S[v0]=true;
    D[v0]=0;

    int v;
    for(int i=1;i<n;i++)
    {
        int min=MaxInt;
        for(int w=0;w<n;w++)
        {
            if(!S[w]&&D[w]<min)
            {
                v=w;
                min=D[w];
            }
        }
        S[v]=true;
        int z=v;
        cout<<G.vexs[v0]<<"->"<<G.vexs[z]<<":";
        string str="";
        str+=G.vexs[z];
        do
        {
            z=Path[z];
            str+=",";
            str+=G.vexs[z];

        }while(z!=v0);
        reverse(str.begin(),str.end());
        cout<<"("<<str<<")"<<D[v]<<endl;

        for(int w=0;w<n;w++)
        {
            if(!S[w]&&(D[v]+G.arcs[v][w]<D[w]))
            {
                D[w]=D[v]+G.arcs[v][w];
                Path[w]=v;
            }
        }
    }
}

void ShorttestPath_DIJ_AL(ALGraph G,int v0)
{
    int n=G.vexnum;
    for(int i=0;i<n;i++)
    {
        S[i]=false;
        Path[i]=-1;
        D[i]=MaxInt;
    }
    ArcNode *p=G.vertics[v0].firstarc;
    while(p)
    {
        D[p->adjvex]=p->info;
        Path[p->adjvex]=v0;
        p=p->nextarc;
    }

    S[v0]=true;
    D[v0]=0;

    int v;
    for(int i=1;i<n;i++)
    {
        int min=MaxInt;
        for(int w=0;w<n;w++)
        {
            if(!S[w]&&D[w]<min)
            {
                v=w;
                min=D[w];
            }
        }
        S[v]=true;
        int z=v;
        cout<<G.vertics[v0].data<<"->"<<G.vertics[z].data<<":";
        string str="";
        str+=G.vertics[z].data;
        do
        {
            z=Path[z];
            str+=",";
            str+=G.vertics[z].data;
        }while(z!=v0);
        reverse(str.begin(),str.end());
        cout<<"("<<str<<")"<<D[v]<<endl;

        ArcNode *p=G.vertics[v].firstarc;
        while(p)
        {
            if(!S[p->adjvex]&&(D[v]+p->info<D[p->adjvex]))
            {
                D[p->adjvex]=D[v]+p->info;
                Path[p->adjvex]=v;
            }
            p=p->nextarc;
        }
    }
}

void fun_AM_test()
{
    system("cls");
    AMGraph G;
    CreateUDN_AM(G);
    cout<<"该无向图的邻接矩阵为:"<<endl;
    for(int i=0;i<G.vexnum;i++)
    {
        cout<<"\t"<<G.vexs[i];
    }cout<<endl<<endl;
    for(int i=0;i<G.vexnum;i++)
    {
        cout<<G.vexs[i]<<"\t";
        for(int j=0;j<G.vexnum;j++)
        {
            cout<<G.arcs[i][j]<<"\t";
        }
        cout<<endl<<endl;
    }
    system("pause");
    system("cls");
    int flag=1;
    while(flag)
    {
        cout<<"***********************************************************"<<endl;
        cout<<"**************  1、深度优先遍历无向图        **************"<<endl;
        cout<<"**************  2、广度优先遍历无向图        **************"<<endl;
        cout<<"**************  3、Dijkstra最短路径算法      **************"<<endl;
        cout<<"**************  4、程序退出                  **************"<<endl;
        cout<<"***********************************************************"<<endl;
        int ip;
        cout<<"请输入指令:";
        cin>>ip;
        switch(ip)
        {
        case 1:
            {
                cout<<"请输入起始顶点的下标(下标从1开始):";
                int num;
                cin>>num;
                DFS_AM(G,num-1);cout<<endl;
                for(int i=0;i<G.vexnum;i++)
                {
                    G.visited[i]=false;
                }
                system("pause");
                break;
            }
        case 2:
            {
                cout<<"请输入起始顶点的下标(下标从1开始):";
                int num;
                cin>>num;
                BFS_AM(G,num-1);cout<<endl;
                system("pause");
                break;
            }
        case 3:
            {
                cout<<"请输入起始顶点的下标(下标从1开始):";
                int num;
                cin>>num;
                ShorttestPath_DIJ_AM(G,num-1);
                system("pause");
                break;
            }
        case 4:
            {
                flag=0;
                cout<<"程序退出!";
                Sleep(1000);
            }
        }
        system("cls");
    }
}

void fun_AL_test()
{
    system("cls");
    ALGraph G;
    CreateUDN_AL(G);
    cout<<"该无向图的邻接表为:"<<endl;
    for(int i=0;i<G.vexnum;i++)
    {
        cout<<G.vertics[i].data<<" ";
        ArcNode *p=G.vertics[i].firstarc;
        while(p)
        {
            cout<<G.vertics[p->adjvex].data<<" ";
            p=p->nextarc;

        }
        cout<<endl;
    }
    system("pause");
    system("cls");
    int flag=1;
    while(flag)
    {
        cout<<"***********************************************************"<<endl;
        cout<<"**************  1、深度优先遍历无向图        **************"<<endl;
        cout<<"**************  2、广度优先遍历无向图        **************"<<endl;
        cout<<"**************  3、Dijkstra最短路径算法      **************"<<endl;
        cout<<"**************  4、程序退出                  **************"<<endl;
        cout<<"***********************************************************"<<endl;
        int ip;
        cout<<"请输入指令:";
        cin>>ip;
        switch(ip)
        {
        case 1:
            {
                cout<<"请输入起始顶点的下标(下标从1开始):";
                int num;
                cin>>num;
                DFS_AL(G,num-1);cout<<endl;
                for(int i=0;i<G.vexnum;i++)
                {
                    G.visited[i]=false;
                }
                system("pause");
                break;
            }
        case 2:
            {
                cout<<"请输入起始顶点的下标(下标从1开始):";
                int num;
                cin>>num;
                BFS_AL(G,num-1);cout<<endl;
                system("pause");
                break;
            }
        case 3:
            {
                cout<<"请输入起始顶点的下标(下标从1开始):";
                int num;
                cin>>num;
                ShorttestPath_DIJ_AL(G,num-1);
                system("pause");
                break;
            }
        case 4:
            {
                flag=0;
                cout<<"程序退出!";
                Sleep(1000);
            }
        }
        system("cls");
    }
}

int main()
{
    cout<<"***********************************************************"<<endl;
    cout<<"**************  1、以邻接矩阵方法创建无向图  **************"<<endl;
    cout<<"**************  2、以邻接表方法创建无向图    **************"<<endl;
    cout<<"**************  3、退出                      **************"<<endl;
    cout<<"***********************************************************"<<endl;

    cout<<"选择以哪种方式创建无向图:";
    while(1)
    {
        int ip;

        cin>>ip;
        if(ip==1)
        {
            fun_AM_test();
            break;
        }
        else if(ip==2)
        {
            fun_AL_test();
            break;
        }
        else if(ip==3)
        {
            cout<<"程序退出!"<<endl;
            break;
        }
        else
        {
            cout<<"指令错误,请重新输入:";
        }
    }

    return 0;
}

/*0 2 10 0 4 30 0 5 100
1 2 5
2 3 50
3 5 10
4 3 20 4 5 60*/

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值