您的位置:首页 > Web前端 > JavaScript

双向Dijstra算法

2015-12-17 16:30 393 查看
双向Dijstra算法:在无向带权图中,求从s到t最短路径。双向Dijstra算法的思想是:分别从s顶点和t顶点开始执行单向Dijstra算法,从s点开始执行的Dijstra算法定义为前向Dijstra搜索,从t点开始执行Dijstra算法定义为后向Dijstra搜索。算法结束的条件是:前向(后向)Dijstra搜索求得当前最短路径上的顶点为u,且在后向(前向)Dijstra搜索已经计算出到u的最短路径,此时s到t的最短路径可以表示为sp(s,u)+sp(t,u)。
    如图所示:求s到t的最短路径,我们分别从s和t执行Dijstra搜索,经过三次迭代后,前向(后向)Dijstra搜索已经求得最短路径上的点为s,a,b(t,g,f),此时优先队列Qf(执行前向Dijstra搜索使用的优先队列)和Qb(执行后向Dijstra搜索使用的优先队列)中分别存储c,d和e,d,且此时s到c和d的最短距离分别为6,10;t到e和d的最短距离也分别为6,10。继续执行,前向Dijstra搜索中c顶点执行出栈操作,同时松弛(c,e)和(c,d)边;后向Dijstra搜索中e顶点出栈,同时松弛(e,c)和(e,d)边。再一次迭代时,前向Dijstra搜索中e顶点执行出栈操作时,后向Dijstra搜索中已经求得t到e最短距离,所以双向Dijstra算法结束,最后求得s到t的最短距离为sp(s,e)+sp(t,e)=13。

[code]
//使用二叉堆选择最小元素的双向Dijstra算法
#include<iostream>
#include<vector>
#include<fstream>
#include<time.h>
using namespace std;

//优先队列里存储元素类型
struct Node
{
	int ver;//源点可达的顶点
	int dis;//源点到可达顶点的距离
	Node(){}
	Node(int ver, int dis)
	{
		this->ver = ver;
		this->dis = dis;
	}
};

//优先队列类
struct HeapMin
{
	vector<Node> ve;//优先队列中存储元素的容器
	vector<int> index;//顶点在优先队列中的下标index[2] = 3;表示顶点为2的顶点存储在优先队列的3号位置。 
	int size;//优先队列的总容量
	int cur;//当前优先队列中元素的个数
	
	//初始化优先队列
	HeapMin(int size)
	{
		this->size = size;
		ve.resize(size);
		index.resize(size);
		cur = 0;
	}
	
	//优先队列中的某个位置(pos)的元素值被改变了,重新调整优先队列
	void siftUp(int pos)
	{
		while(pos > 0 && ve[pos].dis < ve[(pos - 1)/2].dis)
		{
			swap(index[ve[pos].ver],index[ve[(pos - 1)/2].ver]);
			swap(ve[pos],ve[(pos - 1)/2]);
			pos = (pos - 1)/2;
		}
	}
	
	//判断优先队列是否为空
	bool empty()
	{
		if(cur == 0)
			return true;
		else
			return false;
	}
	
	//返回优先队列中的最小元素但是不弹出
	Node top()
	{
		return ve[0];
	}
	
	//弹出优先队列对头元素
	void pop()
	{
		cur--;
		swap(index[ve[cur].ver],index[ve[0].ver]);
		swap(ve[0],ve[cur]);
		siftDown(0);
	}
	
	//从当前位置开始向下调整优先队列
	void siftDown(int start)
	{
		int i = start;
		while((2 * i + 1) < cur && (2 * i + 2) < cur)
		{
			if(ve[2 * i + 1].dis < ve[2 * i + 2].dis)
			{
				if(ve[i].dis > ve[2 * i + 1].dis)
				{
					index[ve[2 *i + 1].ver] = i;
					index[ve[i].ver] = 2 * i + 1;
					swap(ve[i],ve[2 * i + 1]);
					i = 2 * i + 1;
				}
				else
				{
					break;
				}
			}
			else
			{
				if(ve[i].dis > ve[2 *i + 2].dis)
				{
					index[ve[2 * i + 2].ver] = i;
					index[ve[i].ver] = 2 * i + 2;
					swap(ve[i],ve[2 * i + 2]);					
					i = 2 * i + 2;
				}
				else
				{
					break;
				}
			}
		}
		if((2 * i + 1) < cur && ve[i].dis > ve[2 * i + 1].dis)
		{
			swap(ve[i],ve[2 * i + 1]);
			index[ve[2 * i + i].ver] = i;
			index[ve[i].ver] = 2 * i + 1;
		}
	}
	
