找到你要的答案

Q:Finding the number of edges and performing a topo sort in my graph implementation

Q:发现边数,在我的图进行拓扑排序的实现

I have been working on a graph implementation for the last few days. All of this is really new to me, and I am stuck on two parts of my implementation. I am implementing a digraph of courses from an input file. From the file, I can determine which courses are prereqs for other courses. I then create a digraph with courses as nodes, and edges connecting courses that are prereqs. I also want to find the total number of nodes and edges, and perform a topological sort on the graph (I will later be adding weights to the edges). Here is my implementation.

Finding the number of nodes was easy just return work.size. I have confirmed this is working properly. I am lost on how I would return the number of edges in my graph. It seems it would be simple, but everything I tried doesn't work. Secondly, I am completely lost on how to perform a topological sort on this graph. Any assistance is appreciated.

最近几天我一直在做一个图形实现。所有这一切对我来说真的是新的,我坚持我的两部分执行。我是一个有向图实现从输入文件课程。从文件中,我可以确定哪些课程是其他课程的前提。然后我创建一个课程为节点的有向图,连接课程,前提的边缘。我还想查找节点和边的总数,并在图上执行拓扑排序(稍后我将增加边的权重)。以下是我的实现。

发现节点数很容易就返回work.size。我已经确认这是正常工作。我丢失了如何返回我图形中的边数。似乎很简单,但我尝试的一切都不起作用。其次,我完全迷失了如何在这个图形上执行拓扑排序。任何协助是赞赏。

answer1: 回答1:

First, for the number of edges, it would be simpler to count them directly when you build the graph (just add a counter in your Digraph class and increment it each time you add an edge … )

For the topological sort, first I have a question: your edges are from prereqs to dependant courses ? That is you have a link A -> B if A is a prereq of B ? If this not the case, you need to invert your graph.

