【数据结构与算法】 有向图的最短路径实现

Goal: Practice the algorithms of shortest pathproblem.

Task:用一个有向图表示给定的n个(要求至少10个)城市(或校园中的一些地点)及其之间的道路、距离情况,道路是有方向的。要求完成功能:根据用户输入的任意两个城市,给出这两个城市之间的最短距离及其路径。

    要求使用真实地点及其位置,可以使用百度地图获得各点坐标,或者获取可达的两点间距离。

采用Dijkstra算法

Dijkstra算法是由荷兰计算机科学家艾兹格·迪科斯彻发现的。算法解决的是有向图中最短路径问题。

举例来说,如果图中的顶点表示城市,而边上的权重表示著城市间开车行经的距离。 Dijkstra算法可以用来找到两个城市之间的最短路径。

Dijkstra算法的输入包含了一个有权重的有向图G,以及G中的一个来源顶点S。 我们以V表示G中所有顶点的集合。图中的每一个边,都是两个顶点所形成的有序元素对。(u,v)表示从顶点uv有路径相连。 假设E为所有边的集合,而边的权重则由权重函数wE → [0, ∞]定义。 因此,w(u,v)就是从顶点u到顶点v的非负花费值(cost)。 边的花费可以想像成两个顶点之间的距离。任两点间路径的花费值,就是该路径上所有边的花费值总和。 已知有V中有顶点st,Dijkstra算法可以找到st的最低花费路径(i.e. 最短路径)。 这个算法也可以在一个图中,找到从一个顶点s到任何其他顶点的最短路径。

采用不同颜色标注配图路线防止混淆

想到了离散数学的哈密顿图


 

#include <iostream>
#include <windows.h>
#include <stdlib.h>
#include <conio.h>
using namespace std;


int arrow(int up,int down);
void title();
void gotoxy(int xpos, int ypos);
void frontPage();
int main();
void search_path();
void quit();
void find_the_path(const int start, const int dest, int& shortest, int * path);
int minVertex(int* D);
void print_path(int * path, int dest, int start);

class Graph
{
public:
virtual int verNum() = 0;
virtual int edgNum() = 0;
virtual int firstNghbr(int v) = 0;
virtual int nextNghbr(int v1, int v2) = 0;
virtual void setEdge(int v1, int v2, int wgt) = 0;
virtual void delEdge(int v1, int v2) = 0;
virtual int weight(int v1, int v2) = 0;
virtual int getMark(int v) = 0;
virtual void setMark(int v, int val) = 0;
};




class Graphm : public Graph
{
private:
int numVertex, numEdge;
int **matrix;
int *mark;


public:
Graphm()
{}
Graphm(int numVert)   //声明一张图(用邻接矩阵方法实现)
{
int i,j;
numVertex = numVert;
numEdge = 0;
mark = new int[numVert];
for(i=0; i<numVertex; i++)
mark[i] = 0;   //初始化各点访问情况为0,即未访问
matrix = (int**) new int*[numVertex];
for(i=0; i<numVert; i++)
matrix[i] = new int[numVertex];
for(i=0; i<numVertex; i++)
for(j=0; j<numVertex; j++)
matrix[i][j] = 0;      //权为0表示两点间没有边连接
}


~Graphm()
{
delete [] mark;
int i;
for(i=0; i<numVertex; i++)
delete [] matrix[i];
delete [] matrix;
}


int verNum()
{
return numVertex;
}


int edgNum()
{
return numEdge;
}


int firstNghbr(int v)
{
int i;
for(i=0; i<numVertex; i++)
if(matrix[v][i] != 0)
return i;
return i;           //若无第一个邻接结点返回节点数
}


int nextNghbr(int v1, int v2)
{
int i;
for(i=v2+1; i<numVertex; i++)
if(matrix[v1][i] != 0)
return i;
return i;
}


void setEdge(int v1, int v2, int wgt)
{
if(matrix[v1][v2] == 0)
numEdge++;
matrix[v1][v2] = wgt;
}


void delEdge(int v1, int v2)
{
if(matrix[v1][v2] != 0)
numEdge--;
matrix[v1][v2] = 0;
}


int weight(int v1, int v2)
{
return matrix[v1][v2];
}


int getMark(int v)
{
return mark[v];
}


void setMark(int v, int val)
{
mark[v] = val;
}
};