	//创建一个优先队列
	void createHeap()  
	{  
		for(int i = cur / 2 - 1; i >= 0; --i)  
		{  
			siftDown(i);  
		}  
	}
	
	//向优先队列中插入元素,但是不调整优先队列
	void insert(int v, int w)
	{
		Node tmp(v,w);
		ve[cur] = tmp;
		index[cur++] = v;
	}
};

//边的类型
struct Edge
{
	int value;
	float weight;
	Edge(){}
	Edge(int value,float weight)
	{
		this->value = value;
		this->weight = weight;
	}
};

vector<vector<Edge>> mGraph;//图结构
int nodeNum;//图中顶点数
int edgeNum;//图中边数
vector<int> df;//源点到当前顶点的距离
vector<int> db;
vector<int> flagf;
vector<int> flagb;
vector<int> p;//最短路径中的前一个顶点
HeapMin quf(10);//创建一个优先队列
HeapMin qub(10);

//读取图文件
void readGraph()
{
	fstream fin("E:\\SPData\\data05.txt");//打开文件
	fin>>nodeNum>>edgeNum;//读取顶点数和边数
	mGraph.resize(nodeNum);
	df.resize(nodeNum);
	db.resize(nodeNum);
	flagf.resize(nodeNum);
	flagb.resize(nodeNum);
	p.resize(nodeNum);
	int id ,s , t;
	float w;
	Edge tmp;
	while(fin>>id>>s>>t>>w)
	{
		tmp.value = t;
		tmp.weight = w;
		mGraph[s].push_back(tmp);
		tmp.value = s;
		tmp.weight = w;
		mGraph[t].push_back(tmp);
	}
	fin.close();
}

//初始化源点到其他顶点的距离,并且初始化通过那个顶点到达这个顶点
void initialize_signal_source(int s,int t)
{
	for(int i = 0; i < nodeNum; ++i)
	{
		db[i] = 1000;//设置为无穷(用1000表示)
		df[i] = 1000;
		flagf[i] = 0;
		flagb[i] = 0;
		p[i] = -1;
	}
	flagf[s] = 1;
	flagb[t] = 1;
	df[s] = 0;
	db[t] = 0;
}

//松弛边的操作
void relaxf(int u, int v, int w)
{
	if(flagf[v] != 2 && df[v] > df[u] + w)
	{
		df[v] = df[u] + w;
		p[v] = u;
		flagf[v] = 1;
		int pos = quf.index[v];//得到要修改优先队列中距离值得下标
		quf.ve[pos].dis = df[u] + w;//修改对应优先队列中距离值
		quf.siftUp(pos);//从新调整优先队列
	}
}

void relaxb(int u, int v, int w)
{
	if(flagb[v] != 2 && db[v] > db[u] + w)
	{
		db[v] = db[u] + w;
		p[v] = u;
		flagb[v] = 1;
		int pos = qub.index[v];//得到要修改优先队列中距离值得下标
		qub.ve[pos].dis = db[u] + w;//修改对应优先队列中距离值
		qub.siftUp(pos);//从新调整优先队列
	}
}

//迪杰斯特拉算法
void dijkstra(int s,int t)
{
	int dis = 0;
	initialize_signal_source(s,t);//初始化
	for(int i = 0; i < nodeNum; ++i)
	{
		quf.insert(i,df[i]);
		qub.insert(i,db[i]);
	}
	quf.createHeap();//创建优先队列
	qub.createHeap();
	while(!quf.empty() && !qub.empty())//判断优先队列是否为空
	{
		int valf = quf.top().ver;//返回最小值
		int valb = qub.top().ver;
		if(flagb[valf] == 2)
		{
			dis = df[valf] + db[valf];
			break;
		}
		if(flagf[valb] == 2)
		{
			dis = df[valb] + db[valb];
			break;
		}
		flagf[valf] =  2;
		flagb[valb] = 2;
		quf.pop();//队头元素出队列
		qub.pop();
		int countf = mGraph[valf].size();
		for(int i = 0; i < countf; ++i)
		{
			int u = valf;
			int v = mGraph[valf][i].value;
			int weight = mGraph[valf][i].weight;
			relaxf(u,v,weight);		
		}
		int countb = mGraph[valb].size();
		for(int i = 0; i < countb; ++i)
		{
			int u = valb;
			int v = mGraph[valb][i].value;
			int weight = mGraph[valb][i].weight;
			relaxb(u,v,weight);		
		}
	}
	cout<<dis<<endl;
}

int main(void)
{
	readGraph();
	dijkstra(0,8);
	end = clock();
	system("pause");
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: