c++ 下实现多线程的双向dijkstra算法

背景

上学期的通信网理论基础课上,双向dijkstra是一个选作的研究性课题,当时没做,这个假期有时间了准备写一个。写着写着发现既然是双向,两边同时运行肯定比来回切换的“伪同时”要更快,反正现在的CPU基本都是二核以上的。
开始想用fork()函数来着,后来发现windows下没有这玩意,又找到了CreateThread,结果成功实现。

大致思想

依旧是在网格地图中的寻路,由于要在两个方向上进行寻路,于是需要维护两个Priority_queue,而主体dijkstra不需要写两个,只要在传入参数中加一个方向标识即可。在判断寻路完毕上,我最终决定在visited上下手,即将原本的二元0-1 visited变为三元visited——0,正向访问完毕1,反向访问完毕1,当某方向探测到另一方向上的访问完毕标识时,即结束dijkstra,输出结果。与之相应的,控制dijkstra持续运行的不再是while而是递归。

实例代码

#include <iostream>
#include <fstream>
#include <queue>
#include <vector>
#include <windows.h> 

#define unit 10
#define INF 10000
#define forward 1
#define back 0
#define f_visit 6 //正方向访问标识 
#define b_visit 7 //逆方向访问标识 

using namespace std;

class TPoint{
	public:
		int x;
		int y;
};

const int line=23;
const int column=61;
int dis_f[line][column];
int dis_r[line][column];
int visited[line][column];
int map[line][column];
TPoint pre[line][column];



struct cmp_f{

    bool operator()(TPoint a,TPoint b){
   	 
        return dis_f[a.x][a.y]>dis_f[b.x][b.y];  
    }   
};

struct cmp_r{

    bool operator()(TPoint a,TPoint b){
   	 
        return dis_r[a.x][a.y]>dis_r[b.x][b.y];  
    }   
};


priority_queue<TPoint,vector<TPoint>,cmp_f> Q_front;
priority_queue<TPoint,vector<TPoint>,cmp_r> Q_back;

int Distance_Judgement(int ori_x, int ori_y, int next_x, int next_y){
	if(ori_x==next_x && abs(ori_y-next_y)==1)
		return unit;
	if(ori_y==next_y && abs(ori_x-next_x)==1)
		return unit;
	if(abs(ori_x-next_x)==1 && abs(ori_y-next_y)==1)
		return 1.4*unit;//对角线走法路经长为根号2倍单位 
}

bool Meeting_Detector(TPoint v, bool direction){//原理是两个方向上采用不同的visited记号,当某方向上探测到另一种visited记号时即停止探测返回结果 
	
	switch(direction){
		case forward:{
			if(visited[v.x][v.y]==b_visit){
				//cout<< "正方向探测到终结"<< endl; 
				return TRUE;
			}
			else
				return FALSE;
		break;
		}
		 
		
		case back:{
			if(visited[v.x][v.y]==f_visit){
				//cout<< "逆方向探测到终结"<< endl;
				return TRUE;
			}
			else
				return FALSE;
		break;
		}
		
	}
}

void Initia(TPoint ori, TPoint des){
	
	for(int i=0; i<line; i++)
		for(int j=0; j<column; j++){//二维数组不能用={0}这种简单方式初始化 
			pre[i][j].x = -1;
			dis_f[i][j] = INF;
			dis_r[i][j] = INF;
			visited[i][j] = 0;
		}
			
	ifstream fin("map.txt", ios::in);
	while(fin.good())
		for(int i=0; i<line; i++)
			for(int j=0; j<column; j++)
				fin>> map[i][j];
				
	dis_f[ori.x][ori.y] = 0;
	dis_r[des.x][des.y] = 0;
	
}


