so I want to add inbetween two nodes of a linked list a new node whose data field basically contains the sum of the the previous and the next node. I can't understand why once I enter the while loop I can't get out of it. Any suggestions? Thank you.
Here's my code:
void modify_list (node *head) {
nodo *it = head;
nodo *prev = NULL;
int n_prev = 0;
int n_next = 0;
int sum = 0;
it = it->next;
prev = it;
while (it->next != NULL) {
it->data = n_next;
prev->data = n_prev;
sum = n_next + n_prev;
node *new;
new = malloc(sizeof(node));
if (new == NULL) {
printf("Error.\n");
return;
}
memset(nuovo, 0, sizeof(node));
new->data = sum;
prev->next = new;
new->next = it;
sum = 0;
prev = it;
it = it->next;
}
}
When you start the iteration, you are using:
it = it->next;
prev = it;
it and prev are pointing to the same node. A little while later, you are using:
prev->next = new;
which is the same as:
it->next = new;
That means it->next points to the new node. That means, you never really go past the newly created nodes.
You can fix this by using:
prev = it;
it = it->next;
before the start of the while loop.
I would make that more robust by using:
prev = it;
if ( it != NULL )
{
it = it->next;
}
At this time, it could be NULL. Change the conditional in the while statement to:
while (it != NULL) {
May I first suggest breaking your code up in smaller parts
Have a function that inserts a new object
For a singly linked list, this should insert after:
void InsertAfter( Node* n, DATA data )
{
Node* newnode = malloc(sizeof(Node));
newnode->data = data;
newnode->next = n->next;
n->next = newnode;
}
Then you have a function to find the insert-point
It could be for example
Node* FindLastSmaller( Node* n, DATA data )
{
while(true)
{
if( ! n->next ) return n;
if( n->next->data > data ) return n;
n = n->next;
}
}
Then they become easy to combine:
void InsertSorted( Node* n, DATA data )
{
Node* inspos = FindLastSmaller(n,data);
InsertAfter(inspos,data);
}
You can avoid adding special-cases for empty list, if head always
exists, and contains no data. (its a dummy node)
Related
I have a problem that I cannot introduce a temp NODE* and iterate to find the next NODE that is NULL (I marked it in the code with comment).
But, if I do:
parent->child->next->next = result
It works completely fine.
Any help?
typedef struct tNODE {
char* inner_text;
char* tag;
struct tNODE* parent;
struct tNODE* child;
struct tNODE* next;
}NODE;
NODE* new_node(NODE* parent){
NODE* result = (NODE*)malloc(sizeof(NODE));
result->inner_text = NULL;
result->tag = NULL;
result->parent = parent;
result->child = NULL;
result->next = NULL;
if (parent != NULL){
if (parent->child == NULL){
parent->child = result;
} else {
if (parent->child->next == NULL){
parent->child->next = result;
return result;
} else {
//HERE IS THE PROBLEM. A TEMP NODE DOES NOT WORK
//BUT parent->child->next->next = result works. WHY ? what should i do
NODE* temp = parent->child->next;
while(temp != NULL){
temp = temp->next;
}
temp = result;
}
}
}
return result;
}
If the parent has no children, you set the new node as the 1st child. OK.
If the parent has 1 child, you set the new node as the 2nd child. OK.
But, if the parent has more than 2 children, you are looping to the end of the child list, which is where you are going wrong. You are setting temp to point at each child in the list, and break the loop only when temp becomes NULL, meaning it is not pointing at any node at all, as you went beyond the end of your list. You lost track of the last child in the list. And then you are setting temp to point at the new node, but temp does not refer to the last child's next pointer in the list, so assigning it a value does not update the list at all.
Your logic needs to look more like this instead:
NODE* new_node(NODE* parent){
NODE* result = (NODE*) malloc(sizeof(NODE));
if (!result)
return NULL;
// in C++, use this instead:
// NODE* result = new NODE;
result->inner_text = NULL;
result->tag = NULL;
result->parent = parent;
result->child = NULL;
result->next = NULL;
if (parent){
// if no children yet, assign the
// new node as the first child ...
if (!parent->child){
parent->child = result;
} else {
// find the last child ...
NODE *temp = parent->child;
while (temp->next){
temp = temp->next;
}
// ... and set it to point at the
// new node as the next child ...
temp->next = result;
}
}
return result;
}
That being said, the logic can be simplified a bit more. Try this instead:
NODE* new_node(NODE* parent){
NODE* result = (NODE*) malloc(sizeof(NODE));
if (!result)
return NULL;
result->inner_text = NULL;
result->tag = NULL;
result->parent = parent;
result->child = NULL;
result->next = NULL;
if (parent){
// find the last NODE* pointer that is NULL ...
NODE **temp = &(parent->child);
while (*temp) {
temp = &((*temp)->next);
}
// ... and set it to point at the new node ...
*temp = result;
}
return result;
}
And, if you are free to add another member to your NODE type, the logic becomes even simpler as the entire loop can then be eliminated completely, eg:
typedef struct tNODE {
char* inner_text;
char* tag;
struct tNODE* parent;
struct tNODE* first_child;
struct tNODE* last_child;
struct tNODE* next;
}NODE;
NODE* new_node(NODE* parent){
NODE* result = (NODE*) malloc(sizeof(NODE));
if (!result)
return NULL;
result->inner_text = NULL;
result->tag = NULL;
result->parent = parent;
result->first_child = NULL;
result->last_child = NULL;
result->next = NULL;
if (parent){
NODE **temp = (parent->last_child)
? &(parent->last_child->next)
: &(parent->first_child);
*temp = result;
parent->last_child = result;
}
return result;
}
The assignment to temp can never change the linked list. To modify the linked list you need to dereference temp when it still points to the tail node, and then assign to its next member.
So that means you need to stop the loop one iteration earlier:
NODE* temp = parent->child;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = result;
Note that you don't need the innermost if as a special case. The case where parent->child->next == NULL can be dealt with using the code above.
Look at the two alternatives, they are quite different
parent->child->next->next = result;
and
NODE* temp = parent->child->next;
while(temp != NULL){
temp = temp->next;
}
temp = result;
The first one assigns to the next field of parent->child->next. The second assigns to the temp variable. These are not the same thing, it doesn't matter where the temp variable is pointing to when you make the assignment, the temp variable is not any part of your linked list.
Here is what your code should look like
NODE* temp = parent->child;
while(temp->next != NULL){
temp = temp->next;
}
temp->next = result;
In this code temp points to the node whose next field you want to change.
This is the code I tried writing down to add an element in a double linked list, that takes an index and a value and adds a new element to the original list.
It is taking index and value but just adds the elements I give like a stack.
node *add(node *head, int index, int val)
{
node *new = create(val);
node *temp = malloc(sizeof(node));
if (head == NULL)
{
head = new;
temp = head;
//printf(": %d",temp->data);
}
temp = head;
int i = 1;
while (i < (index - 1) && (temp->next != NULL))
{
i++;
temp = temp->next;
}
temp->next = new;
new->next = NULL;
new->prev = temp;
return head;
}
however this code(for a doubly linked list) just adds elements one after the other, disregarding the index passed.
My prof gave us a code for a singly linked list where he did something similar.
struct Node *insert(struct Node *listp, int pos, int info)
{
/*Inserts a Node in list at position pos with data info
pos>0. If pos>list length then new node added at end.
If pos<1 adds at beginning.
*/
struct Node *new=malloc(sizeof(struct Node)), *prev;// new is the new node we create everytime.
//create new node and initialize fields
new->data=info;
new->next=NULL;
if (listp==NULL) listp=new;
else
if (pos<=1) { //negative or 1 index.
new->next=listp; //first node bann gaya new
listp=new; //head is pointing at new
}
else {
//pos>1. Go to node at pos-1.
prev=listp;
int i=1;
while ((i++<pos-1) && prev->next!=NULL) { //indexing
prev=prev->next;
}
new->next=prev->next;
prev->next=new;
}
return listp;
}
how do I address this problem?
To implement a doubly linked list, your node needs to have pointers to the previous node and next node, then you can write something almost as similar to what your professor gave you for single linked list:-
#include <stdlib.h>
#include <stdio.h>
//Doubly linked list Node
typedef struct Node{
int info;
struct Node* next;
struct Node* prev;
} Node;
Node* insert(Node* listp, int pos, int info){
//Allocate memory for node and its previous neighbor
Node* new = malloc(sizeof(Node));
Node* prev = malloc(sizeof(Node)), *tail;
//initialize new node with these values
new->info = info;
new->next = NULL;
new->prev = NULL;
//if head doesn't exist then create one
if(listp == NULL){
/*
listp gets whatever new had, ie
listp->info = info
listp->next = NULL
listp->prev = NULL
*/
Node* tail = malloc(sizeof(Node));
tail->info = 0;
tail->next = NULL;
tail->prev = NULL;
listp = new;
listp->next = tail;
tail->prev = listp;
}
//Lets Loop through the List and insert node at pos
else {
if(pos <= 1){
/*
This should replace the current head
listp = new
*/
new->next = listp;
new->prev = listp->prev;
listp->prev = new;
listp = new;
}
else{
int i = 2;
prev = listp->next;
printf("%d\n", prev->prev->info);
while(i != pos){
printf("%d\n", new->info);
prev = prev->next;
i++;
}
new->next = prev;
new->prev = prev->prev;
prev->prev->next = new;
prev->prev = new;
}
}
return listp;
}
// Test case
int main(){
Node* listp;
listp = insert(NULL, 0, 2);
listp = insert(listp, 1, 3);
listp = insert(listp, 2, 5);
Node* cnt = listp;
printf("|");
while(cnt->next != NULL){
printf("--%d-->", cnt->info);
cnt = cnt->next;
}
printf("\n");
}
Try that. Make any typo corrections if any
#include <stdio.h>
#include <stdlib.h>
/**
* add_node_end - adds a new node at the end of a dllist list
* #head: head of linked list
* #n: integer value of node
*
* Return: address of new element, NULL if fails
*/
node *add_node_end(node **head, const int n)
{
node *new, *temp;
new = malloc(sizeof(node));
if (new == NULL)
return (NULL);
new->n = n;
new->next = NULL;
if (*head == NULL)
{
new->prev = NULL;
*head = new;
return (*head);
}
temp = *head;
while (temp->next)
{
temp = temp->next;
}
temp->next = new;
new->prev = temp;
return (new);
}
/**
* add_dnodeint - adds a new node at the beginning of a dlistint_t list
* #head: head of linked list
* #n: integer value of node
*
* Return: address of new element, NULL if fails
*/
node *add_node_start(node **head, const int n)
{
node *new;
new = malloc(sizeof(node));
if (new == NULL)
return (NULL);
new->n = n;
new->prev = NULL;
if (*head == NULL)
{
new->next = NULL;
*head = new;
return (*head);
}
new->next = *head;
(*head)->prev = new;
*head = new;
return (*head);
}
/**
* node_len - returns the number of elements in a dllist list
* #h: head of doubly linked list
*
* Return: number of nodes
*/
size_t node_len(const node *h)
{
int count = 0;
while (h)
{
count++;
h = h->next;
}
return (count);
}
/**
* insert_dnodeint_at_index - inserts a new node at a given position
* #h: a pointer to a pointer of the first node of node linked list
* #index: the position to add the new node
* #val: the data n of the new node
* Return: if the function fails = NULL
* otherwise - the address of the new node/element
*/
node *insert_dnodeint_at_index(node **h, unsigned int index, int val)
{
node *newNode, *current;
size_t list_length;
unsigned int i = 0;
if (h == NULL)
return (NULL);
if (index == 0)
return (add_node_start(h, n));
list_length = node_len(*h);
if (index == (list_length - 1))
return (add_node_end(h, n));
newNode = malloc(sizeof(node));
if (newNode == NULL)
return (NULL);
newNode->val = val;
if (*h == NULL)
{
newNode->prev = NULL;
newNode->next = NULL;
return (newNode);
}
current = *h;
while (current)
{
if (i == index)
{
newNode->next = current;
newNode->prev = current->prev;
current->prev->next = newNode;
current->prev = newNode;
return (newNode);
}
current = current->next;
i++;
}
free(newNode);
return (NULL);
}
Basically what title says, Im trying to append (add to end of my list). my BuildList function takes in a size parameter that determines how many nodes the list will have. my problem is with my append function. So if I have 5 as my head, how do I fix my append function so that random numbers will be added after 5?
typedef struct Node
{
int value;
struct Node* next;
} Node;
Node *createNode( int num )
{
Node *ptr;
ptr = (Node *) malloc( sizeof( Node ) );
ptr->value = num;
ptr->next = NULL;
return ptr;
}
Node* append (Node* head, Node* newNode)
{
if (head == NULL)
return newNode;
while (head -> next != NULL);
head -> next = newNode;
return head;
}
Node* buildList (int size)
{
Node* newNode = (Node*) malloc (sizeof(Node));
Node* head = NULL;
for (int i = 0; i < size; i++)
{
Node* newNode = createNode (rand () % 10);
head = append (head, newNode);
}
return head;
}
Well, the most glaring issue is this
while (head -> next != NULL);
I believe you meant to write something like this
Node *tmp = head;
while (tmp -> next != NULL) {
tmp = tmp->next;
}
tmp->next = newNode;
You don't want to modify head here since you return it later in the function. If you didn't use tmp, head would always point to the penultimate node in the list.
You just need to modify your while, why do you have an empty instruction there? If the head is not NULL then you will never exit:
while (head -> next != NULL)
{
head = head -> next;
}
I need some help.
I have this homework assignment due on Wednesday and the only thing I haven't been able to do is reverse my linked list. I have literally been working on this all day.
My professor hasn't told us any way to do this and doesn't allow us to email him questions so I'm kind of stuck.
He wants us to accomplish this by using nested while loops and pointers called front & back, and newhead.
Below is my code. Let me know if you have any questions and thanks in advance.
NOTE: Code is compiled in Code::Blocks using the GNU compiler.
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int random_number;
struct node *next;
} Node;
typedef Node *Nodeptr;
void printout(Nodeptr);
void sum(Nodeptr);
void reverse(Nodeptr);
int main() {
Nodeptr head = NULL;
if ((head = malloc(sizeof(Node))) == NULL)
return 0;
head->random_number = rand() % 50 + 50;
head->next = NULL;
Nodeptr here = head;
Nodeptr newnode = NULL;
int n;
for (n = 0; n < 10; n++) {
if ((newnode = malloc(sizeof(Node))) == NULL)
return 0;
newnode->random_number = rand() % 50 + 50;
newnode->next = NULL;
here->next = newnode;
here = here->next;
}
printout(head);
sum(head);
reverse(&head);
printout(head);
return 0;
}
void printout(Nodeptr head) {
Nodeptr aux = head;
int n = 0;
while (aux != NULL) {
printf("The value of node no. %d is %d \n", n, aux->random_number);
aux = aux->next;
n++;
}
}
void sum(Nodeptr head) {
Nodeptr aux = head;
int n = 0, sum = 0;
while (aux != NULL) {
sum += aux->random_number;
aux = aux->next;
n++;
}
printf("The sum total of all nodes in this list is %d\n", sum);
}
void reverse(Nodeptr head) {
Nodeptr newhead = head;
Nodeptr back = NULL;
Nodeptr front = NULL;
while (back != NULL) {
front->next = back;
back = NULL;
front = head->next;
back = head;
while (front != NULL) {
front = newhead->next;
newhead->next = back;
back = newhead;
}
newhead = head;
}
}
If you reverse a linked list:
A -> B -> C -> D -> E (odd numbered case)
E -> D -> C -> B -> A
A -> B -> C -> D (even numbered case)
D -> C -> B -> A
Do you see how the items have changed place? In the odd numbered case, A swapped places with E, B with D and C didn't move.
Now do you have some idea how to do it via a loop? The outer loop goes from the start of the list to the half-way point, the inner loop locates the matching item to swap them.
Definitely not the most efficient way to reverse a linked list, but I guess it's just a way to get you think more about the data structure.
The reverse() you posted didn't make sense, because the pointer values are incorrect. With back initialized to NULL, the while loop will not execute at all.
I am not sure what API you teacher want you to use for reverse:
The simplest one would take a Node * and return the new head pointer. You would invoke it from main as head = reverse(head);
Here is a simple implementation of this approach:
Node *reverse(Node *head) {
Node *front = head;
Node *newhead = NULL;
while (front) {
Node *back = front->next;
front->next = newhead;
newhead = front;
front = back;
}
return newhead;
}
An alternative API would have reverse take a pointer to the head pointer, hence a Node **, and update that to point to the reversed list.
Here is how it works:
void reverse(Node **headp) {
Node *front = *headp;
Node *newhead = NULL;
while (front) {
Node *back = front->next;
front->next = newhead;
newhead = front;
front = back;
}
*headp = newhead;
}
Note that you do not need nested loops.
Note also that you should not hide pointers behind typedefs, it is bad practice, error prone and creates confusion for both the next reader and the original author.
I'm having trouble inserting in a Binary Search Tree using for loop, when I call the InorderTraversal function, there is no output all I get is a blank line, as far as I think rest of the code is okay the only problem is in the insert function.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct BinaryTree{
int data;
struct BinaryTree *left;
struct BinaryTree *right;
} node;
node* Insert(node* head, int value)
{
_Bool flag = true;
for(node *temp = head; flag == true; (temp = (value >= temp->data)?(temp->right):(temp->left)))
{
if(temp == NULL)
{
temp = (node*)malloc(sizeof(node*));
temp->data = value;
temp->left = NULL;
temp->right = NULL;
flag = false;
}
}
return head;
}
void InorderTraversal(node* head)
{
if(head == NULL)
{
return;
}
InorderTraversal(head->left);
printf("%d ",head->data);
InorderTraversal(head->right);
}
int main(void)
{
node *head = NULL;
for(int i = 0; i < 40; i++)
{
head = Insert(head,i);
}
InorderTraversal(head);
return 0;
}
Here try these changes in your Insert function
node* Insert(node *head, int value)
{
if(!head) //Explicitly insert into head if it is NULL
{
head = malloc(sizeof *head);
head->data = value;
head->left = NULL;
head->right = NULL;
return head;
}
for(node *temp = head,*temp2 = head; ;(temp = (value >= temp->data)?(temp->right):(temp->left)))
{
if(temp == NULL)
{
temp = malloc(sizeof *temp);
temp->data = value;
temp->left = NULL;
temp->right = NULL;
if(value >= temp2->data) //update previous nodes left or right pointer accordingly
temp2->right = temp;
else
temp2->left = temp;
break;
}
temp2 = temp; //Use a another pointer to store previous value of node
}
return head;
}
Call me crazy, but shouldn't that malloc(sizeof(node*)) be malloc(sizeof node)?
I am not that so informed, other than being able to read C, so excuse me if this is simply wrong...
Edit: ... or malloc(sizeof * temp)
When you insert the first node you dereference an uninitialized pointer here:
temp->data
Where temp is head and head in uninitialized and pointing to NULL.
So you first have to make special case when head is NULL:
if( !head )
{
head = malloc(sizeof(node));
head->data = value;
head->left = NULL;
head->right = NULL;
return head ;
}
When you continue adding elements you don't update the pointer of the last node. Your for loop should have an extra pointer to the previous node and when you get to the last node and find NULL update the previous nodes left or right pointer.
if(temp == NULL) //wrong, should be: not equal
{
temp = (node*)malloc(sizeof(node*)); //wrong, should be: sizeof the node not the pointer
temp->data = value;
temp->left = NULL;
temp->right = NULL;
flag = false; //use break instead
}
here the previous node pointer left or right is not updated and when you search you can't find any node.