Adding nodes in C Linked List and listing them - c

I'm practicing with linked lists in c, I want to make a program that reads entries from keyboard and lists the contents of the linked list after adding each node, but the output is always the first node, i can't figure out why, could someone please point out the flaw in this code:
#include <stdio.h>
#include <stdlib.h>
typedef int ID;
typedef struct node {
ID id;
struct node * next;
} node_t;
int main(){
node_t * head;
node_t * conductor;
head = NULL;
ID id;
int i=0;
while(i<10){
printf("Introduce an id:\n");
scanf("%d", &id);
if(head == NULL){
head = malloc(sizeof(node_t));
head->id = id;
head->next = NULL;
}
else{
conductor = head;
while(conductor != NULL)
conductor = conductor->next;
conductor = malloc(sizeof(node_t));
conductor->id = id;
conductor->next = NULL;
}
conductor = head;
printf("the list contains these elements:\n");
while(conductor != NULL){
printf("%d\n", conductor->id);
conductor = conductor->next;
}
++i;
}
}

He problem is in your while loop at
while (conductor != NULL)
To add a new node, you need to set conductor->next, after finding the last conductor.
Something like this could work:
While (conductor->next != NULL)

You are running off the end of the list before inserting. You should go till conductor->next becomes NULL , insert new node and set conductor->next to point to the new node.
Some other pointers:
Indent properly. This will make it easier to spot errors
Split code into functions such as addNode, removeNode, printList etc,
Adding elements one by one to end of linked list is O(n) time for each insertion. Either maintain tail pointer or insert at the head for O(1) insertion. This is very important and results in lot of speedup with trivial effort. With head & tail being tracked, you can insert both sides and remove from head in O(1). Removal from tail will still take O(n) though AFAIK

You need something like the following
conductor = head;
// Find the last node in the list
while(conductor->next != NULL)
conductor = conductor->next;
// Setup the new node
node_t* newNode = malloc(sizeof(node_t));
newNode->id = id;
newNode->next = NULL;
// Have the last node's next pointer point to the new node
constructor->next = newNode;
The key is that you move constructor to the last node in the list, the new node will be wired into the list following the last node.
Typically with a linked list you should keep track of the current head and tail, this will improve performance when adding new nodes, you will note need to traverse the existing list everytime.

Related

create linked list using char array as data

I am having a problem on assigning char array after I create a node.
I am having trouble on this function I created which it would make a new node and then assign character array into the created node. I don't have any problems when it comes to int but I can't seem to run when I switched to character array.
I get a run time error when I try to run my code.
Any help would be much appreciated.
Thank You!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 100
struct node{
char data[MAX];
struct node *next;
};
typedef struct node* nodePtr;
void create(nodePtr head, char data[]);
int main()
{
nodePtr head = NULL;
char str[] = "HELLO";
create(head, str);
return 0;
}
void create(nodePtr head, char data[])
{
if (head == NULL)
{
// empty list
head = (nodePtr) malloc(sizeof(struct node)); // create root
strcpy(head->data, data);
head->next = NULL;
}
else
{ // list not empty
nodePtr current = head; // start at the beginning...
while (current->next != NULL)
{
current = current->next; // walk to the end of the list
}
current->next = (nodePtr) malloc(sizeof(struct node));
current = current->next;
strcpy(current->data, data);
}
}
There is more than one problem with your program.
To begin with, when you add elements to a list that already has a head, are not initializing the next member. This will cause multiple list insertions to fail.
current->next = malloc(sizeof(struct node));
current = current->next;
strcpy(current->data, data);
current->next = NULL; //<-- you forgot this
The other big issue is that you are also leaking your entire list, because you pass the head pointer by value into the function. When the list is empty, the function modifies this value but it's a copy so when the function returns, the value of head in main is still NULL.
There are two options. Either you change your function to expect a pointer to the head-pointer, or you use what's called a "dummy head".
Using a dummy head actually simplifies lists a lot. What this means is your head is actually an unused node whose sole responsibility is to store the actual head in its next-pointer:
struct node head = {}; // dummy head node
create(&head, str);
The above will never actually hit the head == NULL part of the create function because dummy heads guarantee the head is always a valid node. So if you set your list up that way, then your create function can be simplified.
If you don't want to do this, then you need to pass a pointer to your head pointer. That means your create function becomes:
void create(nodePtr *head, char data[])
{
if (*head == NULL)
{
*head = malloc(sizeof(struct node));
strcpy((*head)->data, data);
(*head)->next = NULL;
}
else
{
nodePtr current = *head;
while (current->next != NULL) current = current->next;
current->next = malloc(sizeof(struct node));
current = current->next;
if (current != NULL)
{
strcpy(current->data, data);
current->next = NULL;
}
}
}
And you would invoke the above as:
nodePtr head = NULL;
create(&head, str);
One extra thing you might wish to do is make the function return the node that it created. The reason you might want to do this is that currently if you're inserting many items into the list you have to search to the end every time. If instead you pass the last node as the next head, then no searching is necessary:
nodePtr head = NULL;
nodePtr tail = head;
tail = create(head, "goodbye");
tail = create(tail, "cruel");
tail = create(tail, "world");
This would mean a small modification to your function, but I'm sure you can work that out.

