топологическая сортировка c ++ дает неправильный вывод

После тщательного тестирования и отладки я не могу понять, почему мой алгоритм топологической сортировки дает неверный результат. Он просто перечисляет значения узлов в порядке убывания вместо того, чтобы сортировать их топологически. Я перечислил все соответствующие классы / входные файлы. Любые подсказки или помощь приветствуются, заранее спасибо. Заголовок для графа классов:

/*
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;
};

Файл 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;
        }
    }
}

Драйвер для программы

/*
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


person CrazieJester    schedule 25.02.2016    source источник
comment
Что вы узнали, когда использовали свой отладчик? Кроме того, вы должны протестировать меньший образец, чтобы вы могли следить за своим кодом (во время отладки), чтобы увидеть, где он идет не так. Если вы не можете отсортировать 3 или 4 элемента, нет смысла пытаться отсортировать 9 из них.   -  person PaulMcKenzie    schedule 25.02.2016
comment
Не по теме: если вы должны использовать using namespace std;, и вам, вероятно, не следует, сделайте это после включения заголовков, чтобы не рисковать взорвать содержимое внутри заголовков, ожидающее, что пространство имен std будет там, где оно принадлежит.   -  person user4581301    schedule 25.02.2016
comment
Как вы представляете узел, имеющий несколько дочерних элементов? например 7 на твоей картинке.   -  person Barry    schedule 25.02.2016
comment
Я использую список смежности для представления узла, имеющего несколько дочерних узлов. Например, указатель следующего узла узла 7 будет 3, тогда указатель следующего узла 3 будет 8 - @Barry   -  person CrazieJester    schedule 25.02.2016
comment
Спасибо за подсказку user4581301, буду иметь это в виду.   -  person CrazieJester    schedule 25.02.2016
comment
@CrazieJester Не уверен, что ты когда-нибудь навещал всех детей.   -  person Barry    schedule 25.02.2016
comment
PaulMcKenzie, используя отладчик, может показаться, что в функции DFSVisit блок else if (v- ›color == 'w') никогда не выполняется, но я не уверен, как это исправить. Кроме того, я попробовал это с меньшим файлом, и он работает так же, где он просто помещает узлы в порядке убывания.   -  person CrazieJester    schedule 25.02.2016
comment
@Barry Хм, почему ты так говоришь? Я сделал так, чтобы каждый головной узел в списке смежности отслеживал, сколько у него ребер, а затем цикл for в DFSVisit выполняется несколько раз в зависимости от этого числа, разве тогда он не должен посещать каждое ребро? А почему бы и нет?   -  person CrazieJester    schedule 26.02.2016
comment
then 3's next node pointer would be 8: но следующая тройка на графике - 4. Вам нужен список смежности для каждого узла.   -  person Thomas    schedule 26.02.2016
comment
@Thomas: Да, я просто имел в виду, что для этого индекса массива головок узлов, если вы посмотрите на заголовок графа, у меня есть adj [9], который содержит головной узел для каждого списка смежности, поэтому он настроен таким образом.   -  person CrazieJester    schedule 26.02.2016


Ответы (1)


Я думаю, что основная проблема заключалась в том, что была некоторая путаница между «реальными» узлами и узлами в вашем списке смежности. По крайней мере, я запутался, поэтому разбил структуру на struct Node и struct 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]. См. Рабочий пример здесь

Обратите внимание, что по-прежнему существует множество проблем с кодом, особенно. что касается управления памятью. Рассмотрите возможность использования vector<Node> и std::vector<Adj>. В структурах также есть неинициализированные переменные.

person Thomas    schedule 26.02.2016
comment
Спасибо вам большое! Вы заставили меня осознать проблему. Я поступил глупо и создал совершенно новые узлы, чтобы указать на них в списке смежности, где я должен был указывать на сами узлы. Я изменил свой код, чтобы инициализировать узлы в конструкторе, а затем указать на узел в списке смежности, заданный индексом, а не значением. Еще раз спасибо, я очень признателен за вашу помощь! - person CrazieJester; 26.02.2016
comment
Ради интереса я еще немного накачал ваш код. Если вам интересно, вы можете посмотреть здесь. Следующим шагом могло бы быть перемещение dfs из графика и присвоение графику node метода, позволяющего это сделать. - person Thomas; 26.02.2016