您的位置:首页 > 其它

第五周作业——3.Dijkstra算法的实现

2014-04-09 22:51 477 查看
题目原址

#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);
}


因为没实现动态读取文本数据,所以需要注意调整边数.

程序中没实现二分堆的优先队列.使用容器来实现最小键值的获取和调整,因此效率较低.

优先队列往后有空再实现.

文本一题图与结果图:





文本二结果图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: