c ++拓扑排序给出不正确的输出

c++ topological sort giving incorrect output

经过广泛的测试和调试,我终其一生都无法找出我的拓扑排序算法产生错误输出的原因。它只是按降序列出节点的值,而不是按拓扑对它们进行排序。我列出了所有相关的 classes/input 文件。任何提示或帮助表示赞赏,在此先感谢。 Header 对于 class 图:

/*
2/19/2016
This is the header for class graph.  It includes the definition of a node
and the function signatures
*/
#pragma once

#include <iostream>

using namespace std;

struct node
{
    // actual value at each node
    int value;
    // discovered time
    int d;
    // finished time
    int f;
    // keep track of how many edges each vertex has
    int numEdges;
    // keep track of color of node
    char color;
    // parent (previous) node
    node* p;
    // next node
    node* next;
};


// Class to represent a graph
class Graph
{
public:
    // constructor, give number of vertexes
    Graph(int V);

    // depth first search
    void DFS();

    // function to print sorted nodes
    void print();

    // function for reading file into adjacency list
    void readFile(istream& in);

private:
    // private function called in depth first search, visits every vertex
    // of each edge in the graph
    void DFSVisit(node* u);

    // number of vertices
    int V;

    // array of node pointers, first node in each array is
    // the vertex and following nodes are edges
    node* adj[9];

    // linked list to keep track of the sorted list found from depth first search
    node* sorted;

    // keep track of when each node is discovered/finished
    int time;

    // keep track of number of backedges
    int backEdge;
};

class 图的 cpp 文件

/*
2/19/2016
This is the cpp file for class graph.  It defines function behavior
*/

#include "Graph.h"

using namespace std;

#include <iostream>
#include <string>

Graph::Graph(int V)
{
    // set graph's number of vertexes to number input
    this->V = V;
    this->backEdge = 0;
}


// Depth first search
void Graph::DFS()
{
    // initialize all colors to white and parent to null
    for (int i = 0; i < V; i++)
    {
        adj[i]->color = 'w';
        adj[i]->p = NULL;
    }
    // initialize time to 0
    time = 0;
    // for each vertex, if it is white, visit its adjacent nodes
    for (int i = 0; i < V; i++)
    {
        if (adj[i]->color == 'w') {
            DFSVisit(adj[i]);
        }
    }
}

// Visit node used by depth first search
void Graph::DFSVisit(node* u)
{
    // increment time
    time++;
    // set u's discovered time
    u->d = time;
    // set color to grey for visited but not finished
    u->color = 'g';
    // visit each adjacency, number of adjacencies stored by numEdges
    for (int i = 0; i < u->numEdges; i++)
    {
        // create node pointing at u next
        node* v = u->next;
        // if the node is already grey, then it is a backedge
        if (v->color == 'g') {
            backEdge++;
        }
        // if it is white and undiscovered, set its parent to u and visit v's next nodes
        else if (v->color == 'w') {
            v->p = u;
            DFSVisit(v);
        }
    }
    // set last node to black
    u->color = 'b';
    // increment time
    time++;
    // set finishing time
    u->f = time;

    if (backEdge == 0) {
        // adds a node to front of linked list that contains sorted values
        node* newNode = new node;
        newNode->next = sorted;
        newNode->value = u->value;
        sorted = newNode;
    }
}

void Graph::print()
{
    if (backEdge == 0) {
        node* curr = sorted;
        if (sorted == NULL) {
            return;
        }
        else {
            cout << "Sorted List:\n";
            for (; curr; curr = curr->next)
            {
                cout << curr->value << " ";
            }
            cout << endl;
        }
    }
    else cout << "Backedges: " << backEdge << endl;
}

void Graph::readFile(istream& in)
{
    // create node pointers to use later
    node* head;
    node* prev;
    node* curr;

    // temp string to use while reading file
    string temp;
    int j;
    // loop iterate vertex number of times
    for (int i = 0; i < V; i++)
    {
        // 3rd character in string holds name of first edge
        j = 3;
        // read line by line
        getline(in, temp);

        // debug print out adjacency list
        // cout << temp << endl;

        // create head node, set value to value of vertex, put it at beginning of each linked list
        head = new node;
        head->value = i + 1;
        adj[i] = head;
        // set numEdges to 0 when row is started
        adj[i]->numEdges = 0;
        // set prev to head at end of each outer loop
        prev = head;

        // read every adjacency for each vertex, once j goes outside of string reading is done
        while (j < temp.length()) {
            // increment numEdges, meaning vertex has one more adjacency
            adj[i]->numEdges++;
            // create node and put in value, found by moving j up two spaces and subtracting 48
            // because it is a char casted as an int
            curr = new node;
            curr->value = (int)temp.at(j) - 48;
            // connect node, increment j by 2 because adjacencies separated by a whitespace
            prev->next = curr;
            prev = curr;
            j += 2;
        }
    }
}

driver为程序

/*
2/19/2016
This is the driver for the topological sort project.  It reads a file of
vertexes and edges into an adjacency list and performs a depth first
search on that graph representation, creating a topological sort
if no backedges exist, this indicates a DAG or directed acyclic graph
if backedges do exist, this indicates a graph containing cycles meaning
it cannot be topologically sorted
*/

#include <iostream>
#include <fstream>
#include <string>
#include "Graph.h"

using namespace std;

string FILE_NAME = "graphin-DAG.txt";
int NUM_VERTICES = 9;

int main()
{
    // create graph object giving number of vertices
    Graph myGraph(NUM_VERTICES);

    // open file
    ifstream fin(FILE_NAME);

    // validate that file was successfully opened, without file print
    // error and exit program
    if (!fin.is_open()) {
        cerr << "Error opening " + FILE_NAME + " for reading." << endl;
        exit(1);
    }

    // read file into adjacency list
    myGraph.readFile(fin);

    // perform depth first search
    myGraph.DFS();

    // if graph is a DAG, print topological sort, else print backedges
    // this is handled by the print function checking backedges data member
    myGraph.print();
}

和输入文件

1: 2
2: 3 8
3: 4
4: 5
5: 9
6: 4 7
7: 3 8
8: 9
9:

也是邻接表表示的图的直观表示: http://i.imgur.com/6fEjlDY.png

我认为主要问题是 'real' 节点和邻接列表中的节点之间存在一些混淆。至少我弄糊涂了,所以我将结构拆分为 struct Nodestruct Adj。该图现在有一个 Node* nodes[9] 节点。

struct Node;

struct Adj
{
    Node*  node;
    Adj*   next;
};


struct Node
{
    // actual value at each node
    int value;
    // discovered time
    int d;
    // finished time
    int f;
    // keep track of color of node
    char color;
    // the list od adjacencies for the node
    Adj*  adj;
};

而且事情似乎立即奏效。答案

Sorted List:
6 7 3 4 5 1 2 8 9

似乎是正确的,[6 7 3 4 5][1 2 8 9]。请参阅工作示例 here

请注意,代码仍然存在许多问题,尤其是。关于内存管理。考虑使用 vector<Node>std::vector<Adj>。结构中也有未初始化的变量。