int Bi_Dijkstra(TPoint u, bool direction){
	
	int i, j;
	TPoint temp, next;
	
	if(Meeting_Detector(u, direction)){
		
			if(direction==forward){
			Sleep(5);
			cout<< "最短路径前半段长为"<< dis_f[u.x][u.y]<< "后半段长为"<< dis_r[u.x][u.y]<< endl;
			cout<< "总长为"<< dis_f[u.x][u.y]+dis_r[u.x][u.y]<< endl;
			cout<< "正向探测相遇点为"<< u.x<< ","<< u.y<< endl;
			} 
			if(direction==back){
			Sleep(15);
			cout<< "最短路径前半段长为"<< dis_f[u.x][u.y]<< "后半段长为"<< dis_r[u.x][u.y]<< endl;
			cout<< "总长为"<< dis_f[u.x][u.y]+dis_r[u.x][u.y]<< endl;
			cout<< "逆向探测相遇点为"<< u.x<< ","<< u.y<< endl;
			} 

		
			/*搜索区域染色输出 
			ofstream os("map_mirrir.txt");
    		if (os)
   			{
        	for (int i=0;i<line;i++)
        	{
            	for (int j=0;j<column;j++)
                	os<< map[i][j]<<" ";
            	os<<endl;
        	}
        	os<<endl;os<<endl;os<<endl;
 
    		}
    		else
        	cerr<<"error"<<endl;
			*/
			Sleep(20); //执行快的那边等一会执行慢的,让它输出完 
			return 0;
			
	}
		
	if(direction==forward){
		
		visited[u.x][u.y] = f_visit;
		//map[u.x][u.y] = f_visit; //染色 
	}
	if(direction==back){
		
		visited[u.x][u.y] = b_visit;
		//map[u.x][u.y] = b_visit; //染色 
	}
		
	for(i=u.x-1; i<=u.x+1; i++){
		for(j=u.y-1; j<=u.y+1; j++){
			if(map[i][j]==0 || (i<0||i>=line) || (j<0||j>=column)){
				
				continue;
			}
			else if(map[i][j]!=0){
				
				int pace = Distance_Judgement(u.x, u.y, i, j);
					if(direction==forward && visited[i][j]!=f_visit){
						
						if(dis_f[i][j]==INF || dis_f[u.x][u.y]+pace < dis_f[i][j]){
							dis_f[i][j] = dis_f[u.x][u.y]+pace;
							pre[i][j].x = u.x; pre[i][j].y = u.y; 
							temp.x = i; temp.y = j;
							//visited[i][j] = f_visit; //这个在我上一个常规dijkstra算法里没有注释掉,想了想其实应该注释掉的,虽然对结果没影响 
							Q_front.push(temp);
							
						}
					}
					
					if(direction==back && visited[i][j]!=b_visit){
						
						if(dis_r[i][j]==INF || dis_r[u.x][u.y]+pace < dis_r[i][j]){
							dis_r[i][j] = dis_r[u.x][u.y]+pace;
							pre[i][j].x = u.x; pre[i][j].y = u.y; 
							temp.x = i; temp.y = j;
							//visited[i][j] = b_visit; //同上 
							Q_back.push(temp);
								
						}			
					}	
			}
		}
	}
	switch(direction){
		
		case forward:{
			next = Q_front.top();
			Q_front.pop();
			Sleep(1); //因为是并发执行,而且速度很快,不缓冲一下程序就报错,而且也看不出并发效果了 
			Bi_Dijkstra(next, forward);
			break;
		}
		case back:{
			next = Q_back.top();
			Q_back.pop();
			Sleep(1);//缓冲 
			Bi_Dijkstra(next, back);
			break;
		}
	}
}

DWORD WINAPI ThreadProc(LPVOID lpParameter){ //子线程 
		
		TPoint ori, temp1;
		ori.x = 0; ori.y = 0; 
	    Q_front.push(ori);
    	temp1 = Q_front.top();
    	Q_front.pop();
    	Bi_Dijkstra(temp1, forward);
	}
	


int main(){
	
	TPoint ori, des, temp2;
	ori.x = 0; ori.y = 0;
	des.x = 22; des.y = 60;
	Initia(ori, des);
	
	HANDLE thread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);//子线程创建 
    CloseHandle(thread);//结束子线程 
    Q_back.push(des);//主线程部分 
    temp2 = Q_back.top();
    Q_back.pop();
    Bi_Dijkstra(temp2, back);
    
    
	return 0;
}

 
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值