C++ dijkstra 最短路徑演算法、top排序、DFS、BFS 示例 C++11
阿新 • • 發佈:2019-01-07
好一段時間前寫的了。。。正好現在在複習資料結構,重構了一下程式碼
首先先是 圖、點Vertex和邊AdjACent的定義
class JpGraph
{
public:
class Vertex;
class AdjAcent
{
public:
int cost;
Vertex* ptr;
explicit AdjAcent(int newCost = 0,Vertex* newPtr = nullptr):cost(newCost),ptr(newPtr){}
};
class Vertex
{
public:
int index;
int inDegree;
vector<AdjAcent>degree;
Vertex(int data, int in_degree)
: index(data),
inDegree(in_degree)
{
}
};
JpGraph(){}
void lowestCost(const Vertex& v);
void buildGraph(vector<Vertex> vertexs);
void BFS(int index);
void DFS(int index);
void topSort();
private:
vector<Vertex>vertexs;
};
下面是最短路徑的實現,也就是dijkstra演算法的實現
inline void JpGraph::lowestCost(const Vertex& v) //形參既是從哪個點開始算
{
vector<pair<bool, int>> status;
for (int i = 0; i < vertexs.size(); ++i)
{
status.push_back(pair<bool, int>(false, INT32_MAX));
}
//建立與相應點集對應的集合。
status[v.index].second = 0;
auto findMin = [&]() //lambda表示式,反正我就這個函式用就沒單獨寫個私有函式
//目的是找到當前權重最小的點的下標
{
int min = INT32_MAX;
int minIndx = 0;
for (int i = 0; i < status.size(); ++i)
if (status[i].second < min && status[i].first == false)
{
min = status[i].second;
minIndx = i;
}
return minIndx;
};
auto isAllTrue = [&]() //檢查所有的點是不是都已標記為true
{
for (const auto& i : status)
{
if (i.first == false)
return false;
}
return true;
};
//以前寫的實現,這次重構發現完全沒必要全部遍歷。。dijkstra演算法的思想可不就是貪心麼。。不知道以前咋想的
//for (;;)
//{
// status[findMin()].first = true; //每次都將未知的點集中的最小值設為已知
// for (int i = 0; i < status.size(); ++i)
// {
// if (status[i].first == true)
// {
// for (const auto& adj : vertexs[i].degree)
// {
// auto desV = (*(adj.ptr)).index;
// if (status[i].second + adj.cost < status[desV].second) //對與已知點相連線的點的cost進行更新
// status[desV].second = status[i].second + adj.cost;
// }
// }
// }
// if (isAllTrue()) //如果所有點都已知,則退出迴圈
// break;
//}
while(!isAllTrue())
{
auto minIndex = findMin();
status[minIndex].first = true; //每次都將未知的點集中的最小值設為已知
for (const auto& adj : vertexs[minIndex].degree)
{
auto desV = (*(adj.ptr)).index;
if (status[minIndex].second + adj.cost < status[desV].second) //對與已知點相連線的點的cost進行更新
status[desV].second = status[minIndex].second + adj.cost;
}
}
for (int i = 0; i < status.size(); ++i)
{
cout << "vertexIndex :" << i << " cost: " << status[i].second << endl;
}
}
以下為測試程式碼
inline void testDijkstra()
{
std::cout << "testDijkstra :" << std::endl;
vector<int>vec;
//sort(vec.begin(), vec.end(), less<int>());
typedef JpGraph::Vertex vertex;
typedef JpGraph::AdjAcent adj;
vertex v0(0, 0);
vertex v1(1, 1);
vertex v2(2, 1);
vertex v3(3, 2);
vertex v4(4, 2);
vertex v5(5, 3);
vertex v6(6, 2);
v0.degree = vector<adj>{ adj(1,&v3),adj{ 2,&v1 } };
v1.degree = vector<adj>{ adj{ 3,&v3 },adj{ 2,&v4 } };
v2.degree = vector<adj>{ adj{ 5,&v5 },adj{ 4,&v0 } };
v3.degree = vector<adj>{ adj{ 8,&v5 },adj{ 2,&v2 },adj{ 2,&v4 },adj{ 4,&v6 } };
v4.degree = vector<adj>{ adj{ 6,&v6 }, };
v5.degree = vector<adj>();
v6.degree = vector<adj>{ adj{ 1,&v5 } };
JpGraph graph;
graph.buildGraph(vector<vertex>{v0, v1, v2, v3, v4, v5, v6});
graph.lowestCost(v0);
}
以下為top排序,top排序的思想我也不說了,網上一搜都有,以下僅實現
inline void JpGraph::topSort()
{
deque<Vertex>q;
for(const Vertex& vertex : vertexs)
{
if (vertex.inDegree == 0)//將所有入度為0的點加入
q.push_back(vertex);
}
while(q.size()!=0)//依次將與入度為0的點相連的點加入,並將入度0的點pop掉,此處既是一個DFS
{
auto i = q.front(); q.pop_front();
cout<<i.index << " "; //通過簡單的cout代表訪問點
for(auto& adj : i.degree)
{
auto ptr = adj.ptr;
--(ptr->inDegree);
if (ptr->inDegree == 0)
q.push_back(*ptr);
}
}
}
以下為測試程式碼
inline void testTopSort()
{
vector<int>vec;
//sort(vec.begin(), vec.end(), less<int>());
typedef JpGraph::Vertex vertex;
typedef JpGraph::AdjAcent adj;
vertex v0(0, 0);
vertex v1(1, 1);
vertex v2(2, 1);
vertex v3(3, 2);
vertex v4(4, 2);
vertex v5(5, 3);
vertex v6(6, 2);
v0.degree = vector<adj>{ adj(1,&v3),adj{ 2,&v1 } };
v1.degree = vector<adj>{ adj{ 3,&v3 },adj{ 2,&v4 } };
v2.degree = vector<adj>{ adj{ 5,&v5 },adj{4,&v0} };
v3.degree = vector<adj>{ adj{ 8,&v5 },adj{ 2,&v2 },adj{2,&v4},adj{ 4,&v6 } };
v4.degree = vector<adj>{ adj{ 6,&v6 },};
v5.degree = vector<adj>();
v6.degree = vector<adj>{ adj{ 1,&v5 } };
JpGraph graph;
graph.buildGraph(vector<vertex>{v0, v1, v2, v3, v4, v5, v6});
graph.topSort();
}
DFS和BFS我也不說廢話,直接上程式碼,DFS和BFS的思想網上隨便找
inline void JpGraph::BFS(int index)
{
map<int, bool>hasVisited;
deque<int>checkLine;
for (int i = 0; i < vertexs.size(); ++i)
hasVisited[i] = false;
checkLine.push_back(index);
while(!checkLine.empty())
{
int toTravel = checkLine.front();
checkLine.pop_front();
if (!hasVisited[toTravel])
{
hasVisited[toTravel] = true;
cout << vertexs[toTravel].index + 1 << " ";
for(const auto& i : vertexs[toTravel].degree)
{
auto toPAt = *(i.ptr);
if(!hasVisited[toPAt.index])
{
checkLine.push_back(toPAt.index);
}
}
}
else;
}
}
inline void JpGraph::DFS(int index)
{
map<int, bool>hasVisited;
for (int i = 0; i < vertexs.size(); ++i)
{
hasVisited[i] = false;
}
stack<int>stk;
stk.push(index);
while (!stk.empty())
{
int toTravel = stk.top();
stk.pop();
if (hasVisited[toTravel] == false)
{
hasVisited[toTravel] = true;
cout << vertexs[toTravel].index + 1 << " ";
for (const auto& i : vertexs[toTravel].degree)
{
auto toPAt = *(i.ptr);
if (!hasVisited[toPAt.index])
{
stk.push(toPAt.index);
}
}
}
else;
}
}
測試程式碼
inline void testDFSAndBFS()
{
vector<int>vec;
//sort(vec.begin(), vec.end(), less<int>());
typedef JpGraph:: Vertex vertex;
typedef JpGraph:: AdjAcent adj;
vertex v0(0, 0);
vertex v1(1, 1);
vertex v2(2, 1);
vertex v3(3, 2);
vertex v4(4, 2);
vertex v5(5, 3);
vertex v6(6, 2);
v0.degree = vector<adj>{ adj(1,&v3),adj{ 2,&v1 } };
v1.degree = vector<adj>{ adj{ 3,&v3 },adj{ 2,&v4 } };
v2.degree = vector<adj>{ adj{ 5,&v5 },adj{ 4,&v0 } };
v3.degree = vector<adj>{ adj{ 8,&v5 },adj{ 2,&v2 },adj{ 2,&v4 },adj{ 4,&v6 } };
v4.degree = vector<adj>{ adj{ 6,&v6 }, };
v5.degree = vector<adj>();
v6.degree = vector<adj>{ adj{ 1,&v5 } };
JpGraph graph;
graph.buildGraph(vector<vertex>{v0, v1, v2, v3, v4, v5, v6});
std::cout << "testDFS :" << std::endl;
graph.DFS(0);
cout << "test BFS" << endl;
graph.BFS(0);
}