Linked List Reversal has errors

In our class right now we're covering nodes and linked lists, and are working on our first linked list program.
We've been given the following guidelines by the teacher:
Make sure your main function will accept 10 characters from STDIN and create a linked list with those characters (so your nodes will have a char member). Then, add an additional function called reverse. The purpose of the reverse function will be to create a copy of the linked list with the nodes reversed. Finally, print off the original linked list as well as the reversed linked list.
I've gotten it all written out, and I've compiled it with no errors - but the program doesn't work as intended, and I'm not entirely sure why. I'm sure it has something to do with how I've set up the pointers to "walk" the nodes - as the debug I put in shows it looping twice per user input letter. Specifications are that we're only supposed to use one function, and we pass a Node* to the function, and it returns the same. The function cannot print out anything - only make the second list that is a reverse of the first.
Any help would be greatly appreciated, I'm not terribly good at this yet and I'm sure I've made some rather silly mistakes.
#include <stdio.h>
#include <stdlib.h>
//struct declaration with self-reference to make a linked list
struct charNode {
char data;
struct charNode *nextPtr;
struct prevNode *prevPtr;
};
typedef struct charNode Node; //makes Node an alias for charNode
typedef Node *NodePtr; //makes NodePtr an alias for a pointer to Node (I think?)
//function declaration for a reverse function
Node* reverse(Node *stPtr);
int main(void)
{
//main function takes 10 letters and puts them in a linked list
//after that, it calls the reverse function to create a reversed list of those characters
//lastly it prints both lists
NodePtr newNode = NULL;
char input;
Node* revStart;
unsigned int counter = 0;
printf("Enter 10 letters to make a list: ");
NodePtr currentPtr = NULL; //sets currentPointer to startNode.
NodePtr previousPtr = NULL; //set previousPointer to null to start
while(counter<= 10)
{
scanf("%c", &input); //gather next letter
NodePtr newNode = malloc(sizeof(Node)); //creates a new node
if (newNode != NULL) //checks to make sure the node was allocated correctly
{
newNode->data = input; //makes the new node's data == input
newNode->nextPtr = NULL; //makes the nextPtr of the newNode NULL
}
currentPtr = newNode; //sets currentPtr to the address of the newNode
if(previousPtr == NULL) { //first time around previousPtr == NULL
newNode->nextPtr = newNode;
previousPtr = newNode; //sets previousPtr to the address of the new node (1st time only)
} else { //afterwards, currentPtr won't be NULL
previousPtr->nextPtr = currentPtr; //last node's pointer points to the current node
previousPtr = newNode; //update previous pointer to the current node
}
++counter;
//debug
printf("\nLoop #%d\n", counter);
}
revStart = reverse(newNode);
puts("The list is: ");
while (newNode != NULL){
printf("%c --> ", newNode->data);
currentPtr = currentPtr->nextPtr;
}
puts("NULL\n");
}
//reversing the nodes
Node* reverse(Node *stPtr)
{
//make a new node
NodePtr currentPtr = stPtr->nextPtr; //get the next letter ready (this will point to #2)
NodePtr prevRevPtr = NULL; //previous reverse node pointer
Node* revStart;
for(unsigned int counter = 1; counter <= 10; ++counter)
{
NodePtr revNode = malloc(sizeof(Node));
if(revNode != NULL) //if reverseNode is allocated...
{
if(prevRevPtr = NULL) //if previousReversePointer = NULL it's the "first" letter
{
revNode->data = stPtr->data; //letter = current letter
revNode->nextPtr = NULL; //this is the "last" letter, so NULL terminate
prevRevPtr = revNode; //previousReversePointer is this one
}else //after the first loop, the previous ReversePointer will be set
{
revNode->data = currentPtr->data; //set it's data to the pointer's data
revNode->nextPtr = prevRevPtr; //reverseNode's pointer points to last node entered
currentPtr = currentPtr->nextPtr; //moves to next letter
prevRevPtr = revNode; //changes previous reverse node to current node
if(counter == 10)//on the last loop...
{
revStart = revNode; //set revStart as a pointer to the last reverse node
//which is technically the "first"
}
}
}
}
return revStart;
}
Assuming your list is properly wired from inception, reversing a double-linked list is basically this:
Node *reverse(Node *stPtr)
{
Node *lst = stPtr, *cur = stPtr;
while (cur)
{
Node *tmp = cur->nextPtr;
cur->nextPtr = cur->prevPtr;
cur->prevPtr = tmp;
lst = cur;
cur = tmp;
}
return lst;
}
That's it . All this does is walk the list, swapping pointers, and retaining whatever the last node processed was. When done correctly the list will still be end-terminated (first node 'prev' is null, last node 'next' is null, and properly wired between.
I strongly advise walking a list enumeration through this function in a debugger. With each iteration watch what happens to cur as it marches down the list, to the active node's nextPtr and prevPtr values as their swapped, and to lst, which always retains the last-node processed. It's the new list head when done.
Okay so we don't need to contend with no line breaks in commments:
Node *reverse(Node *list) {
Node *rev = NULL;
while (list) {
Node *elt = list; // pop from the list
list = list->next;
elt->next = rev; // push onto reversed list.
rev = elt;
}
return rev;
}
As you wrote in comments, you probably don't need to have a previous pointer; you can just create a singly linked list.
There are several issues in your code, including:
When malloc returns NULL, you still continue with the loop -- only part of the code is protected by the if that follows, but not the rest. You should probably just exit the program when this happens.
Your algorithm does not maintain a reference to the very first node, i.e. the place where the linked list starts. When you print the list you should start with the first node of the list, but instead you start with newNode, which is the last node you created, so obviously not much will be printed except that last node. Moreover, both other pointers you have, will also point to the last node (currentPtr, previousPtr) when the loop ends.
newNode->nextPtr = newNode; temporarily creates an infinite cycle in your list. This is resolved in the next iteration of the loop, but it is unnecessary to ever make the list cyclic.
In the reverse function you have if(prevRevPtr = NULL)... You should get a warning about that, because that is an assignment, not a comparison.
Some other remarks:
The reverse function unnecessarily makes distinction between dealing with the first node and the other nodes.
It is also not nice that it expects the list to have 10 nodes. It would be better to just rely on the fact that the last node will have a NULL for its nextPtr.
It is a common habit to call the first node of a linked list, its head. So naming your variables like that is good practice.
As you are required to print both the initial list and the reversed list, it would be good to create a function that will print a list.
As you need to create new nodes both for the initial list and for the reversed list, it would be good to create a function that will create a node for you.
(I know that your teacher asked to create only one function, but this is just best practice. If this doesn't fit the assignment, then you'll have to go with the malloc-related code duplication, which is a pitty).
As you defined the type NodePtr, it is confusing to see a mix of Node* and NodePtr in your code.
Your question was first not clear on whether the reversal of the list should be in-place or should build a new list without tampering with the initial list. From comments it became clear you needed a new list.
I probably didn't cover all problems with the code. Here is a corrected version:
#include <stdio.h>
#include <stdlib.h>
struct charNode {
char data;
struct charNode *nextPtr;
};
typedef struct charNode Node;
typedef Node *NodePtr;
NodePtr reverse(Node *stPtr);
void printList(Node *headPtr);
NodePtr createNode(int data, NodePtr nextPtr);
int main(void) {
NodePtr headPtr = NULL; // You need a pointer to the very first node
NodePtr tailPtr = NULL; // Maybe a better name for currentPtr
printf("Enter 10 letters to make a list: ");
for (int counter = 0; counter < 10; counter++) {
char input;
scanf("%c", &input);
NodePtr newNode = createNode(input, NULL);
if (headPtr == NULL) {
headPtr = newNode;
} else {
tailPtr->nextPtr = newNode;
}
tailPtr = newNode;
}
NodePtr revHeadPtr = reverse(headPtr);
puts("The list is:\n");
printList(headPtr);
puts("The reversed list is:\n");
printList(revHeadPtr);
}
void printList(NodePtr headPtr) {
while (headPtr != NULL) {
printf("%c --> ", headPtr->data);
// You can just move the head pointer: it is a variable local to this function
headPtr = headPtr->nextPtr;
}
puts("NULL\n");
}
NodePtr createNode(int data, NodePtr nextPtr) {
NodePtr newNode = malloc(sizeof(Node));
if (newNode == NULL) { // If malloc fails, exit the program
puts("Cannot allocate memory\n");
exit(1);
}
newNode->data = data;
newNode->nextPtr = nextPtr;
return newNode;
}
NodePtr reverse(NodePtr headPtr) {
NodePtr revHeadPtr = NULL;
while (headPtr != NULL) {
revHeadPtr = createNode(headPtr->data, revHeadPtr);
// You can just move the head pointer: it is a variable local to this function
headPtr = headPtr->nextPtr;
}
return revHeadPtr;
}

