最短路径 Dijkstra算法

来源:互联网 发布:软件服务商 编辑:程序博客网 时间:2024/06/16 19:16

斗争了整整三天,终于实现了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;}
0 0