迪傑斯特拉算法的C++實現

前言

       最近項目需要有關路徑規劃方面的東西,因此學習了一下有關迪杰特斯拉算法的相關知識。在學習的過程中也看了其他博客的例子。主要參考了最短路徑問題—Dijkstra算法詳解這篇技術博客中的思路與代碼,我在其基礎上進行了修改。

功能

       在已知圖中輸入起點與終點,通過迪傑斯特拉算法找到該起點到終點的最短路徑。

實例與代碼

(1)實例(此處採用的圖仍然是最短路徑問題—Dijkstra算法詳解)中的圖例。
在這裏插入圖片描述
(2)代碼:
dijkstra.h

#pragma once
#include<iostream>
#include<string>
using namespace std;
//記錄起點到每個頂點的最短路徑的信息
struct Dis {
	string path;      //當前路徑
	int value;        
	bool visit;
	Dis() {
		visit = false;
		value = 0;
		path = "";
	}
};

class Graph_DG {
private:
	int vexnum;   //圖的頂點個數
	int edge;     //圖的邊數
	int **arc;    //鄰接矩陣
	//Dis * dis;    //記錄各個頂點最短路徑的信息
public:
	//構造函數
	Graph_DG(int vexnum, int edge);   
	//析構函數
	~Graph_DG();
	// 判斷我們每次輸入的的邊的信息是否合法
	//頂點從1開始編號
	bool check_edge_value(int start, int end, int weight);
	//創建圖
	void createGraph();
	//點對點的迪杰特斯拉算法
	Dis PointToPointDijkstra(int begin,int end);
};

dijkstra.cpp

#include"dijkstra.h"

//構造函數
Graph_DG::Graph_DG(int vexnum, int edge) {
	//初始化頂點數和邊數
	this->vexnum = vexnum;      
	this->edge = edge;
	//爲鄰接矩陣開闢空間和賦初值
	arc = new int*[this->vexnum];
	for (int i = 0; i < this->vexnum; i++) {
		arc[i] = new int[this->vexnum];           //初始化頂點數
		for (int k = 0; k < this->vexnum; k++)    //初始化鄰接矩陣
		{
			//鄰接矩陣初始化爲無窮大
			arc[i][k] = INT_MAX;                 
		}
	}
}
//析構函數
Graph_DG::~Graph_DG() {
	for (int i = 0; i < this->vexnum; i++){
		delete this->arc[i];
	}
	delete arc;
}

