最短路径 Dijkstra算法

本文详细介绍了使用C++实现Dijkstra算法的过程,结合BFS与DFS对图进行操作。通过具体测试案例展示了算法的应用,并附有代码与测试结果。代码质量有待提高,未来计划进行完善。

斗争了整整三天,终于实现了Dijkstra算法的第一个版本。
这次是用C++实现的,顺道集成了BFS与DFS。
这次的代码质量不高,就只发发代码和测试结果得了,下次完善代码之后,写一个篇专门的博文发上来

以下是测试
测试用图1:这里写图片描述
测试结果1:这里写图片描述
测试用图2:这里写图片描述
测试结果2:这里写图片描述

接下来是代码
注释太多了,凑活着看吧

/*
名称:图的最短路径---Dijkstra算法的实现与应用
描述:主体写为类的形式,基本数据成员设定为private权限,而相关的成员函数设定为public权限
主要的成员函数有:图的构造函数(用于图的初始化,输入基本信息,初始化邻接矩阵)、图的矩阵的打印、DFS、BFS、Dijkstra算法、以及一些相应的辅助函数
其中BFS需要的队列的及函出队入队数单独写作一个类
*/
#include<iostream>
#include<string>
using namespace std;
#define MAX 100 //定义最大顶点数
int Infinite=2000000000;//定义无限 用于描述不连同的边
typedef int Vertex;  //用整型描述顶点
typedef int Edge;  //用整型描述边
enum GrapheType{ DG, UDG, DN, UDN };//用于描述图的种类 有向图/无向图 有向网/无向网,本例默认研究有向的连通图

//队列类,在图的BFS中会用到
class Queue//这是一个不循环的队列
{
public:
    Vertex array[MAX];
    Vertex Front, Last;
//public:
    Queue()
    {
        Front = 0;
        Last = 0;
    }
    ~Queue(){};
    //入队函数
    void In_Queue(Vertex Item)
    {
        if (Last != MAX)
            array[Last++] = Item;
        else
            cout << "队列已满" << endl;
    }
    //出队函数
    int De_Queue()
    {
        if (Front != Last)
            return array[Front++];
        else
            cout << "队列为空" << endl;
    }
    //判断队列是否为空
    bool Is_Empty()
    {
        if (Front == Last)
            return true;
        else
            return false;
    }
};

//visited用于记录节点是否被访问
int visited[MAX];

//重置访问结果
void Re_set()
{
    for (int i = 0; i < MAX; i++)
        visited[i] = 0;
}

//图类
class MapGraphe      
{
private:
    int Number_of_Vertex;     //顶点的数量
    int Number_of_Edges;     //边的数量
    Vertex Vertices[MAX];     //用于记录顶点
    Edge Edges[MAX][MAX];//用于记录顶点互相之间的边的情况
    GrapheType Type;    //用于描述图的类型
public:
    //创建并初始化整个图
    void Creat_Map()
    {
        cout << "输入顶点的数量(所有的顶点默认从0开始编号)" << endl;;//先输入顶点的信息
        cin >> Number_of_Vertex;
        for (int i = 0; i < Number_of_Vertex; i++)
        {
            Vertices[i] = i;
        }
        for (int i = 0; i < Number_of_Vertex; i++)//初始化邻接矩阵
        for (int j = 0; j < Number_of_Vertex; j++)
        {
            if (i == j)//对角线的上表示顶点,用零表示
                Edges[i][j] = 0;
            else
                Edges[i][j] = Infinite;//初始化默认没有边连通
        }

        cout << "输入边的总数" << endl;//再输入边的信息
        cin >> Number_of_Edges;
        cout << "输入时按照以下格式:起点 终点 路径长度(请正确输入,错了我可不知道会发生什么)" << endl;
        for (int i = 0; i < Number_of_Edges; i++)
        {
            int start, end, cost;
            cin >> start >> end >> cost;
            Edges[start][end] = cost;//代表start-->end这条路径的长度是cost,而end-->start默认是infinite,即不连通的
        }
    }

    //图的矩阵的打印
    void Matrix()
    {
        for (int i = 0; i < Number_of_Vertex; i++)
        {
            cout << endl;
            for (int j = 0; j < Number_of_Vertex; j++)
            {
                if (Edges[i][j] == Infinite)
                    cout << 'U' << " ";
                else
                cout<<Edges[i][j] << " ";
            }
        }
    }

    //DFS
    void Depth_First_Search(Vertex Vertex_name)
    {
        int i;
        for (i = 0; i < Number_of_Vertex; i++)//先查找传入的节点是否存在
        {
            if (Vertex_name == Vertices[i])//存在则直接break
                break;
        }
        if (i == Number_of_Vertex)//不存在则return
        {
            cout << "没有找到该顶点" << endl;
            return;
        }

        visited[Vertex_name] = 1;
        cout <<Vertex_name<< " ";//找到该顶点后输出该顶点
        for (i = 0; i < Number_of_Vertex; i++)
        {
            if (i == Vertex_name)
                continue;
            if (Edges[Vertex_name][i] != Infinite)
            {
                if ( visited[i]==0 )//递归遍历与之连同且未被访问过的点
                Depth_First_Search(i);
            }
        }
    }

