So I need to do a depth first search traversal of a given graph, however if a node in the graph has multiple adjacent neighbours, I need to choose the node with the lowest value to go to. So I implemented the following recursive depth first search function:
void DFS(struct Graph *graph, int vertex) {
struct node *adjList = graph->adjLists[vertex];
struct node *temp = adjList;
graph->visited[vertex] = 1;
printf("Visited %d \n", vertex);
int neighbouring_nodes[graph->numVertices];
while (temp != NULL) {
int count = 0;
struct node *temp_cpy = temp;
while (temp_cpy != NULL) {
neighbouring_nodes[count] = temp_cpy->vertex;
count++;
temp_cpy = temp_cpy->next;
}
int smallest_node = neighbouring_nodes[0];
for (int i = 0; i < count; i++) {
if (neighbouring_nodes[i] < smallest_node) {
smallest_node = neighbouring_nodes[i];
}
}
if (graph->visited[smallest_node] == 0) {
DFS(graph, smallest_node);
} else if (graph->visited[smallest_node] == 1 && count == 1) {
//if the node is visited but is it the only neighbour
DFS(graph, smallest_node);
}
temp = temp->next;
}
}
But when I run my program, it results in an infinite loop. I think I know why I am getting an infinite loop, it might be because there is never a return condition, so the recursive function just keeps running?
Is this type of depth first search possible with a recursive function? If yes, where am I going wrong? If no, how would I do it iteratively?
Help would be much appreciated.
Below is my full program without the DFS function:
// DFS algorithm in C
#include <stdio.h>
#include <stdlib.h>
struct node {
int vertex;
struct node *next;
};
struct node *createNode(int v);
struct Graph {
int numVertices;
int *visited;
struct node **adjLists;
};
// Create a node
struct node *createNode(int v) {
struct node *newNode = malloc(sizeof(struct node));
newNode->vertex = v;
newNode->next = NULL;
return newNode;
}
// Create graph
struct Graph *createGraph(int vertices) {
struct Graph *graph = malloc(sizeof(struct Graph));
graph->numVertices = vertices;
graph->adjLists = malloc(vertices * sizeof(struct node*));
graph->visited = malloc(vertices * sizeof(int));
int i;
for (i = 0; i < vertices; i++) {
graph->adjLists[i] = NULL;
graph->visited[i] = 0;
}
return graph;
}
// Add edge
void addEdge(struct Graph *graph, int src, int dest) {
// Add edge from src to dest
struct node *newNode = createNode(dest);
newNode->next = graph->adjLists[src];
graph->adjLists[src] = newNode;
// Add edge from dest to src
newNode = createNode(src);
newNode->next = graph->adjLists[dest];
graph->adjLists[dest] = newNode;
}
// Print the graph
void printGraph(struct Graph *graph) {
int v;
for (v = 0; v < graph->numVertices; v++) {
struct node *temp = graph->adjLists[v];
printf("\n Adjacency list of vertex %d\n ", v);
while (temp) {
printf("%d -> ", temp->vertex);
temp = temp->next;
}
printf("\n");
}
}
int main() {
struct Graph *graph = createGraph(4);
addEdge(graph, 0, 1);
addEdge(graph, 0, 2);
addEdge(graph, 1, 2);
addEdge(graph, 2, 3);
printGraph(graph);
DFS(graph, 2);
return 0;
}
"if a node in the graph has multiple adjacent neighbours, I need to choose the node with the lowest value to go to."
I assume the 'value' of a node is an attribute of the node object?
Most implementations of DFS will first look at the node with the lowest index in the data structure containing the node objects. So, if you first sort the nodes in your data structure into ascending value order, then the DFS will do what you want without needing to change the DFS code.
Here is what I came up with:
void DFS(struct Graph* graph, int vertex) {
struct node* temp = graph->adjLists[vertex];
graph->visited[vertex] = 1;
printf("Visited %d \n", vertex);
int neighbouring_nodes[graph->numVertices];
int count = 0;
while(temp != NULL) {
neighbouring_nodes[count] = temp->vertex;
count++;
temp = temp->next;
}
int smallest_node = neighbouring_nodes[0];
// Need to search (at most) in every neighbouring node
for (int i = 0; i < count; i++) {
// Go through all nodes in neighbouring_nodes array in order
// to find the smallest unvisited one, if it exists
for (int j = 0; j < count; j++){
// if current smallest_node has already been visited and
// neighbouring_nodes[j] is unvisited, assign it to smallest_node
if (graph->visited[smallest_node] == 1 && graph->visited[neighbouring_nodes[j]] == 0){
smallest_node = neighbouring_nodes[j];
}
// if neighbouring_nodes[j] is smaller than smallest_node,
// assign it to smallest_node
if (graph->visited[neighbouring_nodes[j]] == 0 && neighbouring_nodes[j] < smallest_node){
smallest_node = neighbouring_nodes[j];
}
}
if (graph->visited[smallest_node] == 0){
// calls DFS on the smallest unvisited neighboring node, if it exists
DFS(graph, smallest_node);
}else{
// otherwise (all neighboring nodes already visited)
// return control to the caller function
return;
}
}
}
I'm not 100% sure I understood what you wanted to do with the while (temp != NULL) and while (temp_cpy != NULL) loops but couldn't really figure out a way to use this approach especially in your particular case in which you want to visit the neighboring nodes in ascending order.
Let's assume a simple graph like 6->0->1, calling DFS(g, 0) will get temp to point to 6->1->NULL (could be also 1->6->NULL, depending on how you construct the graph), then smallest_node will be 1 and therefore the node 1 will be visited and the temp = temp->next will "assign" 1->NULL to temp. Back to the beginning of the loop, now temp_cpy will "be equal" to temp, hence 1->NULL. The node 6 is not on the list anymore even if it was not visited, on the other hand the already visited node 1 is still there. Also count is now equal to 1 therefore the condition (graph->visited[smallest_node] == 1 && count == 1) is met and DFS(g, 1) is called, which should not since node 1 was already visited. The infinite loop arises from this, since the previous condition is always met when temp has one (already visited) element left ([some value]->NULL). Once you reach that point you always call DFS(g, [some value]) and this will never give back control, since before reaching the temp = temp->next statement (which should assign NULL to temp , hence ending the while loop), DFS(g, [some other value]) is again called, which at some point will again call DFS(g, [some value]), and so forth.
As mentioned, one problem your original code has is that you call the DFS function also for an already visited vertex, and this should never be the case. When you encounter an already visited neighboring vertex, you want either to check the next or, if there are no unvisited neighboring vertices left, to give back control to the caller function. Therefore the last if else statement should not be there. The second problem is that smallest_node is selected in the wrong way. This is because temp_cpy, as explained above, is not constructed in such a way that it necessarily contains all unvisited neighboring nodes and also because you're actually looking for the smallest element in this list, regardless if it has already been visited or not (again because of the assumption that temp_cpy contains only all unvisited nodes). In fact you should be looking for the "smallest unvisited node" rather than the "smallest node".
In my code I go through all neighboring nodes with two for loops, find the smallest unvisited one and call DFS(g, [smallest unvisited node]) and once there are no unvisited neighbors left, return control back to the caller function.
I Hope this is somewhat understandable and I also hope I'm not missing something about what you had in mind with your implementation, in which case I would be very much interested in some explanations!
Here is a simpler version of the DFS in which neighboring nodes are checked and eventually visited in the order they're presented in the adjList. In this case I think the while (temp != NULL)/temp = temp->next approach makes sense:
void DFS(struct Graph *graph, int vertex) {
struct node *temp = graph->adjLists[vertex];
graph->visited[vertex] = 1;
printf("Visited %d \n", vertex);
// for vertex search in every neighboring node
while (temp != NULL) {
// if neighboring vertex temp->vertex not visited, then search there
if (graph->visited[temp->vertex] == 0) {
DFS(graph, temp->vertex);
// if already visited, go to the next vertex on the neighbors list
}else{
temp = temp->next;
}
}
// when searched in all neighboring vertexes return control to caller
return;
}
Related
so I have this function which does a depth first search traversal of a graph and prints out the nodes traversed. But instead of printing the nodes I want this function to return the node it newly moved to, return one node per call of the function.
when I call the function with the start node 0, it should return the next node in traversal (order of the nodes when traversing is printed out when running the program, along with the graph's adjacency list), which is 1 but it is returning 3.
the traversal order is: 1 2 3 2 4 5 4 6
below is what I have tried:
int DFS(struct Graph* graph, int vertex) {
struct node* adjList = graph->adjLists[vertex];
struct node* temp = adjList;
int back = 0;
graph->visited[vertex] = 1;
while (temp != NULL) {
int connectedVertex = temp->vertex;
if (graph->visited[connectedVertex] == 0) {
if ( back==1 ) {
return vertex;
printf("node: %d\n", vertex);
}
printf("node 1: %d\n", connectedVertex);
return DFS(graph, connectedVertex);
back = 1;
}
temp = temp->next;
}
return vertex;
}
and here is the function without the return statements (originally a void function):
void DFS(struct Graph* graph, int vertex) {
struct node* adjList = graph->adjLists[vertex];
struct node* temp = adjList;
int back = 0; // = "We have already expanded vertex"
graph->visited[vertex] = 1;
while (temp != NULL) {
int connectedVertex = temp->vertex;
if (graph->visited[connectedVertex] == 0) {
if ( back==1 ) // Report the revisited node
printf("node: %d\n", vertex);
printf("node: %d\n", connectedVertex);
DFS(graph, connectedVertex);
back = 1; // Tag this node as having been expanded.
}
temp = temp->next;
}
}
and here is my full program:
// DFS algorithm in C
#include <stdio.h>
#include <stdlib.h>
struct node {
int vertex;
struct node* next;
};
struct node* createNode(int v);
struct Graph {
int numVertices;
int* visited;
struct node** adjLists;
};
void DFS(struct Graph* graph, int vertex) {
struct node* adjList = graph->adjLists[vertex];
struct node* temp = adjList;
int back = 0; // = "We have already expanded vertex"
graph->visited[vertex] = 1;
while (temp != NULL) {
int connectedVertex = temp->vertex;
if (graph->visited[connectedVertex] == 0) {
if ( back==1 ) // Report the revisited node
printf("node: %d\n", vertex);
printf("node: %d\n", connectedVertex);
DFS(graph, connectedVertex);
back = 1; // Tag this node as having been expanded.
}
temp = temp->next;
}
}
// Create a node
struct node* createNode(int v) {
struct node* newNode = malloc(sizeof(struct node));
newNode->vertex = v;
newNode->next = NULL;
return newNode;
}
// Create graph
struct Graph* createGraph(int vertices) {
struct Graph* graph = malloc(sizeof(struct Graph));
graph->numVertices = vertices;
graph->adjLists = malloc(vertices * sizeof(struct node*));
graph->visited = malloc(vertices * sizeof(int));
int i;
for (i = 0; i < vertices; i++) {
graph->adjLists[i] = NULL;
graph->visited[i] = 0;
}
return graph;
}
void sortedInsert(struct node** head_ref,
struct node* new_node)
{
struct node* current;
/* Special case for the head end */
if (*head_ref == NULL
|| (*head_ref)->vertex
>= new_node->vertex) {
new_node->next = *head_ref;
*head_ref = new_node;
}
else {
/* Locate the node before
the point of insertion */
current = *head_ref;
while (current->next != NULL
&& current->next->vertex < new_node->vertex) {
current = current->next;
}
new_node->next = current->next;
current->next = new_node;
}
}
// Add edge
void addEdge(struct Graph* graph, int src, int dest) {
// Add edge from src to dest
sortedInsert(&graph->adjLists[src], createNode(dest));
// Add edge from dest to src
sortedInsert(&graph->adjLists[dest], createNode(src));
}
// Print the graph
void printGraph(struct Graph* graph) {
int v;
for (v = 0; v < graph->numVertices; v++) {
struct node* temp = graph->adjLists[v];
printf("\n Adjacency list of vertex %d\n ", v);
while (temp) {
printf("%d -> ", temp->vertex);
temp = temp->next;
}
printf("\n");
}
}
int main() {
struct Graph* graph = createGraph(7);
addEdge(graph, 0, 1);
addEdge(graph, 0, 3);
addEdge(graph, 1, 2);
addEdge(graph, 2, 3);
addEdge(graph, 2, 4);
addEdge(graph, 4, 5);
addEdge(graph, 4, 6);
printGraph(graph);
DFS(graph, 0);
return 0;
}
Help would be much appreciated.
" I want this function to return the node it newly moved to, return one node per call of the function."
This is a bad idea, because your function is recursive.
To get the nodes traversed in order add the visited node index to a global data structure.
Note: Recursion is the correct way to go here. Returning the node visited from the recursive function will not work.
Allow me to describe how I would do this:
When searching through graphs, the concept of a "visitor" is useful. A visitor is a function that the search code calls each time it reaches a new node. It makes writing the search code slightly more complex, but you need only do it once. Once written you can adapt the algorithm to do different purposes without disturbing your carefully tested and optimized search code. In this case, all the visitor need do is record the node indexes as they are visited.
Note that once you have the visitor written, you can easily change the searching algorithm ( say from depth first to breadth first ) without writing new code.
Your visitor can look like this in C++
/// in global namespace
std::vector<int> gvIndexNodeVisitedOrder();
void visitor( int indexNode )
{
gvIndexNodeVositedOrder.push_back( indexNode );
}
The searching code looks like:
void depthFirstRecurse(
int v )
{
// Call the visitor
visitor(v);
// remember this node has been visited
gvNodeVisited[v] = 1;
// look at adjacent nodes
for (int w : adjacent(v)) {
// check node has not been visited
if (!gvNodeVisited[w])
{
// continue search from new node
depthFirstRecurse(w);
}
}
}
Note: I have placed stuff in the global namespace because the original question is tagged C. In reality I would use a C++ class and make the "globals" private attributes and methods of the class.
I added this two fuctions:
// Adds a node to a list of nodes
void addNode(struct node** nodeList, int vertex){
struct node *temp = *nodeList;
if(*nodeList == NULL){
*nodeList = createNode(vertex);
}else{
while(temp->next != NULL){
temp = temp->next;
}
temp->next = createNode(vertex);
}
}
// Prints a list of nodes
void printNodeList(struct node* nodeList) {
struct node* temp = nodeList;
while(temp != NULL){
printf("%d", temp->vertex);
if(temp->next != NULL){
printf(" -> ");
}
temp = temp->next;
}
printf("\n");
}
and modified DFS and main as follow:
// added last argument
void DFS(struct Graph* graph, int vertex, struct node** nodeList) {
struct node* adjList = graph->adjLists[vertex];
struct node* temp = adjList;
graph->visited[vertex] = 1;
addNode(nodeList, vertex); // added this
while (temp != NULL) {
int connectedVertex = temp->vertex;
if (graph->visited[connectedVertex] == 0) {
printf("node: %d\n", connectedVertex);
DFS(graph, connectedVertex, nodeList);
addNode(nodeList, vertex); // added this
}
temp = temp->next;
}
}
int main() {
struct node* nodeList = NULL;
struct Graph* graph = createGraph(7);
addEdge(graph, 0, 1);
addEdge(graph, 0, 3);
addEdge(graph, 1, 2);
addEdge(graph, 2, 3);
addEdge(graph, 2, 4);
addEdge(graph, 4, 5);
addEdge(graph, 4, 6);
printGraph(graph);
DFS(graph, 0, &nodeList);
printNodeList(nodeList);
return 0;
}
If I would have to define the traversal order of the nodes, in your example graph it would not be 1 -> 2 -> 3 -> 2 -> 4 -> 5 -> 4 -> 6 but rather 0 -> 1 -> 2 -> 3 -> 2 -> 4 -> 5 -> 4 -> 6 -> 4 -> 2 -> 1 -> 0, since I think that any time you "land" on a different node (either because you call DFS or because DFS gives back control to the caller), that "counts" in the path you're following to search the graph, and this until you're back to the main function, hence you've finished searching. Therefore in the DFS function above I implemented that, but if you need the order you mentioned, just add addNode(nodeList, vertex); below your printf statements and you should get it.
Since the function is recursive you can't really use the return statement to return the visited nodes, because what you want to have at the end is a list of elements and not just a single value. For instance in your code you defined the return type of DFS as int, this means that the function can only give you back a number, but when you call DFS in your main function you expect it to give you back a list of node that got visited. You may be able to figure out something returning a pointer to a data structure or maybe returning an int (the visited vertex) and calling something like addNode(list, DFS(g, vertex)) but you would still need to pass the list to DFS (otherwise you won't be able to call addNode(list,...) inside of it), so you would get addNode(list, DFS(g, vertex, list)), therefore I don't think you would get any advantage out of it, but I don't know.
What I did is to define a list in the main function and to pass it to the recursive function (does not need to return anything), which is then able to add the visited node to it when necessary. The first call to addNode(nodeList, vertex) happens only once per vertex since you never call DFS more than one time for any vertex, while the second happens every time you come back to a vertex after having searched into one of it's neighbors.
I have created a pathfinding algorithm in C that uses a map.txt file with a maze written in 0s for walls and 1s for paths. Currently the path finding algorithm I'm using is a DFS with a stack to keep track of nodes but I'm trying to change it to a queue to utilize BFS so that I will be certain that the shortest path is always found. But when I try to print out the new path in BFS it seems like the rest of the path gets deleted somewhere but I can't find where.
Here is the path-finding algorithm in question:
struct node *BFS(struct graph* graph, int vertex, int endVertex, struct node* path_stack) {
struct node* temp = graph->adjlist[vertex]; //This is the first neighbor to the vertex node
struct node* temp2 = graph->adjlist[endVertex];// We use this temp to check if there exist a path at all (if the end node exist and has neighbours)
graph->visited[vertex] = 1; // sets the self as visited
static int done = 0;
if(temp2 == NULL || temp == NULL)
{
printf("No Path can be found");
return path_stack;
}
// if we havent arrived yet
while (temp != NULL) { // checks if the current neighbor exists
if(done == 1)
{
break;
return path_stack;
}
if(temp->vertex == endVertex) // Check for when we have gotten to the goal
{
printStack(path_stack);
done = 1;
break;
}
path_stack = push(temp, path_stack); // we push the first neighbor to the stack
if (graph->visited[temp->vertex] == 0) { //if the neighbor is not visited we run the algorithm again and now with the neighbors value as the vertex
BFS(graph, temp->vertex, endVertex,path_stack);
}
else
{
if(graph->visited[temp->vertex] == 1)
{
path_stack = pop(path_stack);
}
temp = temp->next; // we go the next neighbor to the current node
}
}
return path_stack;
}
Here is my push code that has been changed to push last like a queue:
struct node* push(struct node* Node, struct node* head)// Push has now been altered to push like a queue, so we can use bfs instead of dfs
{
struct node* temp = CreateNode(Node->vertex,Node->Y,Node->X); // We use a queue to keep track of visited nodes
temp->next = NULL;
if(head == NULL)
head = temp;
else
{
head->next = temp;
head = temp;
}
return head;
}
and here is my function that prints the path but now it only prints the last node in the path and all the others are gone.
void printStack(struct node* head)//Function that prints all the nodes in the stack
{
struct node* tmp = head;
//struct node* tmp2 = NULL;
printf("(The Start)->");
while(tmp != NULL)
{
//tmp2 = push_path(tmp, tmp2);
printf("(%d,%d)->", tmp->X, tmp->Y);
tmp = tmp->next;
}
/* while(tmp2 != NULL)
{
printf("(%d,%d)->", tmp2->X, tmp2->Y);
tmp2 = tmp2->next;
}
*/
printf("(The End)\n");
}
The code for printing the path has also been changed a little because when using DFS the path would be printed reversed so the code that has been commented out was for when I needed to reverse it back but now it's not necessary to use it. Any help with why the path can't be printed is very much appreciated, I'm still quite new to C programming and path finding algorithms.
I am confused in pointer arithmetic, I want to make a tree traversal function, but I am not quite sure about pointer arithmetic to get distant nodes in the tree. It will be a lot more clear when seen in the code, so here it is.
node **root = huffman_tree(probabilities); // I can only return that as a double ptr
Now if I want data from my root node:
printf("%lf", (*root)->data);
If I want data from roots children:
printf("%lf", (*root)->left->data); // or (*root)->right->data
But what if I want to go further in depth search, I dont know how to reach those nodes?
printf("%lf", (*root)->left->left->data); // thats not working
Also, for tree traversal, this is not working: the program crashes.
node **root = huffman_tree(probabailities);
preorder(*root);
void preorder(node *n){
if(n == NULL) return;
printf("%lf", n->data);
preorder(n->left);
preorder(n->right);
}
For the above examples, the program crashes.
Update 1:
It seems like huffman_tree() is indeed returning a tree with corrupted nodes, I must be doing memory allocation for them incorrectly.
The function is passed an array of probabilities, and then obtains steps as it follows:
1) creates nodes with given probabilities (n probabilities --> n new nodes) [works fine]
2) finds the two nodes with lowest probabilities [works fine]
3) creates a new node which is the parent of the two lowest probabilities nodes
4) assign a new node probability equal to the sum of it's children's probabilities
5) repeat from step 2) until there is only one parentless node left
node **huffman_tree(double *probabs){
int num_of_nodes = NUM_OF_SYMBOLS;
int num = NUM_OF_SYMBOLS;
// 1) create nodes for given probabilities
node *leafs = (node*) malloc(num_of_nodes*sizeof(node));
int i;
for(i=0; i<num_of_nodes; i+=1){
node *n = (node *) malloc(sizeof(node));
n->probab = *(probabs + i);
n->symbol = *(SYMBOLS + i);
n->left = NULL;
n->right = NULL;
*(leafs+i) = *n;
//free(n);
}
node **root;
while(num_of_nodes > 1){
// 2) Find the two nodes with lowest probabilities
node *two_mins =(node *)malloc(2*sizeof(node));
two_mins = find_two_mins(leafs, num_of_nodes);
node min_n1 = two_mins[0];
node min_n2 = two_mins[1];
// 3) Create a parent node with probability equals to sum of its children probabilities
// add a parent node to leafs
node *new_node = (node *) malloc(sizeof(node));
new_node->probab = min_n1.probab + min_n2.probab;
new_node->left = &min_n1;
new_node->right = &min_n2;
leafs = add_node(leafs, new_node, num);
num += 1;
leafs = remove_node(leafs, &min_n1, num);
num -= 1;
leafs = remove_node(leafs, &min_n2, num);
num -= 1;
num_of_nodes -= 1;
root = &new_node;
}
return root;
Function add_node() [seems to be working fine]
node *add_node(node *nodes, node *n, int num){
nodes = realloc(nodes, (num+1)*sizeof(node));
nodes[num] = *n;
return nodes;
Function remove_node() [seems to be working fine]
node *remove_node(node *nodes, node *n, int num){
int i;
int index = 0;
for(i=0; i<num; i+=1){
if(nodes_are_equal(nodes[i], *n)) index = i;
}
for(i=index; i<num-1; i+=1){
nodes[i] = nodes[i+1];
}
nodes = realloc(nodes, (num-1)*sizeof(node));
return nodes;
Update 2
I have changed some things in huffman_tree() function.
Function find_two_mins() no longer exists, but it is replaced with two calls of another function find_min(), which finds only one minimum node at a time. Also, this function takes pointer to the dynamically allocated node, and after minimum value is found, returns it back.
node *root;
while(num_of_nodes > 1){
// 2) Find two min nodes
node *min_n1= (node *)malloc(sizeof(node));
node*min_n2= (node *)malloc(sizeof(node));
*min_n1= *find_min(leafs, num, min_n1);
leafs = remove_node(leafs, min_n1, num);
num -= 1;
*min_n2= *find_min(leafs, num, min_n2);
leafs = remove_node(leafs, min_n2, num);
num -= 1;
printf("\nTwo Min Nodes: %lf\t%lf", min_n1->probab, min_n2->probab);
printf("\nSum Of All: %lf", s);
// 3) Create parent node of two min nodes
node *new_node = (node *) malloc(sizeof(node));
new_node->probab= min_n1->probab+ min_n2->probab;
new_node->left = min_n1;
new_node->right = min_n2;
leafs = add_node(leafs, new_node, num);
num += 1;
free(min_n1);
free(min_n2);
num_of_nodes -= 1;
root = new_node;
printf("root=%p\n", root);
printf("*root=%p\n", *root);
}
return root;
And here is the find_min() function:
node *find_min(node *nodes, int num, node *min_node){
double min_probab = nodes[0].probab;
*min_node= nodes[0];
int i;
for(i=0; i<num; i+=1){
if(nodes[i].probab< min_probab){
min_probab = nodes[i].probab;
*min_node = nodes[i];
}
}
return min_node;
It seems like the problem is something about this output:
printf("root=%p\n", root);
printf("*root=%p\n", *root);
Since it outputs "root = 003A17F0" and "*root = 00000000"
Also, I am providing a screenshot of how the program runs, where root values at any point can be seen.
(*root)->left->left->data is the correct way of accessing grand-child nodes, as long as the child is not null, and assuming your node looks something like:
struct node
{
double data;
struct node * left;
struct node * right;
}
Without seeing the full code, it's hard to be sure what's going on here. Your null check in preorder looks good, so I suspect you must be somehow corrupting one of your nodes, and getting an invalid (but non-NULL) pointer in there.
Putting the following immediately after the null check in preorder should make the problem more obvious:
printf("processing node %p", n); fflush(stdout);
printf(" left=%p\n", n->left); fflush(stdout);
printf(" right=%p\n", n->right); fflush(stdout);
You're looking for pointers that don't "look like" the others, particularly just before it crashes.
The most likely causes for problems are within huffman_tree itself. I'd suspect you've got something in there that's taking the address of a node from the stack rather than dynamically allocating it with malloc.
Edit based on additional information supplied in your "answer":
Your problem is probably in your find_two_mins function. The following code
node *two_mins =(node *)malloc(2*sizeof(node));
two_mins = find_two_mins(leafs, num_of_nodes);
node min_n1 = two_mins[0];
node min_n2 = two_mins[1];
is (correctly) dynamically allocating the memory for the nodes, but then you are throwing the pointer to that dynamic memory away and replacing it with the result of find_two_mins.
You've also got some other memory leaks around the place I think (although it's not causing your problem). Within the initial loop,
node *n = (node *) malloc(sizeof(node));
that doesn't get freed. You're copying that struct into the correctly allocated leafs array, so just make that a node n;.
I haven't looked in detail any further than that, so there might be more problems, but let me know where that gets you.
I know this may sound a lot naive, but can someone please explain me how can i implement graphs in C language. I have read the theory, but I am not able to get off the blocks with graph programming.
I would really appreciate if someone could explain how would to create a graph using adjacency lists and adjacency matrix and how would you perform breadth first search and depth first search in C code with some explanations
And before anything, I would like to tell you that this is not a homework. I really want to learn graphs but can't afford a tutor.
I assume that here graph is a collection of vertex and edges. For that you would need an array of pointer to structures. This is adjacency list representation of graph. These structures would having at least an value, which is node number and pointer to another structure. While inserting a new node to graph just go to appropriate index of array and push the node at beginning. This is O(1) time for insertion. My implementation might help you in understanding how it really works. If you are having good skills at C this wouldn't take much longer to understand the code.
// Graph implementation by adjacency list
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 1000
typedef struct node{
int number;
struct node * next;
} Node;
// U is starting node, V is ending node
void addNode (Node *G[], int U, int V, int is_directed)
{
Node * newnode = (Node *)malloc(sizeof(Node));
newnode->number = V;
newnode->next = G[U];
G[U] = newnode;
// 0 for directed, 1 for undirected
if (is_directed)
{
Node * newnode = (Node *)malloc(sizeof(Node));
newnode->number = U;
newnode->next = G[V];
G[V] = newnode;
}
}
void printgraph(Node *G[], int num_nodes)
{
int I;
for (I=0; I<=num_nodes; I++)
{
Node *dum = G[I];
printf("%d : ",I);
while (dum != NULL)
{
printf("%d, ",dum->number);
dum =dum->next;
}
printf("\n");
}
}
void dfs (Node *G[], int num_nodes, int start_node)
{
int stack[MAX_SIZE];
int color[num_nodes+1];
memset (color, 0, sizeof(color));
int top = -1;
stack[top+1] = start_node;
top++;
while (top != -1)
{
int current = stack[top];
printf("%d ",current);
top--;
Node *tmp = G[current];
while (tmp != NULL)
{
if (color[tmp->number] == 0)
{
stack[top+1] = tmp->number;
top++;
color[tmp->number] = 1;
}
tmp = tmp->next;
}
}
}
void bfs (Node *G[], int num_nodes, int start_node)
{
int queue[MAX_SIZE];
int color[num_nodes+1];
memset (color, 0, sizeof (color));
int front=-1, rear=-1;
queue[rear+1] = start_node;
rear++;printf("\n\n");
while (front != rear)
{
front++;
int current = queue[front];
printf("%d ",current);
Node *tmp = G[current];
while (tmp != NULL)
{
if (color[tmp->number] == 0)
{
queue[rear+1] = tmp->number;
rear++;
color[tmp->number] = 1;
}
tmp = tmp->next;
}
}
}
int main(int argc, char **argv)
{
int num_nodes;
// For Demo take num_nodes = 4
scanf("%d",&num_nodes);
Node *G[num_nodes+1];
int I;
for (I=0; I<num_nodes+1 ;I++ )
G[I] = NULL;
addNode (G, 0, 2, 0);
addNode (G, 0, 1, 0);
addNode (G, 1, 3, 0);
addNode (G, 2, 4, 0);
addNode (G, 2, 1, 0);
printgraph( G, num_nodes);
printf("DFS on graph\n");
dfs(G, num_nodes, 0);
printf("\n\nBFS on graph\n");
bfs(G, num_nodes, 0);
return 0;
}
Well, a real naive and basic answer would be that graph can be represented in C using data structures that contain their pointers to other such data structures. Graphs are really just doubly linked lists that can have multiple links from a single node. If you haven't digested linked lists and doubly linked lists, that'd be a good place to start.
So let's say you have a adjacency list, {a,b},{b,c},{d},{b,e}. First off, you parse that and make a list of all your unique items. (A regular linked list, array, whatever, it's just a temporary structure to help you. You could bypass that, do it on the fly, and probably reap a speedup, but this is simple.) Walking through that list, you generate a node for each item. For each node, you go through the adjacency list again and create an edge when it sees itself. This is a pointer inside the node pointing to another node.
In the end you have a regular list of all you nodes, so you don't lose that lone 'd' node hanging out by itself. You also have a graph of all your nodes so you know their relationship to each other.
Search
Searching across graphs is a pretty basic idea. Start in a node, compare, move to one of it's neighbors and do it again. There are a lot of pitfalls though. Like getting into an endless loop and knowing when to stop.
You'll have to ask more specific questions if you want a better explanation than what you can find online already.
Why are the split lists always empty in this program? (It is derived from the code on the Wikipedia page on Linked Lists.)
/*
Example program from wikipedia linked list article
Modified to find nth node and to split the list
*/
#include <stdio.h>
#include <stdlib.h>
typedef struct ns
{
int data;
struct ns *next; /* pointer to next element in list */
} node;
node *list_add(node **p, int i)
{
node *n = (node *)malloc(sizeof(node));
if (n == NULL)
return NULL;
n->next = *p; //* the previous element (*p) now becomes the "next" element */
*p = n; //* add new empty element to the front (head) of the list */
n->data = i;
return *p;
}
void list_print(node *n)
{
int i=0;
if (n == NULL)
{
printf("list is empty\n");
}
while (n != NULL)
{
printf("Value at node #%d = %d\n", i, n->data);
n = n->next;
i++;
}
}
node *list_nth(node *head, int index) {
node *current = head;
node *temp=NULL;
int count = 0; // the index of the node we're currently looking at
while (current != NULL) {
if (count == index)
temp = current;
count++;
current = current->next;
}
return temp;
}
/*
This function is to split a linked list:
Return a list with nodes starting from index 'int ind' and
step the index by 'int step' until the end of list.
*/
node *list_split(node *head, int ind, int step) {
node *current = head;
node *temp=NULL;
int count = ind; // the index of the node we're currently looking at
temp = list_nth(current, ind);
while (current != NULL) {
count = count+step;
temp->next = list_nth(head, count);
current = current->next;
}
return temp; /* return the final stepped list */
}
int main(void)
{
node *n = NULL, *list1=NULL, *list2=NULL, *list3=NULL, *list4=NULL;
int i;
/* List with 30 nodes */
for(i=0;i<=30;i++){
list_add(&n, i);
}
list_print(n);
/* Get 1th, 5th, 9th, 13th, 18th ... nodes of n etc */
list1 = list_split(n, 1, 4);
list_print(list1);
list2 = list_split(n, 2, 4); /* 2, 6, 10, 14 etc */
list_print(list2);
list3 = list_split(n, 3, 4); /* 3, 7, 11, 15 etc */
list_print(list3);
list3 = list_split(n, 4, 4); /* 4, 8, 12, 16 etc */
list_print(list4);
getch();
return 0;
}
temp = list_nth(current, ind);
while (current != NULL) {
count = count+step;
temp->next = list_nth(head, count);
current = current->next;
}
You are finding the correct item to begin the split at, but look at what happens to temp from then on ... you only ever assign to temp->next.
You need to keep track of both the head of your split list and the tail where you are inserting new items.
The program, actually, has more than one problem.
Indexes are not a native way to address linked list content. Normally, pointers to nodes or iterators (which are disguised pointers to nodes) are used. With indexes, accessing a node has linear complexity (O(n)) instead of constant O(1).
Note that list_nth returns a pointer to a "live" node within a list, not a copy. By assigning to temp->next in list_split, you are rewiring the original list instead of creating a new one (but maybe it's intentional?)
Within list_split, temp is never advanced, so the loop just keeps attaching nodes to the head instead of to the tail.
Due to use of list_nth for finding nodes by iterating through the whole list from the beginning, list_split has quadratic time (O(n**2)) instead of linear time. It's better to rewrite the function to iterate through the list once and copy (or re-attach) required nodes as it passes them, instead of calling list_nth. Or, you can write current = list_nth(current, step).
[EDIT] Forgot to mention. Since you are rewiring the original list, writing list_nth(head, count) is incorrect: it will be travelling the "short-cirquited" list, not the unmodified one.
I also notice that it looks like you are skipping the first record in the list when you are calculating list_nth. Remember is C we normally start counting at zero.
Draw out a Linked List diagram and follow your logic:
[0]->[1]->[2]->[3]->[4]->[5]->[6]->[7]->[8]->[9]->...->[10]->[NULL]
Your description of what list_split is supposed to return is pretty clear, but it's not clear what is supposed to happen, if anything, to the original list. Assuming it's not supposed to change:
node *list_split(node *head, int ind, int step) {
node *current = head;
node *newlist=NULL;
node **end = &newlist;
node *temp = list_nth(current, ind);
while (temp != NULL) {
*end = (node *)malloc(sizeof(node));
if (*end == NULL) return NULL;
(*end)->data = temp->data;
end = &((*end)->next);
temp = list_nth(temp, step);
}
return newlist; /* return the final stepped list */
}
(You probably want to factor a list_insert routine out of that that inserts a new
node at a given location. list_add isn't very useful since it always adds to the
beginning of the list.)