Radix Heap ---Dijkstra算法的优化 BY Gremount
Radix Heap 算法是在Dijkstra的Dial实现的基础上,通过减少对桶的使用,来优化算法的时间复杂度:
Dial 时间复杂度是O(m+nC) -------C是最长的链路
Radix Heap 时间复杂度是O(m+n*log(nC))
本质上来说Radix Heap是Dial和Dijkstra的折中,因为Dial用NC个桶,Dijkstra用1个桶
下面是本程序中使用的一些函数介绍:
void radix_heap():
(1)对所有桶的range初始化(2)所有节点的初始化(这一步可以在建图的时候完成);
(2)除开始点,其他全部放入无穷桶里,注意这里的无穷桶的id=初始d值对2求对数后上去整;
(3)更新源节点
(4)后续是找最小值和更新的操作循环(类似于dijkstra算法)
int FindMin():
(1)移动指针到第一个不为空的桶
(2)如果桶的编号是0或者1,则任取元素出来返回;
如果编号大于1且桶内元素个数为1,则将该元素取出来返回;
如果编号大于1且桶内的元素个数大于1,则先找出最小值,再执行redistribute()
重置桶里的元素
int Redistribute():
(1)根据最小值,更改桶的range,修改range和桶的映射;
(2)将该桶内的元素重置位置,返回最小值;
void Update(int i):
根据i点的d值和邻接边的值来更改与i相连的其他节点的d值;
下面是我写的程序,分为三部分,第一部分是主程序,第二部分是资源程序,第三部分是头文件
第一部分:创建如下图:
//radix_heap.cpp 主程序:完成图的创建和最短路函数调用 #include "resources.h" CEdge::CEdge(int a, int b, int c, int d){ tail=a; head=b; weight=c; capacity=d; } CEdge::CEdge(int a, int b, int c){ head=b; tail=a; weight=c; } CEdge::CEdge(CEdge & x){ tail=x.getTail(); head=x.getHead(); weight=x.getWeight(); capacity=x.getCap(); } CGraph::CGraph(list<CEdge*> listEdge){ IncidentList=listEdge; numVertex=N; numEdge=listEdge.size(); } int main() { list<CEdge*> listEdge; CEdge* e1=new CEdge(1,2,1,10); CEdge* e2=new CEdge(2,1,1,10); CEdge* e3=new CEdge(1,7,1,10); CEdge* e4=new CEdge(7,1,1,10); CEdge* e5=new CEdge(7,10,1,10); CEdge* e6=new CEdge(10,7,1,10); CEdge* e7=new CEdge(3,2,1,10); CEdge* e8=new CEdge(2,3,1,10); CEdge* e9=new CEdge(3,4,1,10); CEdge* e10=new CEdge(4,3,1,10); CEdge* e11=new CEdge(4,10,1,10); CEdge* e12=new CEdge(10,4,1,10); CEdge* e13=new CEdge(1,5,1,10); CEdge* e14=new CEdge(5,1,1,10); CEdge* e15=new CEdge(6,5,1,10); CEdge* e16=new CEdge(5,6,1,10); CEdge* e17=new CEdge(6,10,1,10); CEdge* e18=new CEdge(10,6,1,10); CEdge* e19=new CEdge(8,10,1,10); CEdge* e20=new CEdge(10,8,1,10); CEdge* e21=new CEdge(9,10,1,10); CEdge* e22=new CEdge(10,9,1,10); listEdge.push_back(e1); listEdge.push_back(e2); listEdge.push_back(e3); listEdge.push_back(e4); listEdge.push_back(e5); listEdge.push_back(e6); listEdge.push_back(e7); listEdge.push_back(e8); listEdge.push_back(e9); listEdge.push_back(e10); listEdge.push_back(e11); listEdge.push_back(e12); listEdge.push_back(e13); listEdge.push_back(e14); listEdge.push_back(e15); listEdge.push_back(e16); listEdge.push_back(e17); listEdge.push_back(e18); listEdge.push_back(e19); listEdge.push_back(e20); listEdge.push_back(e21); listEdge.push_back(e22); CGraph g(listEdge); g.p1(); g.p2(); g.p3(); g.p4(); g.radix_heap(g,1); getchar(); return 0; }
第二部分:
//resources.h 所用的类:点,边,图 //图中包含对图的测量函数(p1`、p2、p3、p4) //radix_heap() FindMin() Update() Redistribute() #include "common.h" class CVertex{ public: int d; int p; int ID; CVertex(int x){ID=x;d=INF;p=NULL;} ~CVertex(){;} }; class CEdge{ private: int tail, head; int weight, capacity; public: CEdge(int a, int b, int c, int d); CEdge(int a, int b, int c); CEdge(CEdge &x); int getHead(){return head;} int getTail(){return tail;} int getWeight(){return weight;} int getCap(){return capacity;} bool operator<(CEdge& x){ if(weight<x.weight) return 1; else return 0; } }; class CGraph{ private: int numVertex; int numEdge; list<CEdge*> IncidentList; public: set<int> S; set<int> V; int d[N+10]; int p[N+10]; map<int,int> degree_vertex; multimap<int,int> degree_vertex2; map<int,list<int>> adjlist; vector<vector<CEdge*>> adjmatrix; map<int,list<CEdge*>> nelist; map<int,map<int, CVertex*>> mapBuckets; map<int, CVertex*> mapVID_Vertex; map<int,map<int, CVertex*>>::iterator itBucket; map<int, CVertex*>::iterator itcv; int range[2024]; int rbegin[20]; int rend[20]; int zhishu; int db[20]; CGraph(char* inputFile); CGraph(list<CEdge*> listEdge); CGraph(CGraph &); void init() { //range表初始化 zhishu=2; rbegin[0]=1; rend[0]=1; rbegin[1]=2; rend[1]=2; for(int i=2;i<=10;i++) { zhishu=zhishu*2; rbegin[i]=rend[i-1]+1; rend[i]=zhishu; } //等比数列初始化 db[1]=1; for(int i=2;i<=10;i++) db[i]=db[i-1]*2; } int getNumVertex(){ return numVertex; } int getNumEdge(){ return numEdge; } int cmp(const pair<int,int> &x, const pair<int, int> &y){ return x.second > y.second; } void p1(){ list<CEdge*>::iterator it,iend; multimap<int,int>::iterator it2; iend=IncidentList.end(); vector<pair<int,int>> dv_vec; for(int i=1;i<=N;i++) degree_vertex[i]=0; for(it=IncidentList.begin();it!=iend;it++) degree_vertex[(*it)->getTail()]++; for(int i=1;i<=N;i++) degree_vertex2.insert(pair<int,int>(degree_vertex[i],i)); it2=--degree_vertex2.end(); printf("project 1:\n"); for(;it2!=degree_vertex2.begin();it2--) printf("%d,%d\n",it2->second,it2->first); } void p2(){ list<CEdge*>::iterator it,iend; list<int>::iterator it2,iend2; iend=IncidentList.end(); //printf("incidentList:\n"); for(it=IncidentList.begin();it!=iend;it++){ adjlist[(*it)->getTail()].push_back((*it)->getHead()); //printf("%d,%d\n",(*it)->getTail(),(*it)->getHead()); } it2=adjlist[3].begin(); iend2=adjlist[3].end(); printf("\n"); printf("project 2:\n"); printf("3:"); for(;it2!=iend2;it2++) printf("%d ",*it2); } void p3(){ list<CEdge*>::iterator it,iend; iend=IncidentList.end(); CEdge* emptyedge=new CEdge(-1,-1,-1,-1); for(int i=0;i<=numVertex;i++) { vector<CEdge*> vec; for(int j=0;j<=numVertex;j++) { vec.push_back(emptyedge); } adjmatrix.push_back(vec); } for(it=IncidentList.begin();it!=iend;it++){ //CEdge* e = new CEdge((*it)->getTail(),(*it)->getHead(),(*it)->getWeight(),(*it)->getCap()); adjmatrix[(*it)->getTail()][(*it)->getHead()] = *it ; } printf("\n"); printf("project 3:\n"); printf("%d,%d",adjmatrix[2][3]->getTail(),adjmatrix[2][3]->getHead()); } void p4(){ list<CEdge*>::iterator it,iend; iend=IncidentList.end(); for(it=IncidentList.begin();it!=iend;it++){ nelist[(*it)->getTail()].push_back(*it); } printf("\n"); printf("project 4:\n"); list<CEdge*>::iterator it2,iend2; iend2=nelist[3].end(); for(it2=nelist[3].begin();it2!=iend2;it2++) printf("%d %d\n",(*it2)->getTail(),(*it2)->getHead()); } void Update(int i){ list<CEdge*>::iterator it,iend; it=nelist[i].begin(); iend=nelist[i].end(); for(;it!=iend;it++) if((*it)->getWeight()+mapVID_Vertex[i]->d < mapVID_Vertex[(*it)->getHead()]->d){ int d; d=(*it)->getWeight()+mapVID_Vertex[i]->d; //增加新的点,删除旧的点,改动点信息 int k; k = mapVID_Vertex[(*it)->getHead()]->d; //pair<int,CVertex*> p((*it)->getHead(),mapBuckets[int(ceil((log((float)k))/(log((float)2))))][(*it)->getHead()]); pair<int,CVertex*> p((*it)->getHead(),mapVID_Vertex[(*it)->getHead()]); mapBuckets[int(ceil((log((float)d))/(log((float)2))))].insert(p); mapBuckets[int(ceil((log((float)k))/(log((float)2))))].erase((*it)->getHead()); mapVID_Vertex[(*it)->getHead()]->d = (*it)->getWeight()+mapVID_Vertex[i]->d; mapVID_Vertex[(*it)->getHead()]->p = i; } //printf("update\n"); } int Redistribute(int dmin, int mini) { rbegin[0]=dmin; rend[0]=dmin; rbegin[1]=dmin+1; rend[1]=dmin+1; range[dmin]=0; range[dmin+1]=1; for(int i=2;i<=10;i++) { rbegin[i]=rend[i-1]+1; rend[i]=rend[i-1]+db[i]; for(int j=rbegin[i];j<=rend[i];j++) range[j]=i; } cout<<"middle"<<endl; //重置该桶内的所有节点 itcv=itBucket->second.begin(); for(;itcv!=itBucket->second.end();) { //增加新的点,删除旧的点 cout<<"middle2"<<endl; pair<int,CVertex*> p(itcv->first,itcv->second); //mapBuckets[range[mapVID_Vertex[itcv->first]->d]].insert(p); mapBuckets[range[itcv->second->d]].insert(p); cout<<"middle3"<<endl; mapBuckets[itBucket->first].erase(itcv++); cout<<"middle4"<<endl; } itBucket=mapBuckets.begin(); cout<<"Before_FindMin"<<endl; int reward; reward=FindMin(); return reward; } int FindMin(){ set<int>::iterator vi,vend; //移动指针到第一个不为空的桶 while(1) { if(itBucket->second.empty()==true) itBucket++; else {itcv=itBucket->second.begin();break;} } if(itBucket->first==0 || itBucket->first==1) { int mini; printf("1 if\n"); mini=itcv->first; mapBuckets[itBucket->first].erase(itcv++); printf("min is %d\n",mini); return mini; } else if(itBucket->second.size()==1) { int mini; printf("2 if\n"); mini=itcv->first; mapBuckets[itBucket->first].erase(itcv++); //printf("min is %d\n",mini); return mini; } else { int dmin=10000; int mini; printf("3 if\n"); itcv=itBucket->second.begin(); cout<<mapVID_Vertex[itcv->first]->d<<endl; for(;itcv!=itBucket->second.end();itcv++) { if(mapVID_Vertex[itcv->first]->d < dmin) {dmin=mapVID_Vertex[itcv->first]->d;mini=itcv->first;} } cout<<dmin<<mini<<endl; itcv=itBucket->second.begin(); return Redistribute(dmin,mini); } } void radix_heap(CGraph &g,int s){ int i,j; init(); for(i=1;i<=10;i++) V.insert(i); for(i=1;i<=N;i++)//所有节点的初始化 { CVertex* vertex=new CVertex(i); pair<int, CVertex*> p(i,vertex); mapVID_Vertex.insert(p); } for(i=2;i<=N;i++)//除开始点,其他全部放入无穷桶里 { pair<int,CVertex*> p2(i,mapVID_Vertex[i]); mapBuckets[ceil(log(float(INF))/log(2.0))].insert(p2);//10=log1024,对应无穷桶,方便在删除时操作 } S.insert(s); V.erase(s); mapVID_Vertex[1]->d=0; Update(s); itBucket=mapBuckets.begin(); while (V.size()!=0) { j=FindMin(); S.insert(j); V.erase(j); cout<<"V :"<<j<<" "<<V.size()<<endl; Update(j); } printf("\n 1->9:%d\n",mapVID_Vertex[9]->d); } };
第三部分:
//一些需要用到的头文件 #ifndef _COMMON_H_ #define _COMMON_H_ #include <map> #include <vector> #include <list> #include <set> #include <math.h> using namespace std; #include <iostream> #include <stdio.h> #include <algorithm> #define INF 1024 #define N 10 #define C 1 #endif