割点迭代算法

问题描述 投票:0回答:1

我需要将Trajan的递归算法转换为Trajan的迭代算法。我有一个类Graph,它包含几个方法和字段,这是需要的基本结构

class Graph {
protected:
 vector< vector<int> > adjList;
 int n;

这就是递归代码的样子

void DFSforTarjan(int u, vector<bool>& visited,
    set<int>& AP, vector<int>& disc, vector<int>& low, int& time, int parent) {

    int children = 0;
    visited[u] = true;
    disc[u] = low[u] = ++time;
    for (int v : this->getNeighborVertex(u)) {
        if (!visited[v]) {
            children++;
            DFSforTarjan(v, visited, AP, disc, low, time, u);
            low[u] = min(low[u], low[v]);
            if (parent != -1 && low[v] >= disc[u])
                AP.insert(u);
        }
        else if (v != parent)
            low[u] = min(low[u], disc[v]);
    }
    if (parent == -1 && children > 1)
        AP.insert(u);
}

这是我尝试迭代实现的代码,但它不能正常工作,请帮忙

void DFSforTarjan(int u, vector<bool>& visited,
    set<int>& AP, vector<int>& disc, vector<int>& low, vector<int>& parent, vector<int>& children, int& time) {

    stack<int> st;
    st.push(u);
    
    while (!st.empty()) {
        u = st.top();
        st.pop();

        if (parent[u] != -1) {
            children[parent[u]]++;
        }
        visited[u] = true;
        disc[u] = low[u] = ++time;

        for (int v : this->getNeighborVertex(u)) {
            if (!visited[v]) {
                st.push(v);
                parent[v] = u;
                visited[v] = true;
            }
            else if (v != parent[u]) {
                low[u] = min(low[u], disc[v]);
            }
        }

        if (parent[u] == -1 && children[u] > 1)
            AP.insert(u);

        if (parent[u] != -1 && low[u] >= disc[parent[u]])
            AP.insert(parent[u]);
    }
    for (int v : this->getNeighborVertex(u)) {
        if (v != parent[u] && visited[v]) {
            low[u] = min(low[u], low[v]);
        }
    }
}
c++ algorithm graph tarjans-algorithm
1个回答
0
投票

设计递归函数时,尽量减少堆栈内存的使用非常重要。因此,通过使递归函数成为类的方法来减少每次调用时使用的参数数量。

这是一个仅使用三个参数实现 Tarjan 的类的定义。

       /// @brief Find articulation points in an undirected graph
        /// An articulation point is a vertex whose removal
        /// increases the number of connected components in the graph.

        class cTarjan
        {
        public:
            /// @brief Find articulation points with Tarjan's algorithm
            /// @param gd undirected graph description ( directed will raise exception )
            /// @return vector of articulation point names

            std::vector<std::string> ArticulationPoints(sGraphData &gd);

        private:
            std::vector<bool> visited; // true if vertex index has been visited
            std::vector<int> disc;     // discovery times of visited vertices
            std::vector<int> low;      // earliest visited vertex (the vertex with minimum
                                       // discovery time) that can be reached from subtree
                                       // rooted with vertex
            std::set<int> sAP;         // set of articulation point vertex indices

            /// @brief Recursive search graph for articulation points
            /// @param gd graph description
            /// @param time current time
            /// @param parent vertex index to start search from

            void APRecurse(
                sGraphData &gd,
                int &time, int parent);
        };

这是实现

        std::vector<std::string> cTarjan::ArticulationPoints(sGraphData &gd)
        {
            if (gd.g.isDirected())
                throw std::runtime_error(
                    "Tarjan works only for undirected graphs");

            visited.clear();
            visited.resize(gd.g.vertexCount(), false);
            disc.clear();
            disc.resize(gd.g.vertexCount(), 0);
            low.clear();
            low.resize(gd.g.vertexCount(), 0);
            sAP.clear();

            std::vector<std::string> vAP;
            int time = 0, parent = -1;

            // Adding this loop so that the
            // code works even if we are given
            // disconnected graph
            for (int u = 0; u < gd.g.vertexCount(); u++)
                if (!visited[u])
                {
                    gd.startName = gd.g.userName(u);
                    APRecurse(
                        gd,
                        time, parent);
                }

            for (int p : sAP)
                vAP.push_back(gd.g.userName(p));

            return vAP;
        }

        // find articulation points in an undirected graph

        // A recursive function that find articulation
        // points using DFS traversal
        // adj[] --> Adjacency List representation of the graph
        // u --> The vertex to be visited next
        // visited[] --> keeps track of visited vertices
        // disc[] --> Stores discovery times of visited vertices
        // low[] -- >> earliest visited vertex (the vertex with minimum
        // discovery time) that can be reached from subtree
        // rooted with current vertex
        // parent --> Stores the parent vertex in DFS tree
        // sAP[] --> Stores articulation points
        void cTarjan::APRecurse(
            sGraphData &gd,
            int &time, int parent)
        {
            int u = gd.g.find(gd.startName);

            // Count of children in DFS Tree
            int children = 0;

            // Mark the current node as visited
            visited[u] = true;

            // Initialize discovery time and low value
            disc[u] = low[u] = ++time;

            // Go through all vertices adjacent to this
            for (auto v : gd.g.adjacentOut(u))
            {
                // If v is not visited yet, then make it a child of u
                // in DFS tree and recur for it
                if (!visited[v])
                {
                    children++;
                    sGraphData gd2;
                    gd2 = gd;
                    gd2.startName = gd.g.userName(v);
                    APRecurse(
                        gd2, time, u);

                    // Check if the subtree rooted with v has
                    // a connection to one of the ancestors of u
                    low[u] = std::min(low[u], low[v]);

                    // If u is not root and low value of one of
                    // its child is more than discovery value of u.
                    if (parent != -1 && low[v] >= disc[u])
                        sAP.insert(u);
                }

                // Update low value of u for parent function calls.
                else if (v != parent)
                    low[u] = std::min(low[u], disc[v]);
            }

            // If u is root of DFS tree and has two or more children.
            if (parent == -1 && children > 1)
                sAP.insert(u);
        }

完整代码和文档位于 https://github.com/JamesBremner/PathFinder

© www.soinside.com 2019 - 2024. All rights reserved.