Following is my code for building a simple tree. The approach I'm using here is that if a particular node is at index n in the arr[] array, then it has it's left child at index 2*n+1 and right child at 2*n+2 in the same arr[] array. And then I'm doing an inorder traversal. However, I'm getting an infinite loop at node D as my output. Would love if anybody could help me out here.
#include <stdio.h>
#include <malloc.h>
struct node
{
struct node * lc;
char data;
struct node * rc;
};
char arr[] = {'A','B','C','D','E','F','G','\0','\0','H','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'};
struct node * root = NULL;
struct node * buildTree(int rootIndex)
{
struct node * temp = NULL;
if(arr[rootIndex]!='\0')
{
temp = (struct node *)malloc(sizeof(struct node));
temp->lc = buildTree(rootIndex * 2 + 1);
temp->data = arr[rootIndex];
temp->rc = buildTree(rootIndex * 2 + 2);
}
return temp;
}
void inorder(struct node * parent)
{
while(parent != NULL)
{
inorder(parent->lc);
printf("%c\t",parent->data);
inorder(parent->rc);
}
}
int main()
{
root = buildTree(0);
inorder(root);
return 0;
}
Like BLUEPIXY mentioned in comments, you need to replace the while in inorder() method with an if. When building tree, D forms the left-most child. Therefore during in-order traversal, D is encountered as the first node to be printed. But the while loop keeps printing it as the condition never becomes false.
I'm sure a tool like gdb would have done much better job in explaining this.
Related
There are many implementations available on the net, but I wanted to do it on my own.
Can anyone tell what mistakes I am making?
When I created the linked list, I gave input as 3,12,5,2. So after sorting it should have been 2,3,5,12, but it gave me output as 3,5,2,12.
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
struct node *start=NULL;
void sort()
{
struct node *preptr, *ptr, *temp;
temp = (struct node *)malloc(sizeof(struct node));
ptr=start;
while(ptr->next != NULL)
{
preptr=ptr;
ptr=ptr->next;
if (preptr->data > ptr->data )
{
temp->data=ptr->data;
ptr->data=preptr->data;
preptr->data=temp->data;
ptr=start;
}
}
}
You appear to have attempted to implement Bubble Sort, but that requires multiple passes through the data in the general, and you perform only one. On that one pass, with input 3, 12, 5, 2, your code
compares 3 with 12, and makes no change;
compares 12 with 5, and swaps them;
compares 12 with 2, and swaps them.
Then it stops, leaving 3, 5, 2, 12 as the final result.
A Bubble Sort on an n-element list must make n - 1 passes through the list in the general case, and your particular input happens to require that maximum number of passes. One way to fix it would be to just run your existing code for one sorting pass inside a for loop that runs n - 1 times, but of course you then need to compute n first. A better way (without changing to an altogether better algorithm) would be to run an indeterminate number of passes, via an outer loop, keeping track of whether any swaps are performed during the pass. You're then done when you complete a pass without making any swaps.
Additional notes:
You don't need a struct node just to swap the int data of two nodes.
If want a struct node for a local temporary, you don't need to allocate it dynamically. Just declare it:
struct node temp_node;
If you want a struct node * for a local temporary, you (probably) do not need to allocate any memory for it to point to.
If you want a struct node for a local temporary and a pointer to it, you still don't need to allocate anything dynamically. Just declare the struct and take its address:
struct node temp_node;
struct node *temp = &temp_node;
The main reasons to allocate dynamically are that you don't know in advance how much memory you will need, or that the allocated object needs to outlive the execution of the function in which it is created.
Sorting a linked list is usually accomplished by rearranging the nodes by changing their links, not by swapping the node payloads, as your function does. It's not necessarily wrong to swap the payloads, but that does not take any advantage of the linked list structure.
As you wrote in comments that you actually need to move the nodes, not the values, you will need to reassign the next pointers.
For the same reason, it must be possible for start to reference a different node. Therefore I would suggest that sort takes start as an argument and returns the new value it.
For implementing bubble sort, you need an extra outer loop, which restarts the iteration over the list. This should be repeated at most n times, where n is the number of nodes in your list. You could also just check whether a swap was necessary and in that case decide to do another scan through your list... until no more swaps occur.
I have here implemented that second idea:
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
// A function to create a new node.
// This allows for easy initialisation of a linked list
struct node *newNode(int data, struct node *next) {
struct node *temp = (struct node *)malloc(sizeof(struct node));
temp->data = data;
temp->next = next;
return temp;
}
// Useful to see what is in the list...
void printList(struct node *cur) {
while (cur != NULL) {
printf("%i ", cur->data);
cur = cur->next;
}
printf("\n");
}
// Let the sort function
struct node * sort(struct node *start) {
struct node *prev, *cur, *next;
// flag indicating we are not sure yet that
// the list is sorted
int mutation = 1;
// extra dummy node that precedes the start node
struct node sentinel;
sentinel.next = start;
while (mutation) {
mutation = 0;
prev = &sentinel;
cur = sentinel.next;
next = start->next;
while (next != NULL) {
if (cur->data > next->data ) {
// swap cur and next
prev->next = next;
cur->next = next->next;
next->next = cur;
// flag that we need more iterations
mutation = 1;
// prepare for next iteration
prev = next;
} else {
prev = cur;
cur = next;
}
next = cur->next;
}
}
return sentinel.next;
}
// demo:
int main(void) {
// Create list that was given as example
struct node *start = newNode(3, newNode(12, newNode(5, newNode(2, NULL))));
printf("Input:\n");
printList(start);
start = sort(start);
printf("Sorted:\n");
printList(start);
return 0;
}
I'm still learning how to program in C and I've stumbled across a problem.
Using a char array, I need to create a linked list, but I don't know how to do it. I've searched online, but it seems very confusing. The char array is something like this char arr[3][2]={"1A","2B","3C"};
Have a look at this code below. It uses a Node struct and you can see how we iterate through the list, creating nodes, allocating memory, and adding them to the linked list. It is based of this GeeksForGeeks article, with a few modifications. I reccommend you compare the two to help understand what is going on.
#include <stdio.h>
#include <stdlib.h>
struct Node {
char value[2];
struct Node * next;
};
int main() {
char arr[3][2] = {"1A","2B","3C"};
struct Node * linked_list = NULL;
// Iterate over array
// We calculate the size of the array by using sizeof the whole array and dividing it by the sizeof the first element of the array
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
// We create a new node
struct Node * new_node = (struct Node *)malloc(sizeof(struct Node));
// Assign the value, you can't assign arrays so we do each char individually or use strcpy
new_node->value[0] = arr[i][0];
new_node->value[1] = arr[i][1];
// Set next node to NULL
new_node->next = NULL;
if (linked_list == NULL) {
// If the linked_list is empty, this is the first node, add it to the front
linked_list = new_node;
continue;
}
// Find the last node (where next is NULL) and set the next value to the newly created node
struct Node * last = linked_list;
while (last->next != NULL) {
last = last->next;
}
last->next = new_node;
}
// Iterate through our linked list printing each value
struct Node * pointer = linked_list;
while (pointer != NULL) {
printf("%s\n", pointer->value);
pointer = pointer->next;
}
return 0;
}
There are a few things the above code is missing, like checking if each malloc is successful, and freeing the allocated memory afterwards. This is only meant to give you something to build off of!
I am trying to accomplish a function that grows a linked list while also putting them in ascending order at the same time, I have been stuck for a while and gained little progress. I believe my insertLLInOrder is correct it's just the createlinkedList that is messing it up.
Sometimes my output comes out fully and other times it only prints out some of the list.
Anything helps!
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node *next;
} node;
node *createlinkedList(int num);
node *insertLLInOrder(node * h, node * n);
void display(node * head);
int randomVal(int min, int max);
int
main()
{
int usernum = 0;
node *HEAD = NULL;
printf("How many Nodes do you want? ");
scanf("%d", &usernum);
srand(time(0));
HEAD = createlinkedList(usernum);
display(HEAD);
return 0;
}
node *
createlinkedList(int num)
{
int i;
int n = num;
node *head = NULL;
node *newNode;
node *temp;
for (i = 0; i < n; i++) {
newNode = (node *) malloc(sizeof(node));
newNode->next = NULL;
newNode->data = randomVal(1, 9);
temp = insertLLInOrder(head, newNode);
head = temp;
}
return head;
}
int
randomVal(int min, int max)
{
return min + (rand() % (max - min)) + 1;
}
node *
insertLLInOrder(node * h, node * n)
{
//h is the head pointer, n is the pointer to new node
node *ptr = h;
node *previous = NULL;
while ((ptr != NULL) && (ptr->data < n->data)) {
previous = ptr; // remember previous node
ptr = ptr->next; // check for the next node
}
if (previous == NULL) {
//h is an empty list initially
n->next = NULL;
return n; // return the pointer of the new node
}
else {
//if there are nodes in the linked list
// previous will point to the node that has largest value, but smaller than new node
n->next = previous->next; // insert new node between previous, and previous->next
previous->next = n;
return h; // return old head pointer
}
}
void
display(node * head)
{
node *p = head;
while (p != NULL) {
printf("%d, ", p->data);
p = p->next;
}
}
Obviously in your insertLLInOrder() if the first while loop gives previous == NULL it means that you must insert at list head, which is not what your are doing.
Just change n->next = NULL; to n->next = h; and it should improve behavior.
Taking a step back and perspective
This is a very simple error, but it is made harder to spot because of the way you wrote your code.
The bug in itself is not very interesting, but it can help to get a higher perspective on why it happened and how to avoid such bugs.
And, no, running a debugger is not very helpful for such cases!
Having to run a debugger happens sometimes, but it merely means that you have lost the control of your program. Like having a parachute can be a safety mesure for a pilot, but if he has to use it, it also means that the pilot lost control and his plane is crashing.
Do you know the story of the Three Ninjas Programmers?
The three Ninjas
The chief of ninjas orders three Ninja to show him their training level. There is a Noob, a Beginner and a Senior. He asks them to reach a small cabin, on the other side of a field, take some object inside and come back.
The first Ninja is a noob, he runs and jumps across the field with all his speed but soon enough he walks on a (plaster) mine. He goes back at the start line and confesses his failure, which is obvious because his previously black shirt is now covered by white plaster.
The second Ninja shows some practice. You can tell he failed like the Noob on a previous try and that now he is wary. He is very slow and very careful. He sneaks very slowly across the field watching closely everywhere at each step. He gets quite close to the cabin, and everybody believes he will succeed, but eventually, he is also blown by a mine at the last second. He also goes back disappointed to the starting point, but he somehow believes it will be hard for the third Ninja to do any better.
The third Ninja is a Senior. He walks calmly across the field in a straight line, enter the cabin, and goes back without any visible trouble, still merely walking across the field.
When he gets back to the starting point the other two Ninjas are stunned and ask him eagerly:
- How did you avoid the mines?
- Obviously, I didn't put any mines on my path in the first place; why did you put mines in yours?
Back to the code
So, what could be done differently when writing such a program?
First using random values in code is a bad idea. The consequence is that the code behavior can't be repeated from one run to the next one.
It is also important that the code clearly separate user inputs (data) and code manipulating that data.
In that case, it means that the createLinkedList() function should probably have another signature. Probably something like node *createlinkedList(int num, int data[]) where the data[] array will contains values to sort. It is still possible to fill input data with random values if it is what we want.
That way, we can easily create tests set and unit tests, like in code below:
Home made unit tests suite
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node *next;
} node;
node *createlinkedList(int num, int * data);
node *insertLLInOrder(node * h, node * n);
/* No need to have a test framework to write unit tests */
/* Check_LL is some helper function comparing a linked list with test data from an array */
int check_LL(node * head, int num, int * data)
{
node *p = head;
int n = 0;
for (; n < num ; n++){
if (!p){return 0;}
if (p->data != data[n]){return 0;}
p = p->next;
}
return p == NULL;
}
void test_single_node()
{
printf("Running Test %s: ", __FUNCTION__);
int input_data[1] = {1};
int expected[1] = {1};
node * HEAD = createlinkedList(1, input_data);
printf("%s\n", check_LL(HEAD, 1, expected)?"PASSED":"FAILED");
}
void test_insert_after()
{
printf("Running Test %s: ", __FUNCTION__);
int input_data[2] = {1, 2};
int expected[2] = {1, 2};
node * HEAD = createlinkedList(2, input_data);
printf("%s\n", check_LL(HEAD, 2, expected)?"PASSED":"FAILED");
}
void test_insert_before()
{
printf("Running Test %s: ", __FUNCTION__);
int input_data[2] = {2, 1};
int expected[2] = {1, 2};
node * HEAD = createlinkedList(2, input_data);
printf("%s\n", check_LL(HEAD, 2, expected)?"PASSED":"FAILED");
}
/* We could leave test code in program and have a --test command line option to call the code */
int
main()
{
test_single_node();
test_insert_after();
test_insert_before();
}
node *
createlinkedList(int num, int * data)
{
int i;
node *head = NULL;
for (i = 0; i < num; i++) {
node * newNode = (node *) malloc(sizeof(node));
newNode->next = NULL;
newNode->data = data[i];
head = insertLLInOrder(head, newNode);
}
return head;
}
node *
insertLLInOrder(node * h, node * n)
{
//h is the head pointer, n is the pointer to new node
node *ptr = h;
node *previous = NULL;
while ((ptr != NULL) && (ptr->data < n->data)) {
previous = ptr; // remember previous node
ptr = ptr->next; // check for the next node
}
if (previous == NULL) {
//h is an empty list initially
n->next = NULL;
return n; // return the pointer of the new node
}
else {
//if there are nodes in the linked list
// previous will point to the node that has largest value, but smaller than new node
n->next = previous->next; // insert new node between previous, and previous->next
previous->next = n;
return h; // return old head pointer
}
}
As you can see the third test spot the bug.
Of course, you could use some available third party Unit Test library, but the most important point is not the test library, but to write the tests.
Another point is that really you should interleave writing tests and writing implementation code.
This typically helps for writing good code and is what people call TDD. But my answer is probably already long enough, so I won't elaborate here on TDD.
I have been working on a project in C and I am having trouble when trying to copy char* using strcpy/memcpy/strncpy, none of these seem to work. The problem that is arising is that the words that are around 8 or more characters long are not being copied completely.
typedef struct wordFrequency {
char * word;
int frequency;
struct wordFrequency *left, *right;
} *node;
node setnode(char * word) {
node newNode = (node)malloc(sizeof(node));
newNode->word = (char*)malloc(sizeof(word));
strcpy(newNode->word, word); //This is where I'm having trouble
newNode->frequency = 1;
newNode->right = NULL;
return newNode;
}
The code above is what I believe is the main cause for error, but I don't know where to fix it. I have tried messing with the sizes, but that didn't work.
If possible can someone explain to me a way to copy all characters or if I did not allocate enough space?
This program is an mcve that shows how to properly allocate and initialize each node in your linked list:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ARRAY_SIZE(array) \
(sizeof(array) / sizeof(array[0]))
typedef struct wordFrequency {
char *word;
int frequency;
struct wordFrequency *left, *right;
} node;
node *setnode(char *word) {
node *newNode = malloc(sizeof(node));
newNode->word = malloc(strlen(word) + 1);
strcpy(newNode->word, word);
newNode->frequency = 1;
newNode->right = NULL;
return newNode;
}
int main() {
char *wordList[] = {"one", "two", "three"};
node nodeHead;
node *nodePrev = &nodeHead;
node *nodeNext;
for (int index = 0; index < ARRAY_SIZE(wordList); index++) {
nodeNext = setnode(wordList[index]);
nodePrev->right = nodeNext;
nodeNext->left = nodePrev;
nodePrev = nodeNext;
}
for (node *nodePtr = nodeHead.right; nodePtr != NULL; nodePtr = nodePtr->right) {
printf("word = %s, frequency = %d\n", nodePtr->word, nodePtr->frequency);
}
return 0;
}
Output
word = one, frequency = 1
word = two, frequency = 1
word = three, frequency = 1
Note
This program has no error checking and does not free the allocated memory. This code should not be used in a production environment.
Replies to Questions in Comments
I replaced *node with node in the typedef because that allows me to declare instances of node. The other syntax only allows pointers to node.
I use an instance of node instead of node * for nodeHead because any attempt to change its address will be an error.
I use nodePrev to traverse the list and also to provide a target for left in the returned nodes. I initialize nodePrev to &nodeHead because it is the start of the list. I set nodePrev to nodeNext because that's how I chose to traverse the list during initialization. I could have used
nodePrev = nodePrev->right;
and achieved the same effect.
I only implemented list handling so that I could create a self-contained example that would run without changes. You can safely ignore it.
If you want to see good linked list code, I recommend the linux kernel implementation.
I am not too good at making trees and I totally screw up recursion. However, I attempted to make a program to insert and display data into the tree.
The problem is that it crashes after inserting into the root node and I do not know why. The tree is not too big. Just 10 int.
#include <stdio.h>
#include <stdlib.h>
#define SIZE 10;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
struct node{
int data;
struct node * left;
struct node * right;
};
void insert(struct node * root,int num){
printf("Insert called for num:%d\n",num);
if(root == NULL){
root = (struct node *)malloc(sizeof(struct node));
root->data = num;
}else if(num > root->data){ // Number greater than root ?
insert(root->right,num); // Let the right sub-tree deal with it
}else if(num < root->data){// Number less than root ?
insert(root->left,num);// Let the left sub-tree deal with it.
}else{
// nothing, just return.
}
}
void display(struct node * root){ // Inorder traversal
if(root->left!=NULL){ // We still have children in left sub-tree ?
display(root->left); // Display them.
}
printf("%d",root->data); // Display the root data
if(root->right!=NULL){ // We still have children in right sub-tree ?
display(root->right); // Display them.
}
}
int main(int argc, char *argv[]) {
int a[10] = {2,1,3,5,4,6,7,9,8,10};
int i;
struct node * tree;
for(i = 0; i < 10;i++){
insert(tree,a[i]);
}
printf("Insert done");
return 0;
}
Can someone please tell me where I went wrong ?
I know it is frowned upon to ask people to review your code on Stack but sometimes pair programming works :p
Update:
After setting struct node * tree = NULL;, the insert() method works well. The display() causes program to crash.
in your
int main(int argc, char *argv[]) {
// ...
struct node * tree;
// what is the value of tree at this line?
for(i = 0; i < 10;i++){
insert(tree,a[i]);
}
// ...
}
what does "tree" point to at the line marked?