1. 程式人生 > >C++ dijkstra 最短路徑演算法、top排序、DFS、BFS 示例 C++11

C++ dijkstra 最短路徑演算法、top排序、DFS、BFS 示例 C++11

好一段時間前寫的了。。。正好現在在複習資料結構,重構了一下程式碼

首先先是 圖、點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);
    }