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

来源:互联网 发布:申请淘宝网店的步骤 编辑:程序博客网 时间:2024/05/16 12:35

背景

上学期的通信网理论基础课上,双向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;}elsereturn FALSE;break;} case back:{if(visited[v.x][v.y]==f_visit){//cout<< "逆方向探测到终结"<< endl;return TRUE;}elsereturn 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 0
原创粉丝点击