#include <iostream>
#include <fstream>
#include <iterator>
#include <list>
using namespace std;
#define MAX_EDGE 2550
#define SAFE_DEL(p) { if (p!=NULL) { delete [] p;}}
class Vertex_Weight
{
public:
int no;
float weight;
Vertex_Weight(){}
Vertex_Weight(int n,float w)
{
no=n;
weight=w;
}
bool operator <(Vertex_Weight &t)
{
if(weight<t.weight) return true;
else return false;
}
bool operator >(Vertex_Weight &t)
{
if(weight>t.weight) return true;
else return false;
}
};
float *dist=NULL;
int *prever=NULL;
int ImportToArray(const char *filename,float *array) //将filename内的纯数字文本导入数组array;
{
int count=0;
ifstream fin;
fin.open(filename);
if( fin.fail() )
{
cout<<"file read fail!"<<endl;
return -1;
}
while( fin.eof() ==false )
fin>>array[count++];
fin.close();
return count;
}
void CreateAdjTable(list<int> *AdjTable,int *array,int count) //创建邻接表
{
for(int i=2;i<count;i+=2)
{
AdjTable[ array[i] ].push_back( array[i+1] );
}
}
void CreateReverseAdjTable(list<int> *AdjTable,int *array,int count) //创建反图邻接表
{
for(int i=2;i<count;i+=2)
{
AdjTable[ array[i+1] ].push_back( array[i] );
}
}
void ReverseAdjTable(list<int> *AdjTable,list<int> *RAdjTable,int vertexNum) //根据邻接表创建反图邻接表
{
list<int>::iterator it;
for(int i=0;i<vertexNum;i++)
for(it=AdjTable[i].begin();it!=AdjTable[i].end();++it)
{
RAdjTable[ *it ].push_back(i);
}
}
void ShowAdjTable(list<int> *AdjTable,int vertexNum) //显示邻接表
{
for(int i=0;i<vertexNum;i++)
{
cout<<i<<":";
copy(AdjTable[i].begin(),AdjTable[i].end(), ostream_iterator<int>(cout," "));
cout<<endl;
}
}
void CreateWeightAdjTable(list<Vertex_Weight> *WAdjTable,float *array,int count) //创建带权的邻接表
{
for(int i=2;i<count;i+=3)
{
Vertex_Weight t;
t.no=array[i+1];
t.weight=array[i+2];
WAdjTable[ (int)array[i] ].push_back(t);
}
}
void ShowWeightAdjTable()
{
}
void GraphBFS(list<Vertex_Weight> *WAdjTable,int start,int vertexNum) //广度优先遍历
{
float unlimit=INT_MAX/2;
for(int i=0;i<vertexNum;i++)
dist[i]=unlimit; //算是无穷
dist[start]=0;
list<int> Q;
Q.push_back(start);
while( !Q.empty() ) //队列Q不为空时
{
int u=Q.front();
Q.pop_front(); //获取队列头元素,并删除该元素
list<Vertex_Weight>::iterator it;
for(it=WAdjTable[u].begin();it!=WAdjTable[u].end();++it)
{
if ( unlimit==dist[it->no]) //v=it->no;
{
Q.push_back(it->no);
dist[it->no]=dist[u]+1;
}
}
}
}
void decreasekey(list<Vertex_Weight> &H,int v)
{
list<Vertex_Weight>::iterator it;
for(it=H.begin();it!=H.end();it++)
{
if(v==it->no)
{
it->weight=dist[v]; //更新键值
break;
}
}
}
int deletemin(list<Vertex_Weight> &H) //有误
{
list<Vertex_Weight>::iterator it=H.begin();
list<Vertex_Weight>::iterator delp=it;
int u=it->no;
int d=it->weight;
for(;it!=H.end();it++)
{
if( it->weight < d )
{
u=it->no;
d=it->weight;
delp=it;
}
}
H.erase(delp); //移除dist值最小的元素
return u;
}
void Dijkstra(list<Vertex_Weight> *WAdjTable,int start,int vertexNum)
{
float unlimit=INT_MAX/2;
for(int i=0;i<vertexNum;i++)
{
dist[i]=unlimit;
prever[i]=-1;
}
dist[start]=0;
创建伪优先队列
list<Vertex_Weight> H(vertexNum,Vertex_Weight(0,0)); //最小键值总在队列头
list<Vertex_Weight>::iterator it;
int i=start;
for(it=H.begin();it!=H.end();++it)
{
it->no=i;
it->weight=dist[i];
i=(i+1)%vertexNum;
}
/
while(!H.empty())
{
int u=H.front().no; //获取最小键值的顶点号
H.pop_front(); //获取后删除该元素
//int u=deletemin(H); //同上
for(it=WAdjTable[u].begin();it!=WAdjTable[u].end();++it) //此时v==it->no
{
if(dist[it->no] > dist[u] + it->weight) //即if dist[v]>dist[u]+l(u,v);
{
dist[it->no]=dist[u] + it->weight;
prever[it->no]=u;
decreasekey(H,it->no);
}
}
H.sort(); //排序,使最小键值元素在最前;
}
}
void ShowPath(int start,int vertexNum)
{
list<int> stack;
for(int i=(start+1)%vertexNum;i!=start;i=(i+1)%vertexNum)
{
int v=i;
stack.push_front(v);
while(v!=start)
{
v=prever[v];
stack.push_front(v);
}
cout<<start<<"到"<<i<<"的路径:"<<endl;
copy(stack.begin(),stack.end(),ostream_iterator<int>(cout,"->"));
cout<<"路径距离:"<<dist[i]<<endl;
stack.clear();
}
}
void Showdist(int vertexNum)
{
for(int i=0;i<vertexNum;i++)
cout<<i<<"\t";
cout<<endl;
for(int i=0;i<vertexNum;i++)
cout<<dist[i]<<"\t";
cout<<endl;
}
void main()
{
float *array=new float[MAX_EDGE*3];
int count=ImportToArray("tinyEWD.txt",array);//注意文本最后有无空行
int vertexNum=array[0],edgeNum=array[1];
list<Vertex_Weight> *WAdjTable=new list<Vertex_Weight>[vertexNum];
dist=new float[vertexNum];
prever=new int[vertexNum];
CreateWeightAdjTable(WAdjTable,array,count);
cout<<vertexNum<<" "<<edgeNum<<endl;
cout<<WAdjTable[vertexNum-1].front().no<<" "<<WAdjTable[vertexNum-1].front().weight<<endl;
// GraphBFS(WAdjTable,0,vertexNum);
Dijkstra(WAdjTable,0,vertexNum);
Showdist(vertexNum);
ShowPath(0,vertexNum);
/*
list<int> *AdjTable=new list<int>[vertexNum];
list<int> *RAdjTable=new list<int>[vertexNum];
CreateAdjTable(AdjTable,array,count-1); //创建邻接表
ReverseAdjTable(AdjTable,RAdjTable,vertexNum); //创建反图邻接表
cout<<"邻接表:"<<endl;
ShowAdjTable(AdjTable,vertexNum);
cout<<"反图邻接表:"<<endl;
ShowAdjTable(RAdjTable,vertexNum);
//
//销毁动态数组
for(int i=0;i<vertexNum;i++)
{
AdjTable[i].clear();
RAdjTable[i].clear();
}
SAFE_DEL(RAdjTable);
SAFE_DEL(AdjTable);*/
//销毁动态数组
for(int i=0;i<vertexNum;i++)
{
WAdjTable[i].clear();
}
SAFE_DEL(dist);
SAFE_DEL(WAdjTable);
SAFE_DEL(array);
}
因为没实现动态读取文本数据,所以需要注意调整边数.
程序中没实现二分堆的优先队列.使用容器来实现最小键值的获取和调整,因此效率较低.
优先队列往后有空再实现.
文本一题图与结果图:
文本二结果图: