【问题标题】:Topological Sort using Iteration instead of Recursion使用迭代而不是递归的拓扑排序
【发布时间】:2016-06-17 18:08:05
【问题描述】:

我最初有这个用于拓扑排序的递归解决方案:

void dfs(int v, bool visited[], node* adjList[], std::stack<int> &myStack) {
    visited[v] = true;
    node* curr = adjList[v];

    while (curr != NULL) {
        if(!visited[curr->val]) {
            dfs(curr->val, visited, adjList, myStack);
        }
        curr = curr->next;
    }
    myStack.push(v);
}

它似乎对我的目的有效。但是我在将其转换为迭代解决方案时遇到了麻烦。这是我的尝试:

void dfs(int v, bool visited[], node* adjList[], std::stack<int> &myStack) {
    std::stack<int> recursion;
    visited[v] = true;

    recursion.push(v);

    while( !recursion.empty() ) {
        v = recursion.top();
        recursion.pop();
        node* curr = adjList[v];

        myStack.push(v);

        while (curr != NULL) {
            if(!visited[curr->val]) {
                visited[curr->val] = true;
                recursion.push(curr->val);
            }
            curr = curr->next;
        }
    }
}

但是顺序完全乱了!我认为这可能是由于我的myStack.push(v) 的定位,但我不知道如何处理这个问题。任何帮助将不胜感激。

【问题讨论】:

  • 我在过去的几天里想,诀窍通常是反转递归退出条件并将其用于非递归函数的 while 条件。然后,我推测,您可以保留大部分旧逻辑。
  • @BitTickler 你这是什么意思?
  • 主要区别在于递归中visited的状态不同,而在迭代版本中你只修改一个这样的列表,并且在回溯时取消设置visited

标签: c++ recursion graph depth-first-search topological-sort


【解决方案1】:

我想我解决了自己的问题。本质上,您可以通过按完成时间对节点进行排序来获得拓扑顺序。但是,我们可以将其保持为 O(n),而不是进行排序并获得 O(nlogn) 解决方案。当您完成一个节点时,我们可以将节点的唯一标识符弹出到堆栈中,而不是记录其完成时间。由于在我的情况下我们只处理正顶点,因此将唯一标识符简单地设置为顶点值的负值就足够了。因此,如果我们连续弹出堆栈,我们将获得拓扑顺序。

 void dfs(int v, bool visited[], node* adjList[], std::stack<int> &myStack) {
     std::stack<int> recursion;
     visited[v] = true;
     recursion.push(v);

     while( !recursion.empty() ) {
        v = recursion.top();
        recursion.pop();

        //A dummy node to denote finish order (e.g. topological order)
        if (v < 0) {
            myStack.push(v * -1);
        } else {
            node* curr = adjList[v];
            recursion.push(v * -1);

             while (curr != NULL) {
                if(!visited[curr->val]) {
                    visited[curr->val] = true;
                    recursion.push(curr->val);
                }
                curr = curr->next;
            }
        }
    }
}

【讨论】:

  • 这个答案对我来说效果很好。你的符号翻转技巧真的很聪明,正如你提到的,所有条目都大于 0,这绝对是我的情况。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-21
  • 1970-01-01
  • 2021-07-28
  • 1970-01-01
相关资源
最近更新 更多