class City
{
private:
int id;
char * cityName;
public:
City()
{}
City(int newId, char* newName)
{
id = newId;
cityName = newName;
}


char* getCityName()
{
return cityName;
}
};


City* cityDB = new City[10];  //声明十个城市
Graphm cityGraph = Graphm(10); //声明城市间火车路线图






void gotoxy(int xpos, int ypos)
{
  COORD scrn;   


  HANDLE hOuput = GetStdHandle(STD_OUTPUT_HANDLE);


  scrn.X = xpos; scrn.Y = ypos;


  SetConsoleCursorPosition(hOuput,scrn);
}






void title()
{
gotoxy(0,0);


cout<<"**********************************************************************"<<endl; 
cout<<endl;
cout<<"                 欢迎使用城市间最短里程路径查询程序    "<<endl;
cout<<endl;
cout<<"**********************************************************************"<<endl;

}






int arrow(int up,int down)
{
int i,j,c;


gotoxy(20,up);
j=up;
cout<<"-->";


for(i=0;i<10000;i++)
{
if(j>down)
{
gotoxy(20,j);
cout<<"   ";
j=up;
gotoxy(20,j);
cout<<"-->";
}


if(j<up)
{
gotoxy(20,j);
cout<<"   ";
j=down;
gotoxy(20,j);
cout<<"-->";
}


c=getch();
if(c==10 || c==13)
break;
if(c==224)
{
c=getch();
if(c == 80)
{
gotoxy(20,j+1);
cout<<"-->";
gotoxy(20,j);
cout<<"   ";
j++;
}
if(c == 72)
{
gotoxy(20,j-1);
cout<<"-->";
gotoxy(20,j);
cout<<"   ";
j--;
}
}
}
return j;


}       //光标移动选择功能 








void frontPage()
{
system("cls");
title();


    cout<<endl;
cout<<endl;
cout<<endl;
cout<<endl;


cout<<"                 请上下键选择操作:\n"<<endl;
cout<<endl;
cout<<endl;
cout<<"                       查询城市间最短里程路径 "<<endl;
cout<<"                       退出程序 "<<endl;


int j = arrow(13,14);


system("cls");


switch (j)
{
case 13:search_path();break;
case 14:quit();break;
}

}


void quit()
{
system("cls");
exit(0);
}








void search_path()
{
title();


cout<<endl;


int start=11, dest=11;
char start1,dest1;

cout<<"本程序存储有以下十个城市的线路信息,请输入其中任意两个城市ID获取之间最短路径: "<<endl;
cout<<endl;
cout<<"         0.北京     1.天津     2.上海     3.武汉     4.广州"<<endl;
cout<<"         5.南京     6.重庆     7.成都     8.西安     9.郑州"<<endl;
cout<<endl;
cout<<"提示:若输入的ID不在[0,9]范围内或两次输入同样的ID,输入界面会刷新等待重新输入";


while(start<0||start>=10||dest<0||dest>=10||start==dest)
{
gotoxy(17,13);
cout<<"输入出发城市ID:         ";
gotoxy(17,14);
cout<<"输入目的城市ID:         ";
gotoxy(33,13);
cin>>start1;

start=int(start1);
   if(start1=='0')
start=10;
else if(start1=='1')
start=1;
else if(start1=='2')
start=2;
else if(start1=='3')
start=3;
else if(start1=='4')
start=4;
else if(start1=='5')
start=5;
else if(start1=='6')
start=6;
else if(start1=='7')
start=7;
else if(start1=='8')
start=8;
else if(start1=='9')
start=9;
gotoxy(33,14);
cin>>dest1;
dest=int(dest1);
    if(dest1=='0')
dest=10;
else if(dest1=='1')
dest=1;
else if(dest1=='2')
dest=2;
else if(dest1=='3')
dest=3;
else if(dest1=='4')
dest=4;
else if(dest1=='5')
dest=5;
else if(dest1=='6')
dest=6;
else if(dest1=='7')
dest=7;
else if(dest1=='8')
dest=8;
else if(dest1=='9')
dest=9;
}


int shortest = 100000;  //保存最短距离
int path[10];  //保存最短路径
int i;
for(i=0;i<10;i++)
path[i] = 11;
find_the_path(start,dest,shortest,path);
cout<<endl;
cout<<cityDB[start].getCityName()<<" 到 "<<cityDB[dest].getCityName()<<" 的最短里程为 "<<shortest<<" 公里, 路径为:"<<endl;
cout<<cityDB[start].getCityName()<<"-->";
print_path(path,dest,start);
cout<<cityDB[dest].getCityName()<<endl;
cout<<endl;
cout<<"按任意键返回主界面"<<endl;
system("pause");
for(i=0;i<10;i++)
cityGraph.setMark(i,0);   //重置访问标记
frontPage();
}






