After extensive testing and debugging, I cannot for the life of my find out why my topological sort algorithm produces the incorrect output. It simply lists the values of the nodes in descending order instead of sorting them topologically. I have listed all relevant classes/input files. Any hints or help is appreciated, thanks in advance.
Header for class graph:
/*
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;
};
The cpp file for class graph
/*
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;
}
}
}
The driver for the program
/*
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();
}
And the input file
1: 2
2: 3 8
3: 4
4: 5
5: 9
6: 4 7
7: 3 8
8: 9
9:
Also a visual representation of the graph represented by the adjacency list:
http://i.imgur.com/6fEjlDY.png
I think the main problem was that there was some confusion between the 'real' nodes and the nodes in your adjacency list. At least I got confused, so I split the structure into struct Node and struct Adj. The graph now has a Node* nodes[9] for the nodes.
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;
};
and things almost instantly seem to work. The answer
Sorted List:
6 7 3 4 5 1 2 8 9
seems correct, [6 7 3 4 5] and [1 2 8 9]. See working example here
Please note that there are still numerous issues with the code, esp. with regard to memory management. Consider using a vector<Node> and a std::vector<Adj>. There are also uninitialized variables in the structs.
Related
In the code, I create an adjacency list with an array and each element of the array makes a list with it's adjacent nodes.
To access the array I needed to use ints; however, my vertex names were strings, so I mapped each vertex name to an int counting up from 0. As you can see in the nextNode() function the when a new node is created the'next'node should always be null.
An example result of the adjacency list will look something like this
inputVertices: a,b,c,d
inputEdges: (a,b), (a,d), (b,c) (d,b)
mapping: a<->0, b<->1, c<->2, d<->3
adjacency list:
arr elements| linked lists connected to elements
0 |->b->d
1 |->c
2 |
3 |->b
struct Node {
string vert;
int weight;
Node *next;
};
struct List {
struct Node *head;
};
class Graph {
int vertices;
int edges;
struct List *vertexArray;
int count = 0;
map<string, int> vertList;
public:
Graph(int vertices) {
this->vertices = vertices;
vertexArray = new List[vertices];
for (int i = 0; i < vertices; i++) {
vertexArray[i].head = NULL;
}
}
~Graph() {
vertList.clear();
}
Node *nextNode(string vert) {
Node *newNode = new Node;
newNode->vert = vert;
newNode->weight = 0;
newNode->next = NULL;
return newNode;
}
void addVertex(string vert) {
vertList[vert] = count; //maps Vertex to an integer in the order the Vertex is added
count++;
}
void addEdge(string head, string vert, int weight) {
Node *newNode = nextNode(vert);
newNode->weight = weight;
newNode->next = vertexArray[vertList.at(head)].head;
vertexArray[vertList.at(head)].head = newNode;
}
I stumbled upon my problem while trying to print my adjacency list
here and the program always crashes in the while loop below. It gets
through the first list of nodes fine, but crashes during the second
list.
I figured out the reason is the first list points to everything fine array[0].head->next = node1 node1->next = node2...noden->next = null(this exits the loop), however for the second list something different happens: array[1].head->next = node1 node1->next = node2...noden->next = 0xabababab. The last node should be null, but it is not. I set all new nodes to null. This causes a seg fault and crashes the program.
void print() {
for (int i = 0; i < vertices; i++) {
Node *n = vertexArray[i].head;
for (auto it = vertList.cbegin(); it != vertList.cend(); ++it) {
if ((*it).second == i) { // true if second type in map (aka int) == current array position
cout << (*it).first; //corresponding first type in map
while (n) {
cout << "-> " << n->vert;
n = n->next;
}
cout << endl;
}
}
}
}
Some days ago I wrote this question: See here
Where I asked how to insert elements in a list inside a graph struct.
I've been writing more code and reached a point I cannot move forward.
I am posting the code just to make you have an idea:
//data_structures.h
#include <list>
// A structure to represent an adjacency list node
struct AdjListNode
{
int dest;
int weight;
std::list<int> adjacents;
struct AdjListNode* next;
AdjListNode() : dest(0), weight(0), next(NULL) {}
};
// A structure to represent an adjacency list
struct AdjList
{
struct AdjListNode *head; // pointer to head node of list
//Initialize each adjacency list as empty by making head as NULL
AdjList(): head(NULL) {}
~AdjList()
{
while (head) {
struct AdjListNode* temp = head;
head = head->next;
delete temp;
}
}
void addAdjacent(int adjacent) {
struct AdjListNode* newNode = new AdjListNode;
newNode->next = head;
head = newNode;
newNode->adjacents.push_back(adjacent);
}
};
// A structure to represent a graph. A graph is an array of adjacency lists.
// Size of array will be V (number of vertices in graph)
struct Graph
{
int V;
struct AdjList* array;
// Create an array of adjacency lists. Size of array will be V
Graph(int v) : V(v), array(NULL) {
if(v >= 0) {
array = new struct AdjList[v];
}
else {
throw std::bad_alloc();
}
}
~Graph() {delete [] array;}
};
//main.cpp
int main()
{
// create the graph given in above figure
struct Graph* graph = new Graph(2);
graph->array[0].addAdjacent(1);
graph->array[1].addAdjacent(0);
for(int i = 0; i < graph->V; i++) {
for (list<int>::iterator it = graph->array[i].head->adjacents.begin();
it != graph->array[i].head->adjacents.end(); ++it) {
cout << "Vertex: " << i << " is adjacent to: " << *it << endl;
cout << "Amount: " << graph->array[i].head->adjacents.size() << endl;
cout << endl;
}
}
return 0;
}
As the graph is undirected, the output when zero is connected to 1 and vise-versa (graph->array[0].addAdjacent(1); array1.addAdjacent(0);) is:
Vertex: 0 is adjacent to: 1
Vertex: 1 is adjacent to: 0
However, adding more vertices (let's say, just one more) connected to vertex 0, for instance:
change this:
graph->array[0].addAdjacent(1);
graph->array[1].addAdjacent(0);
by
graph->array[0].addAdjacent(1);
graph->array[1].addAdjacent(0);
graph->array[0].addAdjacent(2);
graph->array[2].addAdjacent(0);
would output this:
Vertex: 0 is adjacent to: 2
Vertex: 1 is adjacent to: 0
Vertex: 2 is adjacent to: 0
What is clearly not correct. It is like vertex 0 is being overwritten, somehow. Any help, please?
First of all ,I am new to graphs.After researching through the concepts of graphs.I thought of implementing in c++. When I searched for implementation i felt it very hard to understand the codes ,So i thought of implementing myself.
Following is the code i tried:
#include<iostream>
using namespace std;
struct Node {
int data;
Node *link;
};
//creating array of nodes
struct Node *array[10];
//creating array of head pointers to point each of the array node.
struct Node *head[10];
//creating array of current pointers to track the list on each array node.
struct Node *cur[10];
void create(int v)
{
for (int i = 0; i < v; i++) {
array[i] = new Node;
head[i] = cur[i] = array[i];
array[i]->data = i;
array[i]->link = NULL;
}
}
void add(int fr, int to)
{
Node *np = new Node;
np->data = to;
np->link = NULL;
if (head[fr]->link == NULL) {
head[fr]->link = np;
cur[fr] = np;
} else {
cur[fr]->link = np;
cur[fr] = np;
}
/*Node* np1=new Node;
np1->data=fr;
np1->link=NULL;
if(head[to]->link==NULL)
{
head[to]->link=np1;
cur[to]=np1;
}else
{
cur[to]->link=np1;
cur[to]=np1;
}*/
}
void print(int a)
{
Node *p = NULL;
p = head[a];
for (; p != NULL; p = p->link)
{ cout << p->data; }
}
main()
{
int a;
cout << "enter the size of array";
cin >> a;
create(a);
//adding edges
add(1, 4);
add(1, 3);
add(0, 3);
add(0, 2);
print(0);
cout << "\n";
print(1);
//print(3);
}
Explanation:
1) Asking the user to enter an integer(no.of vertices),accordingly i am creating an array with requested size.At the same time i am pointing the head and cur pointers to each of the array node. The index number of the array is equal to vertex number.
2)adding edges from one vertex to other by add function. if the head node of a vertex from which an edge emanates is null then i point the head=cur=new node(np),else i am updating cur pointer after each addition. Head will be pointing to the array index node.
3)Printing the edges connected to the requested node.
My questions are:
1)Is this way of implementation right?
2)In the above case lets assume we are connecting vertex 1 and vertex 3.with the above code3 is linked to 1.I wanted to automatically update connection from vertex 3 to vertex 1,So i added the code which is inside the comment section in add function.When i tried running the code it asked me to enter size of array ,i enter some integer it shows me segmentation fault. why?
I'll try to give you the idea.
In an undirected graph every node can be connected to any other node.
This means a node 'points' to any number of other nodes.
In you code instead each node has Node*link; which is a pointer to the next node. You need a list (or an array) of links instead: each node must contain a link to all the node it is connected to. This is the adjacency list. Something like
struct Node
{
int data;
ADJ* adjs; // list of Node*
};
struct ADJ
{
ADJ* next;
Node* data;
};
Here adjs is the list of adjacency.
Also your solution for void print(int a) is more similar to what you would find in a common list. You need to print all the adjacency of a node, i.e. all the node it points to.
Remember that since the graph is undirected you need both the pointert A->B and B->A
After calling create(3) your array looks something like below:
array
0 -> (0,NULL)
1 -> (1,NULL)
2 -> (2,NULL)
3
4
5
6
7
8
9
Segmentation fault occured when add(1,4) is called.
In the first part i.e.
Node *np = new Node;
np->data = to;
np->link = NULL;
if (head[fr]->link == NULL) {
head[fr]->link = np;
cur[fr] = np;
} else {
cur[fr]->link = np;
cur[fr] = np;
}
no problem at all.
Now array looks as shown:
array
0 -> (0,NULL)
1 -> (1,->) (4,NULL)
2 -> (2,NULL)
3
4
5
6
7
8
9
But the Next part is the cause of segmentation fault i.e.
Node* np1=new Node;
np1->data=fr;
np1->link=NULL;
if(head[to]->link==NULL)
{
head[to]->link=np1;
cur[to]=np1;
}else
{
cur[to]->link=np1;
cur[to]=np1;
}
problem is in this line:
head[to]->link==NULL
Here value of to is 4 it means your code trying access link part of head[4] but head[4] is not storing address of valid Node.
Specifically, the goal here is to create a linked structure that has some number of nodes, between 5 and 2 million. Don’t worry that this number is large or that values may wrap around past the max size of integer. If you have created your linked structure correctly, a modern computer can breeze through this code very quickly. Notice that the comments describe exactly how this main should work. Here are the highlights:
Create three loops
The first loop creates the linked structure, hooking together the “next” fields of each node and giving each node an integer value between 0 and the randomly chosen size.
The second loop adds up all of the nodes and counts them. Counting the nodes in this case should be used only as check to make sure you are not missing one.
The third loop traverses all nodes again, this time deleting them.
Node.h
class Node {
public:
Node();
Node(const Node& orig);
virtual ~Node();
bool hasNext();
Node* getNext();
void setNext(Node* newNext);
int getValue();
void setValue(int val);
private:
Node* next;
int value;
};
#endif
Node.cpp
include "Node.h"
include <iostream>
Node::Node() {
next = NULL;
}
Node::Node(const Node& orig) {
next = orig.next;
value = orig.value;
}
Node::~Node() {
}
bool Node::hasNext(){
if (next != NULL)
return true;
else
return false;
}
Node* Node::getNext(){
return next;
}
void Node::setNext(Node* newNext){
if(newNext == NULL)
next = NULL;
else
next = newNext->next;
}
int Node::getValue(){
return value;
}
void Node::setValue(int val){
value = val;
}
main.cpp
include <cstdlib>
include <iostream>
include "Node.h"
include <time.h>
using namespace std;
int main(int argc, char** argv) {
//This is the node that starts it all
Node *tail;
Node* head = new Node();
//select a random number between 5 and 2,000,000
srand(time(NULL));
int size = (rand() % 2000000) + 5;
int total = 0;
int counter = 0;
//print out the size of the list that will be created/destroyed
cout << "The total size is: " << size << endl;
head->setValue(0);
tail = head;
Node *newNode = new Node;
for (int i = 1; i < size; i++){
Node *newNode = new Node;
newNode->setValue(i);
newNode->setNext(NULL);
tail->setNext(newNode);
tail = newNode;
}
//Create a list that counts from 0 to 2,000,000
//Link all of the nodes together
//A for loop is easiest here
cout << head->getNext()->getValue();
Node* current = head;
while (current != NULL){
counter += current->getValue();
cout << current->getValue();
current = current->getNext();
total++;
}
//Traverse the list you created and add up all of the values
//Use a while loop
//output the number of nodes. In addition, print out the sum
//of all of the values of the nodes.
cout << "Tracked " << total << " nodes, with a total count of " << counter << endl;
//Now loop through your linked structure a third time and
//delete all of the nodes
//Again, I require you use a while loop
cout << "Deleted " << total << " nodes. We're done!" << endl;
return 0;
}
It is printing out the total size then...
I am getting a Seg fault:11.
I am also missing some parts in the main, I am confused on how to write these as well.
it should be next = newNext; instead of next = newNext->next;
void Node::setNext(Node* newNext){
if(newNext == NULL)
next = NULL;
else
next = newNext;
}
First of all, avoid using getter functions in your Abstract Data Type. Those should be reserved for your client test application; keep them out of your ADT. Instead, pass any values in as parameters as re: the prototype. Second, avoid void returning methods in your classes. Rather, return a bool or int. Zero or false for error, and true or some non-zero integer for your success message.
That aside, I was looking up ways to use classes to build nodes, and your post came up. Interesting start. We'll see where we go with this.
Ciao,
Lewsutt
I'm trying to wrap my head around how to write an algorithm to sort a linked list, but I'm having a hard time coming up with something that will work. What we need to do have a linked list that contains a name in a string, and an int for hours. After displaying the list and the sum of the hours, we then have to sort the list in ascending order by the hours in a queue. I have the list and all it's functioned stored in a class object, as you will see. I cleared the whole function of what I had in hopes of coming up with a fresh idea but nothing is coming to mind. I initially was going to create a second linked list that had the sorted list, but then I began to wonder if it was possible to sort it within the same list. Here is my code as of posting.
#include <iostream>
#include <ctime>
using namespace std;
// OrderedLL class
template<class T>
class OrderedLL
{
private:
struct NODE
{
string sName;
int sHours;
NODE *next;
};
NODE *list;
NODE *rear;
public:
// Constructor
OrderedLL () { list = rear = NULL;}
// Insert item x -------------------------------------
void Insert(string x, int y)
{
NODE *r;
// Create a new node
r = new(NODE); r->sName = x; r->sHours = y;
r->next = NULL;
// Inserts the item into the list
r->next = list;
list = r;
}
// Display the linked list --------------------------
void display()
{ NODE *p = list;
while( p != NULL)
{ cout << p->sName << "/" << p->sHours << "-->"; p = p->next;}
cout << "NULL\n";
}
// Delete x from the linked list --------------------
void DeleteNode(T x)
{
NODE *p = list, *r = list;
while( p->info != x) {r=p; p=p->next; }
if( p == list)
{ // delete the first node
list = p->next; delete(p);
}
else
{ r->next = p->next; delete(p);}
}
// Sort by hours ------------------------------------
void sortHours()
{
NODE *p, *q;
}
// Display the total hours --------------------------
friend T totHours(OrderedLL LL)
{
NODE *p;
int total = 0;
p = LL.list;
while(p != NULL)
{
total += p->sHours;
p = p->next;
}
cout << "Total spending time = " << total << endl;
}
}; // end of OrderedLL class
int main(void)
{
// Declare variables
time_t a;
OrderedLL<int> unsortedLL;
OrderedLL<int> sortedLL;
int inHours;
string inName;
// Displays the current time and date
time(&a);
cout << "Today is " << ctime(&a) << endl;
// Asks the user to enter a name and hours 5 times, inserting each entry
// into the queue
for(int i = 0; i < 5; i++)
{
cout << "Enter name and Time: ";
cin >> inName >> inHours;
unsortedLL.Insert(inName, inHours);
}
// Displays the unsorted list
cout << "\nWaiting List-->";
unsortedLL.display();
totHours(unsortedLL);
// Calls for the function to sort the list into a queue by hours
unsortedLL.sortHours();
unsortedLL.display();
return 0;
} // End of "main"
As always thanks to anyone who can help
Try sorting the linked-list like you are sorting an integer array. Instead of swapping the nodes, swap the contents inside the nodes.
If you don't care about efficiency you can use any sorting algorithm. What's different between linked lists and arrays is that the swap operation, to swap the position of two elements while sorting, will be a lot slower because it has to run through the links of the list.
An O(n²) bubble sort is easy to implement with a linked list since it only swaps an element with its neighbor.
If you care about efficiency you can look into implementing the merge sort algorithm even if it's a little more complicated.
You should insert like this
void Insert(string x, int y)
{
NODE *r;NODE *temp;
// Create a new node
r = new NODE; r->sName = x; r->sHours = y;r->next = NULL;
if(list==null)//check if list is empty
{
list=r;//insert the node r in the list
}
else
{
temp=list;
while(temp->next!=null)temp=temp->next;//reach to the end of the list
temp->next=r;//insert it at the end of the list
}
}
No need of rear pointer..just check if list->next is null,if yes you are at the end
and your sorthour function should be
void sortHours()
{
for(NODE* n=list;n->next!=null;n=n->next)//get each of the node in list 1 by 1 except the last one i.e. n
{
for(NODE* n1=n->next;n1!=null;n1=n1->next)//compare the list n node with all the nodes that follow it i.e.n1
{
if(n->sHours > n1->sHours)//if one of the node is the less than n
{
//swap n and n1
node temp=*n;
n->age=n1->age;
n->name=n1->name;
n1->age=temp.age;
n1->name=temp.name;
}
}
}
}