【问题标题】:Topological Sorting Algorithm not working right拓扑排序算法无法正常工作
【发布时间】:2014-05-20 04:45:25
【问题描述】:

好的,我必须对图进行拓扑排序算法。我需要找到度数为 0 的节点并将其排队,然后打印它并删除所有通往它的边缘。我通过减少 countList 映射中进入边缘的数量来移除边缘。我将邻接列表作为地图,并将每个节点的度数作为地图。我的算法只访问邻接列表的第一个元素。所以我的输出队列只显示邻接列表映射的第一个键。一遍又一遍。我在 25 处停止了 while 循环,所以它不会是无限的。

            string z = "";
            string a = "";
            cout << "Queue: ";
            do{
                for(it = countList.begin(); it!=countList.end(); ++it){
                    if(it->second == 0){
                        Q.push(it->first);
                                                    countList.at(it->first)--;
                        z = adjList[it->first];
                        cout <<"z: " << z <<endl;
                        //remove edges
                        for(int i = 0; i< z.length(); i++){
                            a = z.at(i);
                            cout << "z at " <<i << " : " <<a <<endl;
                            countList.at(a)--;
                        }//end for
                    }//end if
                    //cout << Q.front() << ", ";
                    //Q.pop();

                }//end for
                cout << Q.front() << ", ";
                Q.pop();
            }while(!Q.empty());

有人可以帮助我理解为什么它没有遍历 countList 并且只停留在第一个元素上吗?

谢谢。

所以我将 countList.at(a)-+1 更改为 countList.at(a)-- 以进行适当的递减。 现在输出不仅仅是度数为 0 的第一个顶点。但是输出仍然是错误的。

这就是全部。 我的变量声明

    vector<string> E;   
map<string, string> adjList;
map<string, int>countList;
map<string, int>::iterator it;
queue<string> Q;

我不想贴出 adjacencyList 或 countList 的代码,但这是它们的外观。

//These represent the edges between the two paired nodes
AdjacencyList: (1,2) (1,4) (1,3) (2,4) (2,5) (3,6) (4,6) (4,7) (4,3) (5,4) (5,7) (7,6)

//The first is the node name and the second element is how many edges come into that node.
countList: (1,0) (2,1) (3,2) (4,3) (5,1) (6,3) (7,2)

我的输出应该是:

Queue: 1,2,5,4,3,7,6 
//or
Queue: 1,2,5,4,7,3,6

好的,我添加了

countList.at(it->first)--;

在我将顶点推入队列之后。所以这应该将该顶点的计数减少到-1。 这大大缩小了我的输出范围。

好的,现在可以使用了!!! 我将while循环更改为在队列为空后停止并在while循环中打印队列并解决了问题。

我现在的输出是:

Queue: 1, 2, 5, 4, 7, 3, 6, 

好的,此代码仅在节点名称仅为单个值时才有效。 对于节点名称长于单个字符的值,我将如何更改 adjList 映射? 也许键值指向一个链表?如果是这样,我该怎么做?

【问题讨论】:

  • 除非您保证只有一个入度为 0 的节点(一般情况下不是这样),否则我认为您的基本方法是有缺陷的。如果您有一组关系{ (a,b), (c,b) },则ac 的入度都为0,但是在处理它们之前不能处理它们中的任何一个(正确的顺序)将是 a, c, bc, a, b)...
  • 我不知道这是否是为了研究,但有现有的算法。 boost.org/doc/libs/1_42_0/libs/graph/doc/topological_sort.html
  • “countList”的声明是什么?我怀疑“countList.at(a)-+1”行不正确——它似乎没有减少计数器。
  • 你能包含完整的输出吗?

标签: c++ sorting loops graph topological-sort


【解决方案1】:

好的,现在我们到了某个地方。

第一个版本(在您编辑之前)确实错误地减少了传入的边数。

现在还有另一个问题:在每次迭代中,您重复地选取已经被选取的节点(节点 #1 是一个很好的例子),因为它们的计数仍然为零(传入边的数量)。通过一次又一次地递减它们的祖先,一些计数将降至零以下(例如节点 #2)。

您必须以某种方式标记已使用的节点,并且不要在每个循环中一次又一次地使用它们。这可以通过 a) 为节点设置一些标志来实现,b) 使用一组已使用的节点,c) 通过从列表中删除节点,或者(可能是最简单的)d) 通过将它们的边数设置为负数将它们放入输出队列后的数字(例如,-1)。

在您的第二次编辑之后,这样的算法应该可以工作(经过一些小的 tweek 后它对我有用)。但是,adjList 的用法很奇怪——如何将一个节点的多条边准确地包含到地图中?

【讨论】:

  • 我使用了字符串映射。其中键值是节点名称,第二个字符串值是边缘的连接字符串。然后我将字符串拆分为其他节点的名称。这仅在节点名称是单个值时才有效。我才意识到这一点。那么如果节点的名称不止一个值,我将如何映射它们呢?我可以将链表作为键的映射值吗?它看起来像这样 (1, 234)
  • 是的,你可以这样做。或者您可以使用多张地图。
猜你喜欢
  • 2018-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-26
  • 2018-06-23
  • 1970-01-01
  • 2020-12-14
相关资源
最近更新 更多