void print_path(int * path, int dest, int start)
{
int k;
k = path[dest];
if(k == start)
return;
print_path(path,k,start);
cout<<cityDB[k].getCityName()<<"-->";
}






void find_the_path(const int start, const int dest, int& shortest, int * path)  //Dijkstra算法应用
{
int D[10];   //存储设置的源城市到任意城市的估计最小长度
int i,v,w;


for(i=0; i<10; i++)
{
D[i] = 100000;
path[i] = -1;
}
D[start] = 0;
// path[start] = 0;
for(i=0; i<cityGraph.verNum(); i++)
{
v=minVertex(D);
if(D[v] == 100000)
return;
cityGraph.setMark(v,1);
for(w=cityGraph.firstNghbr(v); w<cityGraph.verNum(); w=cityGraph.nextNghbr(v,w))
{
if(D[w]>(D[v]+cityGraph.weight(v,w)))
{
D[w] = D[v] + cityGraph.weight(v,w);
path[w] = v;
}
}
}


shortest = D[dest];
}


int minVertex(int* D)
{
int i,v;
for(i=0; i<cityGraph.verNum(); i++)
{
if(cityGraph.getMark(i) == 0)
{
v = i;
break;
}
}
for(i++; i<cityGraph.verNum(); i++)
if((cityGraph.getMark(i) == 0) && (D[i] < D[v]))
v = i;
return v;
}


int main()
{
system("mode con cols=70 lines=23");
char c[20]="color 7f";     
    system(c);       //对cmd窗口显示的调整变化(美化)
       
cityDB[0] = City(0,"北京");
cityDB[1] = City(1,"天津");
cityDB[2] = City(2,"上海");
cityDB[3] = City(3,"武汉");
cityDB[4] = City(4,"广州");
cityDB[5] = City(5,"南京");
cityDB[6] = City(6,"重庆");
cityDB[7] = City(7,"成都");
cityDB[8] = City(8,"西安");
cityDB[9] = City(9,"郑州");

cityGraph.setEdge(1,0,108);
cityGraph.setEdge(2,1,956);
cityGraph.setEdge(0,9,624);
cityGraph.setEdge(2,9,807);
cityGraph.setEdge(9,8,427);
cityGraph.setEdge(9,3,457);
cityGraph.setEdge(8,3,661);
cityGraph.setEdge(7,8,617);
cityGraph.setEdge(6,7,267);
cityGraph.setEdge(3,6,752);
cityGraph.setEdge(3,2,686);
cityGraph.setEdge(3,5,457);
cityGraph.setEdge(5,6,1199);
cityGraph.setEdge(2,4,1219);
cityGraph.setEdge(4,3,846);
cityGraph.setEdge(4,5,1142);


frontPage();
return 0;
}

能否用同一个调用形式,既能调用派生类又能调用基类的同名函数。在程序中不是通过不同的对象名去调用不同派生层次中的同名函数,而是通过指针调用它们。例如,用同一个语句“pt->display( );”可以调用不同派生层次中的display函数,只需在调用前给指针变量 pt 赋以不同的值(使之指向不同的类对象)即可。

C++中虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。

纯虚函数在基类中是没有定义的,必须在子类中加以实现,很像java中的接口函数!


百度解释:

在某 基类中声明为 virtual 并在一个或多个 派生类中被重新定义的 成员函数,用法格式为:virtual 函数返回类型 函数名(参数表) { 函数体};实现 多态性,通过指向派生类的基类 指针或引用,访问派生类中同名覆盖成员函数
中文名
虚函数
外文名
virtual function
定    义
被virtual关键字修饰的成员函数
作    用
实现 多态性
形象解释
求同存异
关    键
用指向 基类指针或引用操作对象
声    明
 virtual 







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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值