2016-02-25 52 views
0

經過廣泛的測試和調試之後,我無法瞭解我的生活爲什麼我的拓撲排序算法會產生不正確的輸出。它只是按降序列出節點的值,而不是對它們進行拓撲排序。我列出了所有相關的類/輸入文件。任何提示或幫助表示感謝,提前感謝。 部首類圖形:C++ topological sort給出不正確的輸出

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

類圖表

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

而且駕駛員cpp文件AV由鄰接表所代表的圖的等式表示: http://i.imgur.com/6fEjlDY.png

+1

當你使用你的調試器時,你發現了什麼?此外,您應該測試一個較小的示例,以便您可以跟蹤代碼(在調試過程中)以查看它出錯的位置。如果你不能對3或4個項目進行排序,那麼嘗試對其中的9個進行排序是沒有意義的。 – PaulMcKenzie

+0

Off topic:如果您必須使用'using namespace std;',[並且您可能不應該](http://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-練習),在包含頭文件之後進行,這樣您就不會冒險在頭文件中炸掉那些希望std名稱空間屬於它的地方的東西。 – user4581301

+0

你是如何代表有多個孩子的節點?例如'7'在你的照片中。 – Barry

回答

0

我認爲主要問題是'真實'節點和鄰接表中的節點之間存在一些混淆。至少我感到困惑,所以我將結構拆分爲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>。結構中還有未初始化的變量。

+0

謝謝!你讓我意識到了這個問題。我很傻,創建了全新的節點,指向鄰接列表,我應該指向實際的節點本身。我改變了我的代碼來初始化構造函數中的節點,然後指向由索引而不是值指定的鄰接列表中的節點。再次感謝我非常感謝您的幫助! – CrazieJester

+0

爲了好玩,我將你的代碼更多地翻了一遍。如果你有興趣,你可以看看[這裏](http://coliru.stacked-crooked.com/a/8a57bbe87ed09fb1)。下一步可能是將'dfs'移出圖形,並給圖形一個'節點'方法來啓用它。 – Thomas