数据结构 最短路径课设(源码+实验报告+视频讲解)(不要钱、用了自取)

news/2024/11/28 20:40:48/

XI`AN TECHNOLOGICAL UNIVERSITY

课程设计报告

实验课程名称   算法与数据结构   

专    业:         

班    级:              

姓    名:               

学    号:         

实验学时:                        

指导教师:                     

成    绩:                        

        

    2023      1  7  日

目录

一、实验报告

        一、绪论

        二、基本要求

        三、信息描述

        五、详细设计

        六、调试与测试:

        八、总结

 源码:

视频上传比较麻烦,需要的同学可以联系我


一、实验报告

一、绪论

迪杰特斯拉算法思想:

设G=(V,E)是一个带权有向图,把顶点集合V分成两组,求出最短路径的顶点集合(用S表示,初始时S中只有一个源点,以后每求得一条最短路径,就将加入到集合S中。直到全部顶点都加入到S中,算法就结束了)。第二组为其余未确定最短路径的顶点集合(用U表示),按最短路径长度的递增次序依次把第二组的顶点加入S中。在加入的过程中,总保持从源点V到S中各顶点的最短路径长度大于从源点V到V中任何顶点的最短路径长度。此外,每个顶点对应一个距离,S中的顶点的距离就是从V到此顶点的最短路径长度,V中的顶点的距离是从V到此顶点只包括S中的顶点为中间顶点的当前最短路径长度。

二、基本要求

(1)设计最短路径,包含以下方面:

1、用邻接矩阵存储一张带权有向图。

2、对图进行从某一源点到其他各顶点的最短路径

3、输出最后结果(路径名称、路径长度)。

三、信息描述

邻接矩阵建立包括:用二维数组存储信息。没有直达路径的为无穷。

用循环来判断最小值。

最终结果用一维数组存储。D[]存放源点到其他顶点的最短路径的长度,P[]存放该顶点最短路径的前驱顶点下标,visit[]为访问标识。初始全部值设为F,先把源点的标识设为T,后面每找到一个源点到其余顶点的最短路径,就将该顶点下标对应的标识置为T。直到全部顶点执行完毕。

输出一维数组D[]和P[],显示最终结果。

  • 总体设计

五、详细设计

  • 第一部分,进行对邻接矩阵的初始化,首先自己到自己的距离肯定为0,然后到其余结点初始化为MAX,然后通过一个for循环,对边进行数据存入,打印函数用来验证。

  • 第二部分对于结点类的创建(构造、拷贝构造、赋值运算符重载、比较方式的重载)类中存放每一个结点的下标、最短路径长度、前驱结点。

  •  第三部分:打印结果函数

  •  迪杰斯特拉算法部分(核心)

完成好邻接矩阵的初始化工作以后,输入我们的起点坐标,对于起点来说,从起点到达起点的距离肯定是0,然后将起点坐标置入优先队列中,进入循环,循环退出条件是优先队列为空

每次取堆顶元素,使用cur进行保存,之后就将此结点pop

利用cur找出所有可以从cur出发到达的所有结点,将这些结点保存到集合S中,对于集合中的所有结点进行:

newlength = node[Index]._length + Graph[Index][back];

// 如果新距离小于cur之前的最小距离,就将cur重新赋值,并入队列

   if (newlength < node[back]._length)

   {

    node[back]._length = newlength;

    node[back]._prev = Index;

    q.push(node[back]);

   }

六、调试与测试:

在我写代码的时候大部分问题都可以查资料解决,如何使用vector,如果使用优先级队列,以及思路的来源也是借助于网上的资料查看,视频讲解,耗费时间最多的应该就是对于自定义类型优先级队列第三个参数比较方式的确定,本来我的代码是这样通过结构体与函数指针来实现,不过也出现了类型不匹配的问题,最后通过使用类中对比较关系的重载写出了bool类型关于>符号的重载(因为要建大堆)。

七、程序清单和执行结果:清单中应有足够的注释

运行结果:

源码:

//(1)设计最短路径,包含以下方面:

//1、用邻接矩阵存储一张带权有向图。

//2、对图进行从某一源点到其他各顶点的最短路径

//了、输出最后结果(路径名称、路径长度)。

//三、信息描述

//邻接矩阵建立包括 : 用二维数组存储信息。没有直达路径的为无

//

//用循环来判断最小值

//最终结果用一维数组存储。D[]存放源点到其他顶点的最短路径的

//长度,P[]存放该顶点最短路径的前驱顶点下标

// 0 1 2   0 4 10  1 2 3  1 4 7  2 0 4  2 3 4  3 4 5  4 2 3

#include<functional>

#include<stdlib.h>

#include<iostream>

using namespace std;

#include<vector>

#include<queue>

#define MAX 1000 // 不可到达

int V, E, S; // 顶点数、边数、起点

vector<vector<int>> Graph;

void CreatMyGraph() // 初始化邻接矩阵

{

    cout << "请输入顶点数、边数" << endl;

    cin >> V >> E;

    Graph.resize(V);

    for (int i = 0; i < V; i++)

    {

        Graph[i].resize(V);

        for (int j = 0; j < V; j++)

        {

            if (i == j)

                Graph[i][j] = 0; // 自己到自己赋值为0

            else

                Graph[i][j] = MAX;   // 默认初始化到其余顶点均为MAX

        }

    }

    /*Graph[0][1] = 2;

    Graph[0][3] = 1;

    Graph[1][3] = 3;

    Graph[1][4] = 7;

    Graph[2][0] = 4;

    Graph[3][2] = 2;

    Graph[3][4] = 2;

    Graph[3][5] = 8;

    Graph[3][6] = 4;

    Graph[4][6] = 1;

    Graph[6][5] = 1;

    Graph[2][5] = 5;*/

    int begin, end;

    int length;

    for (int i = 0; i < E; i++)

    {

        cout << "请输入第" << i + 1 << "条边的起点、终点、权值:" << endl;

        cin >> begin >> end >> length;

        Graph[begin][end] = length;   // 初始化邻接矩阵

    }

}

void PrintMyGraph()

{

    cout << "图的邻接矩阵存储为:" << endl;

    for (int i = 0; i < V; i++)

    {

        for (int j = 0; j < V; j++)

        {

            cout << Graph[i][j] << " ";

        }

        cout << endl;

    }

}

//typedef struct DjNode

//{

//  int _index;

//  int _length;

//  int _prev;

//}Node;

//Node BuyNode(int index, int length)

//{

//  Node* newnode = (Node*)malloc(sizeof(Node));

//  newnode->_index = index;

//  newnode->_length = length;

//  newnode->_prev = 0;

//  return newnode;

//}

//typedef bool (*PCOM)(const Node& left, const Node& right);

//bool Compare(const Node left, const Node right)

//{

//  return left._length > right._length;

//}

class Node

{

public:

    Node(int index, int length, int prev)

        : _index(index)

        , _length(length)

        , _prev(prev)

    {}

    Node(const Node& d)

    {

        _index = d._index;

        _length = d._length;

        _prev = d._prev;

    }

    Node& operator=(const Node& node)

    {

        if (this != &node)

        {

            _index = node._index;

            _length = node._length;

            _prev = node._prev;

        }

        return *this;

    }

    bool operator>(const Node& d)const

    {

        return _length > d._length;

    }

    bool operator<(const Node& d)const

    {

        return _length < d._length;

    }

    int _index;

    int _length;

    int _prev;

};

class Com

{

public:

    bool operator()(const Node&left, const Node&right)const

    {

        return left._length > right._length;

    }

};

void Print_output(int start, vector<Node> node)

{

    cout << "由" << start << "到其余各顶点距离分别为" << endl;

    for (int i = 0; i < V; i++)

    {

        if (i == start)

            continue;

        else

            cout << start << "->" << i << ": " << node[i]._length << endl;

    }

}

void Dijkstra_Algorithm()

{

    // 1、初始化输出数组D、P

    //vector<int> D(V, MAX);  // 初始化最短长度数组D

    //vector<int> P(V, 0); // 初始化前驱结点数组P

    vector<Node> node(V, Node(0,0,0));

    for (int i = 0; i < V; i++)

    {

        //node[i] = BuyNode(i, MAX); // 结点初始化

        node[i]._index = i;

        node[i]._length = MAX;

        node[i]._prev = 0;

    }

    // 2、初始化顶点D[S]

    cout << "请输入起点" << endl;

    cin >> S;

    node[S]._length = 0;

    // 3、创建优先队列,起点元素入队列

    priority_queue<Node, vector<Node>, greater<Node>> q;

    q.push(node[S]);

    while (!q.empty())

    {

        Node cur = q.top();

        q.pop(); // 取出堆顶元素并进行保存

        vector<int> pre_next;

        int Index = cur._index;

        for (int i = 0; i < V; i++) // 将所有可以一步到达当前结点的元素下标全部保存到pre_next中

        {

            if (Graph[Index][i] > 0 && Graph[Index][i] != MAX)

                pre_next.push_back(i);

        }

        while (!pre_next.empty()) // 对于每一个可以到达cur的结点

        {

            int back = pre_next.back();   //访问一个取出一个

            pre_next.pop_back();

            // 新距离就为 从源点到back距离  加上  back到cur的距离

            int newlength = node[Index]._length + Graph[Index][back];

            // 如果新距离小于cur之前的最小距离,就将cur重新赋值,并入队列

            if (newlength < node[back]._length)

            {

                node[back]._length = newlength;

                node[back]._prev = Index;

                q.push(node[back]);

            }

        }

    }

    cout << endl;

    Print_output(S, node);

}

void _Dijkstra_Algorithm()

{

    cout << "Dijkstra_Algorithm :" << endl;

    int choice;

    while (1)

    {

        cout << "请输入:" << "[1]开始" << "[0]结束" << endl;

        cin >> choice;

        switch (choice)

        {

        case 1:

            Dijkstra_Algorithm();

            break;

        case 0:

            exit(0);

            break;

        }

    }

}

int main()

{

    int choice;

    while (1)

    {

        cout << "*******************************************" << endl;

        cout << "***************请输入请求:****************" << endl;

        cout << "***************[1]初始化数据***************" << endl;

        cout << "***************[2]迪杰斯特拉算法***********" << endl;

        cout << "***************[0]退出*********************" << endl;

        cout << "*******************************************" << endl;

        cin >> choice;

        switch (choice)

        {

        case 1:

            CreatMyGraph();

            break;

        case 2:

            _Dijkstra_Algorithm();

            break;

        case 0:

            exit(0);

            break;

        default:

            cout << "输入错误,请重新输入" << endl;

            break;

        }

    }

    return 0;

}

八、总结

通过这次课设,进一步提高了对于数据结构的认知,提升了自己的编程能力,了解了迪杰斯特拉算法在使用优先级队列来解决问题的便利之处。

 源码:

//(1)设计最短路径,包含以下方面:
//1、用邻接矩阵存储一张带权有向图。
//2、对图进行从某一源点到其他各顶点的最短路径
//了、输出最后结果(路径名称、路径长度)。
//三、信息描述
//邻接矩阵建立包括 : 用二维数组存储信息。没有直达路径的为无
//穷
//用循环来判断最小值
//最终结果用一维数组存储。D[]存放源点到其他顶点的最短路径的
//长度,P[]存放该顶点最短路径的前驱顶点下标
// 0 1 2   0 4 10  1 2 3  1 4 7  2 0 4  2 3 4  3 4 5  4 2 3
#include<functional>
#include<stdlib.h>
#include<iostream>
using namespace std;
#include<vector>
#include<queue>
#define MAX 1000 // 不可到达
int V, E, S; // 顶点数、边数、起点vector<vector<int>> Graph;void CreatMyGraph() // 初始化邻接矩阵
{cout << "请输入顶点数、边数" << endl;cin >> V >> E;Graph.resize(V);for (int i = 0; i < V; i++){Graph[i].resize(V);for (int j = 0; j < V; j++){if (i == j)Graph[i][j] = 0;	// 自己到自己赋值为0elseGraph[i][j] = MAX;	// 默认初始化到其余顶点均为MAX}}/*Graph[0][1] = 2;Graph[0][3] = 1;Graph[1][3] = 3;Graph[1][4] = 7;Graph[2][0] = 4;Graph[3][2] = 2;Graph[3][4] = 2;Graph[3][5] = 8;Graph[3][6] = 4;Graph[4][6] = 1;Graph[6][5] = 1;Graph[2][5] = 5;*/int begin, end;int	length;for (int i = 0; i < E; i++){cout << "请输入第" << i + 1 << "条边的起点、终点、权值:" << endl;cin >> begin >> end >> length;Graph[begin][end] = length;	// 初始化邻接矩阵}
}void PrintMyGraph()
{cout << "图的邻接矩阵存储为:" << endl;for (int i = 0; i < V; i++){for (int j = 0; j < V; j++){cout << Graph[i][j] << " ";}cout << endl;}
}//typedef struct DjNode
//{
//	int _index;
//	int _length;
//	int _prev;
//}Node;//Node BuyNode(int index, int length)
//{
//	Node* newnode = (Node*)malloc(sizeof(Node));
//	newnode->_index = index;
//	newnode->_length = length;
//	newnode->_prev = 0;
//	return newnode;
//}//typedef bool (*PCOM)(const Node& left, const Node& right);
//bool Compare(const Node left, const Node right)
//{
//	return left._length > right._length;
//}class Node
{
public:Node(int index, int length, int prev): _index(index), _length(length), _prev(prev){}Node(const Node& d){_index = d._index;_length = d._length;_prev = d._prev;}Node& operator=(const Node& node){if (this != &node){_index = node._index;_length = node._length;_prev = node._prev;}return *this;}bool operator>(const Node& d)const{return _length > d._length;}bool operator<(const Node& d)const{return _length < d._length;}int _index;int _length;int _prev;
};class Com
{
public:bool operator()(const Node&left, const Node&right)const{return left._length > right._length;}
};void Print_output(int start, vector<Node> node)
{cout << "由" << start << "到其余各顶点距离分别为" << endl;for (int i = 0; i < V; i++){if (i == start)continue;elsecout << start << "->" << i << ": " << node[i]._length << endl;}
}void Dijkstra_Algorithm()
{// 1、初始化输出数组D、P//vector<int> D(V, MAX);	// 初始化最短长度数组D//vector<int> P(V, 0);	// 初始化前驱结点数组Pvector<Node> node(V, Node(0,0,0));for (int i = 0; i < V; i++){//node[i] = BuyNode(i, MAX); // 结点初始化node[i]._index = i;node[i]._length = MAX;node[i]._prev = 0;}// 2、初始化顶点D[S]cout << "请输入起点" << endl;cin >> S;node[S]._length = 0;// 3、创建优先队列,起点元素入队列priority_queue<Node, vector<Node>, greater<Node>> q; q.push(node[S]);while (!q.empty()){Node cur = q.top();q.pop(); // 取出堆顶元素并进行保存vector<int> pre_next;int Index = cur._index;for (int i = 0; i < V; i++) // 将所有可以一步到达当前结点的元素下标全部保存到pre_next中{if (Graph[Index][i] > 0 && Graph[Index][i] != MAX)pre_next.push_back(i);}while (!pre_next.empty())	// 对于每一个可以到达cur的结点{int back = pre_next.back();	//访问一个取出一个pre_next.pop_back();// 新距离就为 从源点到back距离  加上  back到cur的距离int newlength = node[Index]._length + Graph[Index][back];// 如果新距离小于cur之前的最小距离,就将cur重新赋值,并入队列if (newlength < node[back]._length){node[back]._length = newlength;node[back]._prev = Index;q.push(node[back]);}}}cout << endl;Print_output(S, node);
}void _Dijkstra_Algorithm()
{cout << "Dijkstra_Algorithm :" << endl;int choice;while (1){cout << "请输入:" << "[1]开始" << "[0]结束" << endl;cin >> choice;switch (choice){case 1:Dijkstra_Algorithm();break;case 0:exit(0);break;}}
}int main()
{int choice;while (1){cout << "*******************************************" << endl;cout << "***************请输入请求:****************" << endl;cout << "***************[1]初始化数据***************" << endl;cout << "***************[2]迪杰斯特拉算法***********" << endl;cout << "***************[0]退出*********************" << endl;cout << "*******************************************" << endl;cin >> choice;switch (choice){case 1:CreatMyGraph();break;case 2:_Dijkstra_Algorithm();break;case 0:exit(0);break;default:cout << "输入错误,请重新输入" << endl;break;}}return 0;
}


http://www.ppmy.cn/news/19019.html

相关文章

Ubuntu显示优化 动画

之前从win转到了ubuntu。老大哥问我为啥不直接用Mac。我笑笑没说话。其实就一个字&#xff0c;穷。 使用Ubuntu的过程中有一点小问题&#xff0c;不过平时我主要用来编程&#xff0c;对壁纸&#xff0c;过渡动画这些东西其实并不是很在乎。直到我审美感爆棚的妻子告诉我&#…

【题解】2023牛客寒假算法基础集训营2

目录A. Tokitsukaze and abn (easy)思路B. Tokitsukaze and abn (medium)思路Tokitsukaze and abn (hard)思路D. Tokitsukaze and Energy Tree思路bfsdfsE. Tokitsukaze and Energy Tree思维F. Tokitsukaze and Gold Coins (easy)思路G. Tokitsukaze and Gold Coins (hard)H. T…

为什么会有右值引用?(移动构造、移动赋值)

目录 1、左值引用的缺陷 2、移动构造&#xff1a;解决临时对象的深拷贝 3、拓展&#xff1a;移动赋值 1、左值引用的缺陷 左值引用作为函数参数传递&#xff0c;减少了参数拷贝&#xff1b;但是作为函数返回值&#xff0c;并不适用于所有场景&#xff0c;比如要返回一个临…

使用 Grafana 请求API接口

目的: 使用Grafana 配合JSON API 插件 请求API接口,完成可视化,实现一些简单的请求功能 假设我们想将如下的API接口返回的json数据可视化 这里借用一下 小熊同学的 金融数据接口 用请求如下接口举例 https://api.doctorxiong.club/v1/fund/detail?code000001&startDat…

树莓派配置Python虚拟环境、安装PyQt5、安装PySide2

要从头设置好一台可用于开发的树莓派&#xff0c;可以参考树莓派 4B 无屏幕&#xff0c;连接WiFi、SSH、VNC&#xff0c;系统换源、pip换源&#xff0c;安装中文输入法 Python虚拟环境 树莓派&#xff08;或者说arm平台&#xff09;使用Python虚拟环境的正确方式是使用pipenv…

网关超详解

文章目录网关详解一、Spring Cloud Gateway用法二、实现三、网关的分类四、什么是网关五、网关的作用路由负载均衡统一鉴权统一处理跨域统一业务处理访问控制发布控制流量染色接口保护统一日志统一文档网关详解 一、Spring Cloud Gateway用法 去看官网&#xff1a;https://sp…

casbin权限和配置文件的理解

官方文档 基础权限模型 下图为我基于个人理解画出来的(关于多租户RBAC模型可能有误) 发现一篇博客讲的还行Casbin权限模型&#xff0c;看他的权限系统设计模型分析部分 casbin配置文件内容的结构解释 注意matchers可以设置多个。我在知道这个之前一直疑惑为什么需要policy_…

Sprig框架集成(SSM框架) | Sping+SpringMVC+Mybatis

SSM框架 SSM是spingspringMVCmybatis集成的框架&#xff1a;标准的MVC模式&#xff0c;整个系统划分为表现层&#xff0c;controller层&#xff0c;service层&#xff0c;DAO层四层 Spring&#xff08;业务层&#xff09; Spring就像是整个项目中装配bean的大工厂&#xff0c;在…