insertion sort doubly linked list

I'm trying to do an insertion sort on a doubly linked list in C. in this state, my code gets me stuck in an non-ending loop spitting out 8s and 9s.
can someone please be kind enough to explain how the "insertionSort" method is supposed to be designed?
my linked list is designed containing head, previous, next and some data.
Here is my code so far
My hope is NULL. please help.
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* next;
struct Node* previous;
}Node;
struct Node* head = NULL;
struct Node* current = NULL;
struct Node* headsorted = NULL;
int l = 0;
int empty = 1;
int length = 0;
int change = 0;
void InsertSort(){
Node* temp = (Node*)malloc(sizeof(struct Node));
temp = head;
current = head->next;
printf("\nInsert Sort begins...\n");
if (head != NULL && head->next != NULL)
{
for (int i = 1; i < length; i++)
{
while(current->data > current->next->data && current->next != NULL && current != NULL)
{
temp = current;
current = current->next;
current->next = temp;
}
}
}
else
{
printf("\nList Error!\n");
}
temp = NULL;
}
void Insert(int x)
{
Node* temp = (Node*)malloc(sizeof(struct Node));
temp->data = x;
temp->next = head;
temp->previous = NULL;
if (head != NULL)
{
head->previous = temp;
}
head = temp;
}
void Print(){
struct Node* temp = head;
printf("List is: ");
while(temp != NULL)
{
printf(" %d", temp->data);
temp = temp->next;
}
}
int main()
{
head = NULL;
FILE * file = fopen("List.txt", "r");
fscanf(file, "%d", &l);
while (!feof (file))
{
Insert(l);
fscanf(file, "%d", &l);
length++;
}
fclose(file);
Print();
printf("\n\n\n");
printf("data: %d next: %d " , head->data, head->next->data);
InsertSort();
Print();
return 0;
}
can someone please be kind enough to explain how the "insertionSort"
method is supposed to be designed?
In the first place, I suggest getting rid of the length variable, or at least not using it in your sort routine. It is not needed, and relying on it may be diverting your thinking too much toward array-style implementations. You know you've reached the end of the list when you discover a node whose next pointer is NULL.
Secondly, I reiterate my comment that you are not performing node swaps correctly for a doubly-linked list. A node swap on any linked list, whether singly- or doubly-linked, is equivalent to extracting the second node from the list altogether, then reinserting it before the first. In a singly-linked list that affects, in general, three nodes: in addition to the two being swapped, the predecessor to the first. In a doubly-linked list, it also affects the successor to the second. That's messy enough in the doubly-linked case that I suggest structuring it explicitly as an excision followed by an insertion.
But I also suggest that you take a step back and look at the algorithm from a high level. It works by considering each node in turn, starting with the second, and if necessary removing it and reinserting it at its correct position in the (sorted) sublist preceding it. So what, then, does pairwise swapping even have to do with it? Nothing. That's a detail convenient in implementing such a sort on an array, but it makes needless work when sorting a linked list.
For a linked list, especially a doubly-linked one, I suggest an implementation cleaving more directly to the abstract description of the algorithm:
Maintain a pointer, S, to the last node of the sorted leading sublist. Initially, this will point to the list head.
If S points to the last node (which you can judge by S->next) then stop.
Otherwise, check whether *N, the successor to *S, is correctly ordered relative to *S.
If so, then set S (the pointer, not its referrent) equal to N.
If not, then
cut the *N from the list (updating both its predecessor and its successor, if any, appropriately), and
step backward through the sorted sublist until you reach either the first node or one whose predecessor should precede *N, whichever is encountered first.
Insert *N before the node you've discovered.
If that makes *N the list head (which you can judge by the new value of its previous pointer), then set the head pointer (not its referrent) equal to N.
repeat from point 2
The actual code is left as the exercise it is intended to be.