// 判斷我們每次輸入的的邊的信息是否合法
//頂點從1開始編號
bool Graph_DG::check_edge_value(int start, int end, int weight)    //主要判斷開始的頂點數與邊的權重
{
	if (start<1 || end<1 || start>vexnum || end>vexnum || weight < 0) {
		return false;
	}
	return true;
}
//創建鄰接矩陣
void Graph_DG::createGraph()      
{
	cout << "請輸入每條邊的起點和終點(頂點編號從1開始)以及其權重" << endl;
	int start;     
	int end;
	int weight;
	int count = 0;
	while (count != this->edge) {
		cin >> start >> end >> weight;      //輸入起點、終點、邊權重
		//首先判斷邊的信息是否合法
		while (!this->check_edge_value(start, end, weight)){
			cout << "輸入的邊的信息不合法,請重新輸入" << endl;
			cin >> start >> end >> weight;     
		}
		//對鄰接矩陣對應上的點賦值
		arc[start - 1][end - 1] = weight;
		//無向圖添加上這行代碼
		//arc[end - 1][start - 1] = weight;
		++count;
	}
}
Dis Graph_DG::PointToPointDijkstra(int begin, int end)
{
	Dis Output;
	Dis *dis;
	dis = new Dis[this->vexnum];
	if (begin == end) {
		Output.path = "當前最短路徑爲0";
		Output.value = 0; 
		cout << "v" << begin << "到" << "v" << end << "的最短路徑爲:" << "v" << begin << "-->v" << end << "。路距爲:" << Output.value << endl;
		delete[]dis;
		return Output;
	}
	else {
		//首先初始化我們的dis數組
		int i;
		for (i = 0; i < this->vexnum; i++)
		{
			//設置當前的路徑
			dis[i].path = "v" + to_string(begin) + "-->v" + to_string(i + 1);     //輸入到各個點的路徑
			dis[i].value = arc[begin - 1][i];                                     //從一點到各個點的距離
		}
		//設置起點的到起點的路徑爲0
		dis[begin - 1].value = 0;
		dis[begin - 1].visit = true;   //從起點到終點的最短距離爲
		int count = 1;
		//計算剩餘的頂點的最短路徑(剩餘this->vexnum-1個頂點)
		while (count != this->vexnum)
		{
			//temp用於保存當前dis數組中最小值的那個下標
			//min記錄的當前的最小值
			int temp = begin - 1;
			int min = INT_MAX;
			for (i = 0; i < this->vexnum; i++)
			{
				if (!dis[i].visit && dis[i].value<min)
				{
					min = dis[i].value;                    //確定出函數中的最小值
					temp = i;                              //當前dis數組中最小值的那個下標
				}
			}
			if (end-1==temp) {
				Output.path = dis[temp].path;
				Output.value = dis[temp].value;
				cout << "v" << begin << "到" << "v" << end << "的最短路徑爲:" << Output.path << "。路距爲:" << Output.value << endl;
				delete[]dis;
				return Output;
			}
			//把temp對應的頂點加入到已經找到的最短路徑的集合中
			dis[temp].visit = true;
			++count;
			for (i = 0; i < this->vexnum; i++){
				//注意這裏的條件arc[temp][i]!=INT_MAX必須加,不然會出現溢出,從而造成程序異常
				if (!dis[i].visit && arc[temp][i] != INT_MAX && (dis[temp].value + arc[temp][i]) < dis[i].value){
					//如果新得到的邊可以影響其他爲訪問的頂點,那就就更新它的最短路徑和長度
					dis[i].value = dis[temp].value + arc[temp][i];
					dis[i].path = dis[temp].path + "-->v" + to_string(i + 1);
				}
			}
		}
		if (dis[end-1].value == INT_MAX){
			Output.path = "無路徑可達";
			Output.value = -1;
			cout << "v" << begin << "到" << "v" << end << "的最短路徑爲:" << Output.path << "。路距爲:" << Output.value << endl;
			delete[]dis;
			return Output;
		}
	}
	
}

main.cpp

#include"Dijkstra.h"
//檢驗輸入邊數和頂點數的值是否有效,可以自己推算爲啥:
//頂點數和邊數的關係是:((Vexnum*(Vexnum - 1)) / 2) < edge
bool check(int Vexnum, int edge) {
	if (Vexnum <= 0 || edge <= 0 || ((Vexnum*(Vexnum - 1)) / 2) < edge)
		return false;
	return true;
}
int main() {
	int vexnum; int edge;
	cout << "輸入圖的頂點個數和邊的條數:" << endl;
	cin >> vexnum >> edge;
	while (!check(vexnum, edge)) {
		cout << "輸入的數值不合法,請重新輸入" << endl;
		cin >> vexnum >> edge;
	}
	Graph_DG graph(vexnum, edge);
	graph.createGraph();
	while (true)
	{
		cout << "//*********************//" << endl;
		cout << "****請輸入起點和終點****" << endl;
		int begin = 0,end = 0;
		cin >> begin >> end;
		graph.PointToPointDijkstra(begin,end);
	}
	system("pause");
	return 0;
}

(3)運行效果
在這裏插入圖片描述
注:
1.路徑不可達的路距默認採用的是-1。
2.本次代碼使用的有向圖的方式。關於無向圖,代碼中已經有所提示。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章