You to main algorithm in order to build a topological sort: one based on a simple DFS (http://en.wikipedia.org/wiki/Depth-first_search) and the other relying on in-degrees (http://en.wikipedia.org/wiki/Directed_graph#Indegree_and_outdegree) of your vertices (courses in your case.)

Normally, you need to verify that your graph doesn't contain any cycle, which will normally be the case if your data are coherent.

Let's consider the DFS based algorithm: a DFS traverses each vertices from a given root following edges as they appear. We can easily prove that order of last encounter of a vertex forms a reverse topological order. So, all we need is to push in a stack the current vertex after the calls on its successors.

I made a quick and dirty implementation for you, using C++11 again.

First, add the following to the Digraph class:

  typedef std::unordered_set<vertex*> marks_set;
  marks_set marks;
  typedef std::deque<vertex*> stack;
  stack topo;
  void dfs(vertex* vcur);

Then here comes the code:

void Digraph::dfs(vertex* vcur) {
  marks.insert(vcur);
  for (const auto & adj : vcur->adjacency) {
    vertex* suc = adj.second;
    if (marks.find(suc) == marks.end()) {
      this->dfs(suc);
    } // you can detect cycle in the else statement
  }
  topo.push_back(vcur);
}

void Digraph::getTopoSort() {
  // It should be a good idea to separate this algorithm from the graph itself
  // You probably don't want the inner state of it in your graph,
  // but that's your part.

  // Be sure marks and topo are empty
  marks.clear();
  topo.clear();
  // Run the DFS on all connected components
  for (const auto & v : work) {
    if (marks.find(v.second) == marks.end()) {
      this->dfs(v.second);
    }
  }
  // Display it
  for (const auto v : topo) {
    std::cout << v->course << "\n";
  }
}

The code compiles but I haven't tested. If for any reasons you have an issue with the recursive algorithm (the function Digraph::dfs), it can be derecursified using a stack containing the parent of the target vertex and the iterator to the current successor, the iterator reach the end of the adjacency list, you can push the parent in the topological sort.

The other algorithm is almost as simple: for each vertices you need to count the number of predecessor (in-degree) which can be done while building the graph. In order to compute the topological sort, you look for the first vertex with a in-degree of 0 (no predecessor), you then decrease the in-degree of all its successors and continue with the next vertex with 0. If the graph has no cycle, there will always be a vertex with a in-degree of 0 (at beginning of course, but also during the algorithm run as you decrease it) until all vertices have been seen. The order of vertices encounter form a topological sort (this is related to the Bellman shortest-path algorithm.)

Note that these 2 algorithms are listed here: http://en.wikipedia.org/wiki/Topological_sorting. The one using in-degree is described in terms of removing edges which we simply simulate by decreasing the in-degree (a far less destructive approach … )

首先,对于边数,会简单的计数时直接建立图(只需添加一个计数器在您的图类,增加每次添加一个边缘…)

对于拓扑排序,首先我有一个问题:你的边从前提到相关的课程?那是你有一个链接- >;如果A是一个先决条件B?如果不是这样的话,你需要反转你的图形。

你的主要算法构建的拓扑排序:一个简单的基于DFS(http://en.wikipedia.org/wiki/depth-first_search)和其他依赖度(http:/ /恩。维基百科。org /维基/ directed_graph # indegree_and_outdegree)你的顶点(在你的案子。课程)

通常情况下,您需要验证您的图表不包含任何循环,通常情况下,如果您的数据是一致的。

让我们考虑算法DFS:DFS遍历每个顶点从一个给定的根下面的边缘出现。我们可以很容易地证明,一个顶点的最后相遇的顺序形成一个反向拓扑秩序。所以,我们只需要在继承人的调用之后推入当前顶点的堆栈。

我为你做了一个快速和肮脏的实现,使用C++ 11次。

首先,添加下面的图类:

  typedef std::unordered_set<vertex*> marks_set;
  marks_set marks;
  typedef std::deque<vertex*> stack;
  stack topo;
  void dfs(vertex* vcur);

然后代码来了:

void Digraph::dfs(vertex* vcur) {
  marks.insert(vcur);
  for (const auto & adj : vcur->adjacency) {
    vertex* suc = adj.second;
    if (marks.find(suc) == marks.end()) {
      this->dfs(suc);
    } // you can detect cycle in the else statement
  }
  topo.push_back(vcur);
}

void Digraph::getTopoSort() {
  // It should be a good idea to separate this algorithm from the graph itself
  // You probably don't want the inner state of it in your graph,
  // but that's your part.

  // Be sure marks and topo are empty
  marks.clear();
  topo.clear();
  // Run the DFS on all connected components
  for (const auto & v : work) {
    if (marks.find(v.second) == marks.end()) {
      this->dfs(v.second);
    }
  }
  // Display it
  for (const auto v : topo) {
    std::cout << v->course << "\n";
  }
}

代码编译但我没有测试。如果你用递归算法有问题的任何原因(功能图::DFS),它可以derecursified使用堆栈包含目标顶点母和迭代器的继任者,迭代器实现邻接表的结束,您可以按拓扑排序的父。

另一种算法几乎是一样简单:对于每个顶点,你需要计算的数目的前身(程度),可以在建立图形。为了计算拓扑排序,你寻找的第一个顶点的程度为0(没有前身),然后减少其所有继承人的程度,并继续与下一个顶点与0。如果图没有循环,总是会有一个顶点的度为0(当然在开始,但也在算法运行,因为你减少它),直到所有的顶点已经看到。顶点顺序相遇形成一个拓扑排序(这是服务员最短路径的算法。相关)

请注意,这2种算法如下:http://en.wikipedia.org/wiki/topological_sorting。在程度上的一个描述中除去边缘,我们简单地模拟通过减少的程度(远破坏性的方法…)

answer2: 回答2:

A simple way would be to iterate through all vertices in your graph, add up their neighbor counts and then divide by two:

int Digraph::getNumEdges(){
     int count = 0;
     for (const auto & v : work) {
         count += v.second->adjacency.size();
     }
     return count / 2;
}

To use the range based for loop, you need to use c++11. With g++ that would be --std=c++11 on the command line.

EDIT: I just realized you have a directed graph, and you probably want to count one for each direction. In such case: don't divide by two!

int Digraph::getNumEdges(){
     int count = 0;
     for (const auto & v : work) {
         count += v.second->adjacency.size();
     }
     return count;
}

一个简单的方法就是在你的图的遍历所有顶点,添加了他们的邻居数,然后除以2:

int Digraph::getNumEdges(){
     int count = 0;
     for (const auto & v : work) {
         count += v.second->adjacency.size();
     }
     return count / 2;
}

使用基于环的范围,你需要使用C++ 11。G + +将性病= C++ 11在命令行。

EDIT: I just realized you have a directed graph, and you probably want to count one for each direction. In such case: don't divide by two!

int Digraph::getNumEdges(){
     int count = 0;
     for (const auto & v : work) {
         count += v.second->adjacency.size();
     }
     return count;
}
c++  graph  graph-algorithm  topological-sort