Linked list traversing with and without the next field

I have written two functions while learning Linked list. First counts and returns number of nodes in the list. Second adds new node towards the end of the list. Can you please help me understand why I need to use "current->next" to check for NULL in my code below in the addatend function? I did not have to use it for first function. Without that my exe crashes with bad pointer...
Thank you very much for your time and help.
int length(node * head) {
node * current = head;
int count = 0;
while(current != NULL){ // This line works as expected....
count ++;
current = current->next;
}
return count;
}
void addatend (node * head, int value){
node * newnode = (struct node *) malloc(sizeof(struct node));
node * current = head;
while (current != NULL){ // This line would not work?? If I use current->next != NULL it works.....
current = current->next;
}
current->next = newnode;
newnode->data = value;
newnode->next = NULL;
}
In the second function your are accessing current->MEMBER after you changed it to current->next, while in the first one you are not. That is, in the first one you just run to end, and end up with a NULL pointer, but you don't use it, so it's ok. In the second one, you do use it.
In order not to mess up with your original linked-list you copy the head to the current, and then you can do what you want with that current node.
Linked lists are generated like:
typedef struct e
{
int data;
struct e *next;
} node;
which means each node (in my example) has a data of type integer and a pointer to the next node. Let's suppose that our list has 4 objects:
1->2->3->4->NULL
the first node (data=1) point to its next node (data=2) and so on till last node (data=4) which the next node does not exist so will point to NULL.
in the function "addatend" in order to add new node to the end of the linked-list you should travel through the last element of the list (data=4 in my example), which the node next to it will point to NULL, so you should go through the list till the end and when you arrive there, you can add the "newnode".