    //BFS
    void Breadth_First_Serach(Vertex Vertex_name)
    {
        int i;
        for (i = 0; i < Number_of_Vertex; i++)//先查找传入的节点是否存在
        {
            if (Vertex_name == Vertices[i])//存在则直接break
                break;
        }
        if (i == Number_of_Vertex)//不存在则return
        {
            cout << "没有找到该顶点" << endl;
            return;
        }

        Queue queue;//创建队列
        queue.In_Queue(Vertex_name);//将第一个顶点入队
        while (!queue.Is_Empty())
        {
            int De_Queue_Item = queue.De_Queue();//将最前面的节点出队,打印并查找与之相连的顶点
            if (visited[De_Queue_Item] == 1)//如果出队的节点已经访问过,进入下一次循环,再次出队元素
                continue;
            cout << De_Queue_Item << " ";
            visited[De_Queue_Item] = 1;//访问过后,将之设置为已访问的状态
            for (i = 0; i < Number_of_Vertex; i++)
            {
                if (i == De_Queue_Item )
                    continue;
                if (Edges[De_Queue_Item][i] != Infinite)
                    queue.In_Queue(i);
            }
        } 
    }

    //(辅助函数) Judge_Dijkstra : 判断是否全部顶点求出距离
    bool Judge_Dijkstra(Vertex U[])
    {
        int Invaild = -1;//查找非无效点来判断是否完全被纳入
        for (int i = 0; i < Number_of_Vertex; i++)
        {
            if (U[i] != Invaild )//表示如果U中还有除出发点以外的任何顶点存在,则继续迭代
                return 1;
        }
        return 0;//表示所有顶点已被纳入
    }

    //(辅助函数) Find_Min : 找到集合中最小元素的
    int Find_Min(Vertex U[])
    {
        int Min = Infinite;
        for (int i = 0; i < Number_of_Vertex; i++)
        {
            if (U[i] < Min && U[i]>0)
            {
                Min = U[i];
            }
        }
        return Min;
    }

    //(辅助函数) Find_Index_of_Min : 找到集合中最小元素在数组中的下标
    int Find_Index_of_Min(Vertex U[],Vertex Min)
    {
        for (int i = 0; i < Number_of_Vertex; i++)
        {
            if (U[i] == Min)
                return i;
        }
    }

    //Dijkstra
    void Dijkstra(Vertex First_Vertex)
    {
        int Invaild = -1;//用于描述U中的以加入S的无效顶点
        Vertex temp_Vertex = First_Vertex;//每次迭代用的点
        Vertex S[MAX];//S代表已查找到指定顶点的最短路径的集合
        Vertex U[MAX];//U代表尚未纳入集合的点
        for (int i = 0; i < Number_of_Vertex; i++)
        {
            U[i] = Infinite;//初始化两个集合,默认除出发点以外的所有顶点都未被纳入集合
            S[i] = Infinite;//默认所有顶点的距离都未被确定
        }
        S[First_Vertex] = 0;//初始顶点到自己的距离为0
        U[First_Vertex] = Invaild;//初始顶点在U中是无效点

        do//一旦有顶点未被纳入,就继续迭代
        {
            for (int i = 0; i < Number_of_Edges; i++)
            {
                if (temp_Vertex == i)//不能与自身比较,跳过
                    continue;
                if (Edges[temp_Vertex][i] != Infinite)//找到可以连接的点
                if (U[i]>Edges[temp_Vertex][i] + S[temp_Vertex])//如果这个顶点的距离比原来U中小,则更新
                    U[i] = Edges[temp_Vertex][i] + S[temp_Vertex];
            }
            Vertex Min = Find_Min(U);//找到集合中最小的元素
            Vertex Index_of_Min = Find_Index_of_Min(U, Min);//找到集合中最小的元素在数组中的下标
            S[Index_of_Min] = Min;//将找到最小元素加入集合中
            U[Index_of_Min] = Invaild;//将这个顶点从U中删除掉

            temp_Vertex = Index_of_Min;//以被删除的顶点进行考虑,更新到其它点的距离

            for (int i = 0; i < Number_of_Vertex; i++)//新加入顶点之后,对到其它顶点的距离进行更新
            {
                if (S[i]==0 && S[i]==Infinite)//跳过出发点和已经纳入S的点
                    continue;
                if (S[i] == Infinite)//并且这个节点并未纳入到S中
                {
                    int Path_length = Edges[Index_of_Min][i] + S[Index_of_Min];//计算出其距离出发点的距离
                    if (Path_length < U[i])//如果这个距离小于原本的连同距离,则更新
                        U[i]=Path_length;
                }
            }

        } while (Judge_Dijkstra(U));

        //结束之后输出各点到出发点的最短距离
        for (int i = 0; i < Number_of_Vertex; i++)
        {
            cout << "顶点标号" << i << "到顶点的距离" << S[i] << endl;
        }
    }
};

//一个输入提示菜单
void list()
{
    cout << "\n1.打印矩阵  "<< "2.DFS  " << "3.BFS  " <<"4.求最短路径 " <<"5.退出 :";
}
int main()
{
    int i=0,j;
    MapGraphe Map;
    Map.Creat_Map();
    while (i != 4)
    {
        list();
        cin >> i;
        switch (i)
        {
            case 1: Map.Matrix(); break;
            case 2: cout << "输入DFS的第一个顶点:"; cin >> j; Map.Depth_First_Search(j); Re_set(); break;
            case 3: cout << "输入BFS的第一个顶点:"; cin >> j; Map.Breadth_First_Serach(j); Re_set(); break;
            case 4:cout << "输入出发点的标号:"; cin >> j; Map.Dijkstra(j); continue; break;
            case 5:return 0;break;
            default:continue;break;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值