Singly linked list - push_back

I have to create method push_back which will add an item to the end of my list.
But I have one constraint - I can't check if head is empty (if head is null)
I don't have idea how I can do this. Here is my code:
#include <stdio.h>
#include <stdlib.h>
struct node
{
int value;
struct node* next;
};
void print(struct node* head)
{
struct node* iterator = head;
while (iterator != NULL)
{
printf("%d\n", iterator->value);
iterator = iterator->next;
}
printf("\n");
}
void pushBack(struct node** head, int value)
{
struct node* element = (struct node*)malloc(sizeof(struct node));
struct node* iterator = *head;
element->value = value;
element->next = NULL;
if (iterator == NULL) //can't!
{
*head = element;
return;
}
while (iterator->next != NULL)
{
iterator = iterator->next;
}
iterator->next = element;
}
int main(void)
{
struct node* head = NULL;
pushBack(&head, 4);
pushBack(&head, 5);
pushBack(&head, 52);
pushBack(&head, 1);
print(head);
return 0;
}
Any ideas how I can get working push_back method without checking head and without empty nodes?
My teacher asked after classes, where we was discussing about linked list, if it's possible to do this - no one knew how it can be done.
I think you may have misunderstood your instructors wishes. I believe the instructor desired you not check if (head); Instead check if (*head). They're not the same condition.
In your code, head is a pointer to pointer. Though you may pedantically wish to check that someone did not pass you a null pointer to pointer, the fact is all you really care about is whether the pointer it points to is null (thus the dereference).
And that considerably reduces your code lineage.
void pushBack(struct node** head, int value)
{
while (*head)
head = &(*head)->next;
*head = malloc(sizeof(**head));
(*head)->value = value;
(*head)->next = NULL;
}
Yes of course you can do this. Thats a very good use for a pointer-to-a-pointer. You can even use pushBack() like this:
pushBack(&(element->next), 4);
if element is a pointer to the last element!
If you return the new element from pushBack, you can add new elements in constant time O(1), because you don't have to iterate through all the previous elements.
If head points to the last element in the list then you just say
newItem->next = head;
head = newItem;
of course this operations is more often called a "push". I've not heard the term push back.
This sounds like a data structures class problem. The answer should be in the reading assignments.
But anyway. I believe the answer is to use a circular linked list. What this is, is a head pointer to an empty node. The empty node marks the beginning AND end of the list. Doing it this way simplifies all of the list operations, because it completely removes the need to operate on the head pointer.

Resources