Sorted insert program in a linked list - c

I am a beginner in Data structures and I am learning linked list now .
I encountered a program about sorted insert where I had an add() function to add the nodes in the sorted order
/*Linked List program to add ascending order sorted nodes in
the list */
#include <stdio.h>
#include <stdlib.h>
enter code here
struct node {
int data ;
struct node link;
};
void add(struct node **q,int num){
struct node *r,*temp = *q;
r = malloc(sizeof(struct node )); //Data Allocated
r->data = num;
if(*q==NULL ||(*q)->data >num){
*q = r;
(*q)->link = temp;
}else{
while(temp !=NULL){
if(temp->data <=num &&(temp->link->data >num
||temp->link==NULL)){
r->link = temp->link;
temp->link=r;
return;
}
temp = temp->link;
}
}
}
void main(){
struct node *p;
p = NULL;
}
I have expected to add the nodes in sorted ascending order but when I input data then error is shown.I am Using Code Blocks to run the program in C
I think it has to do something with the end condition temp->link == null but I am unable to figure out exact condition for that part of code .Please Help !

The definition for the structure struct node is not correct. I assume it is a typo. It should be struct node *link;
Your conditions for traversing the loop are not correct. As mentioned in the comments, you are accessing temp->link in case it might be NULL.
You are not checking for the condition that the number to be added is greater than all the numbers and is to be added at the end of the list.
The modified function is below.
void add(struct node **q,int num){
struct node *r,*temp = *q;
r = malloc(sizeof(struct node )); //Data Allocated
r->data = num;
r->link = NULL;
if(*q==NULL ||(*q)->data >num){
*q = r;
(*q)->link = temp;
}else{
while(temp->link !=NULL){
if(temp->data <=num &&(temp->link->data >num)){
r->link = temp->link;
temp->link=r;
return;
}
temp = temp->link;
}
temp ->link = r; // add at the end as not added at any other location.
}
}

In addition to Rishikesh Raje's answer (you need to use a pointer inside struct: struct node* link;; you need to check first for link being null, then access link->data), the loop can be simplified quite a bit:
// advance only, if we need to insert (at least) after temp->link:
while(temp->link && temp->link->data <= num)
{
temp = temp->link;
}
// once the loop is done, temp points to the last element smaller than num, so:
r->link = temp->link;
temp->link = r;
Inside the while, we don't need to check for temp->data > num; we re-enter the loop only, if the loop condition was met previously, which checked exactly this condition already; remains the very first loop run; however, in this case, your if before the loop covered the condition already.
Side note: Is it a requirement to insert new elements after the existing ones? If not, inserting in front of is a bit faster, all you'd do is replacing <= with < and > with >=...

You should use
( temp->link == NULL || temp->link->data > num )
instead of
( temp->link->data > num || temp->link == NULL )
because if temp->link is NULL, the first code will return true immediately after checking the first condition and will not check the second condition, thus you will not get an error.
But when you use it like in the second expression, if temp->link is NULL, you will get an error because you are trying to reach a field named "data" of a NULL object with the code
temp->link->data

Related

sort a singly linked list formed of 1, 2 and 0s by swapping the nodes through one traversal in C

I'm trying to solve the question that I need to sort a given linked list which values consist of 1, 2 and 0 by traversing the list only once and I need to swap the nodes not values.
my code is:
#define max 3
void sortList(node **headRef)
{
if(*headRef==NULL){
return;
}
node* head[max];
node*tail[max];
node* curr=*headRef;
int i;
for(i=0; i<max; i++){
head[i]=tail[i]=NULL;
}
while(curr!=NULL){
i=curr->data;
if(head[i]==NULL){
head[i]=tail[i]=curr;
}
else{
tail[i]=tail[i]->next=curr;
}
curr=curr->next;
}
for(int i=0, curr=(*headRef)=NULL; i<max; i++){
if(head[i]!=NULL){
if(*headRef==NULL){
*headRef=head[i];
}
else{
curr = curr->next =head[i];
}
curr=tail[i];
}
}
curr->next=NULL;
}
but it keep giving me an error and I don't know how to solve it if anyone can help me please.
Your problem is this:
for(int i=0, curr=(*headRef)=NULL; i<max; i++)
^^^^^^^ here ^^^^^^^
And you solve it by better-understanding the features of the language you're using before you use them. The optional declaration + initialization part of a for-loop allows you to not only initialize, but also declare variables (and in this case, shadow/hide existing variables). The above will declare two loop-scope int variables: i and curr, initializing the first to 0, and the second to the expression result of (*headRef)=NULL, which for near-all C implementations, will be equivalent to (void*)0. But now curr is an int, and the previous declaration of curr as a node pointer is hidden. Therefore, this:
curr = curr->next =head[i];
is now nonsense.
Change your code to this:
curr=(*headRef)=NULL;
for(int i=0; i<max; i++)
and it should work.
Your code is close, but it's a bit cumbersome.
Whenever I see parallel arrays indexed by the same [type of] index, I think of creating a struct. You have head[] and tail[] so I'd create a "bucket" struct.
The multiple assignments in a single line [although doable/legal] makes the code hard(er) to read. Note that:
x = y = z;
Is no faster than:
x = z;
y = z;
if z is a simple scalar. The compiler will generate the same code but the latter is often cleaner/clearer.
Your code may [or may not] handle all cases of lists that are missing one or more of the 0,1,2 values. That is, lists of the form:
0,0,0
1,1,1
2,2,2
0,1
0,2
1,2
Using for loops here is also helps the code readability.
Here's the refactored code (I've compiled it, but not tested it):
#include <stdio.h>
#define max 3
typedef struct node node;
struct node {
int value;
node *next;
};
typedef struct {
node *head;
node *tail;
} list;
void
sortList(node **headRef)
{
node *head = *headRef;
node *tail;
node *curr;
node *next;
if (head == NULL)
return;
list *buck;
list buckets[max] = { 0 };
// split into buckets
for (curr = head; curr != NULL; curr = next) {
next = curr->next;
curr->next = NULL;
buck = &buckets[curr->value];
if (buck->head == NULL)
buck->head = curr;
else
buck->tail->next = curr;
buck->tail = curr;
}
// combine buckets into [new] single list
head = NULL;
tail = NULL;
for (int i = 0; i < max; ++i) {
buck = &buckets[i];
// skip empty buckets
if (buck->head == NULL)
continue;
// point to _first_ non-empty bucket
if (head == NULL)
head = buck->head;
// append _next_ non-empty bucket
else
tail->next = buck->head;
tail = buck->tail;
}
*headRef = head;
}

This function returns a list that contains the values that appear in list "A" at positions given in "pos_list"

-If A list has integer data such as: 1->2->3->4->5->6
-And pos_list has integer data such as: 4->0->5
-Then this function should return a New List hat contains the values that appear in list A at positions given in pos_list
such that New List= 5->1->6
I am implementing deep copy to make new List.
I am trying to use a loop that iterates according to the data of pos_list. Inside this loop, node of A will move to position of pos_list data. In this time i will copy the node A in new list to make another list.
Say for first case, pos_list has data 4, so the loop will run 4 times until the node of list A points to its fourth position. Inside this loop i will copy the data of list A in a new loop.
I need a guidance to solve this problem.
struct node * sublist(struct node * A, struct node * pos_list) {
struct node* newList=NULL;
struct node * curr;
int i=0;
for (i = 0, curr = pos_list->next; (curr != NULL); curr = curr->next) { //pos_list->data has a dummy node so loop until the end of pos_list->data.
struct node* newList = (struct node *) malloc(sizeof (struct node));
for(int i=0;i<=pos_list->data;i++){ //counter for pos_list as it will be (3 then 0,6 and 4)
if(i==pos_list->data){ //At the time when i == pos_list->data(3 or 0 or 6..)
newList->data = A->data; //Putting value of list A data in new list.
newList = newList->next; //Linking
printf("%d\t", newList->data); //Just for log
}
A=A->next; //Going to next position on A
}
pos_list=pos_list->next; //Going to next position on B
}
return newList ;
}
If A list is : 1->2->3->4->5->6
And pos_list is: 4->0->5
I expect the output is new list as 5->1->6
Your code has several problems:
You should start your traversal with pos_list, not with pos_list->next. The node pointed to by the head pointer is part of the list. Further, if pos_list == NULL, pos_list->next will lead to undefined behaviour.
The outer definition of int i isn't useful. Delete it.
Don't iterate through A by means of the position. If the position isn't valid, you will walk beyond the end of the list, get null pointers and invoke undefined behaviour. Lists should be iterated by list nodes accessed from the previous nodes' next pointers. (It is, of course, the caller's resposibility to provide valid positions, but your program should handle invalid input gracefully.)
Create the new node only when you have found a valid position. Otherwise you create a node that is never inserted and thus leak memory.
Here: newList = newList->next, newList->next isn't initialized. Remember that malloc gives you a chunk of uninitialized data.
You try to make newList point to the end of the newly created list, so that appending new nodes ist fast. That's a good idea, but if you return that pointer, you'll get a list that consists only of one element. (You'll also no loger be able to access any previously created nodes in that list.)
Here's an implementation that should work:
struct node *sublist(struct node *A, struct node *pos_list)
{
struct node *newHead = NULL;
struct node *newTail = NULL;
struct node *pos = pos_list;
while (pos) {
struct node *a = A;
int i = 0;
while (a) {
if (i == pos->data) {
struct node *node = malloc(sizeof(*node));
if (newHead == NULL) newHead = node;
if (newTail) newTail->next = node;
node->data = a->data;
node->next = NULL;
newTail = node;
break;
}
a = a->next;
i++;
}
pos = pos->next;
}
return newHead;
}
The question does not condone using a "struct" to implement the solution.
If it does, I am mistaken but if it does not, isn't it an overkill, when something akin to the following can be implemented....
#include <stdio.h>
#define CREATE_ARRAY(n) int result[n]
void main() {
int data[] = {1,2,3,4,5,6};
int pos[] = {4,0,5};
int i;
CREATE_ARRAY(sizeof(pos)/sizeof(int));
for(i = 0; i < sizeof(pos)/sizeof(int);++i)
result[i] = data[pos[i]];
/*
To print the values stored in result
for(i = 0;i < sizeof(result)/sizeof(int); ++i)
printf("%d ",result[i]);
putchar('\n');
}
*/
For starters the function sublist should be declared like
struct node * sublist( const struct node *A, const struct node *pos_list );
because neither the list A nor the list pos_list are changed in the function. Otherwise the declaration of the function confuses readers of the code.
It is a bad idea that the list pos_list contains a dummy node as it is wrote in the comment to this statement
for (i = 0, curr = pos_list->next; (curr != NULL); curr = curr->next) { //pos_list->data has a dummy node so loop until the end of pos_list->data
Neither dummy node should be in the list.
In this inner loop
for(int i=0;i<=pos_list->data;i++){
there is not used the dummy node of the list. Moreover the pos_list is traversed in the two loops: the outer loop and the inner loop
for (i = 0, curr = pos_list->next; (curr != NULL); curr = curr->next) { //pos_list->data has a dummy node so loop until the end of pos_list->data.
struct node* newList = (struct node *) malloc(sizeof (struct node));
for(int i=0;i<=pos_list->data;i++){
Within the loops the value of the variable newList is changed
newList = newList->next;
So as a result the function always returns some indeterminate value instead of the head of the newly created list. The value is indeterminate because the data member next of a new created node is not initialized.
newList->data = A->data; //Putting value of list A data in new list.
newList = newList->next;
The function can be defined the following way
struct node * sublist( const struct node *A, const struct node *pos_list )
{
struct node *newList = NULL;
struct node **current = &newList;
for ( ; pos_list != NULL; pos_list = pos_list->next )
{
const struct node *target = A;
for ( int index = pos_list->data; index != 0 && target != NULL; --index )
{
target = target->next;
}
if ( target != NULL )
{
*current = malloc( sizeof( struct node ) );
( *current )->data = target->data;
( *current )->next = NULL;
current = &( *current )->next;
}
}
return newList;
}

Thread 1: EXC_BAD_ACCESS (code=1, address=0x800000012)

I've tried to look up the solution to this problem through various other threads but my search was unsuccessful. I'm new to C and also new to this site so I apologize in advance if I'm incorrect in phrasing this question. I kinda have an idea of what's going on, but at the same time I might be entirely wrong. I have a linked list and I'm trying to insert at the end of the list. But when Xcode gets to the statement while(ptr->next!=NULL) it throws the error:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x800000012)
I read somewhere before that it was because I'm accessing something that doesn't exist or I'm failing to initialize node->next to NULL but I did in the previous "if statement". I'm pretty new at coding with pointers and linked lists and again I apologize for any weird stuff that might be in my code ):
////LIST AND NODE STRUCTURES
//data nodes
typedef struct node{
int data;
int ID;
struct node* prev;
struct node* next;
} node;
typedef struct ListInfo{
int count; //numnodes
struct node *list; //list of nodes
} ListInfo;
////INSERT FUNCITON
void insert(ListInfo *H, node *n){
if(n == NULL)
return;
node* ptr = H->list;
if(H==NULL){
ptr = n;
ptr->next = NULL;
}
else{
while(ptr->next!=NULL){ //Thread 1: EXC_BAD_ACCESS (code=1, address=0x800000012)
ptr = ptr->next;
}
ptr = n;
ptr->next = NULL;
}
// End of function
return;
}
////MAIN
int main(){ // No Edititng is needed for the main function.
ListInfo H;
H.count =0;
node *n;
int Data = 0,ID =0 ;
do{
printf("Enter an ID and a Value to add to the list, Enter -1 to stop: ");
//Get value from user to store in the new linked list node later.
scanf("%d %d",&ID,&Data);
// Check if the user entered "-1", if so exit the loop.
if(Data == -1||ID == -1)
return 0;
// Allocate memory for a new Node to be added to the Linked List.
n = malloc(sizeof(node));
// Put the Data from the user into the linked list node.
n->data = Data;
n->ID = ID;
//Increment the number of nodes in the list Header.
// If the current node count is zero, this means that this node is the first node
// in this list.
if(H.count++ == 0)
H.list = n;
// Otherwise, just use the insert function to add node to the list.
else insert(&H,n);
}while(Data != -1);
// Display all nodes in the list.
DisplayList(&H);
//Remove a node from the list, and display the list each time.
while(H.count != 0){
Delete(&H,H.list->data);
DisplayList(&H);
}
// Display the list, this should be empty if everything was correct.
DisplayList(&H);
}
When you allocate n you never set n->next. When you pass it to insert() you try to access the bad pointer and crash. When you set n->ID you should set n->next to NULL.

Using a while loop to check the content of struct

I'm trying to append a node to a linked list however, when I use a while loop to check if the "link" is set to NULL, the loop is being executed when it shouldn't.
It is as if the "cursor->link" was not set to NULL and the code inside the while loop is being executed, I put the print statement there just to test it and it is being executed even though "cursor->link" is set to NULL. The create function returns a "node*".
EDIT - I apologize guys, I posted this question late at night and I guess I might not have been in the best shape to express myself properly. Plus I'm still a bit confused about how to handle and work with Linked Listing (as my code probably shows). I've been given a template to work with (as in the functions append and display were preset and I've to work with them as is). The compiler did not set off any warnings with the code as is. However the program still crashes in the append function around the While loop.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct node {
int data;
struct node * link;
} node;
node* create(int data,node* link) {
node* newNode = (node*)malloc(sizeof(node));
newNode->data = data;
newNode->link = link;
return newNode;
}
void append ( node **, int ) ;
void display ( node * ) ;
int main() {
node *p ;
p=NULL;
int n;
char ch[10];
do {
printf("Enter the value\n");
scanf("%d",&n);
append(&p,n);
printf("Do you want to add another node? Type Yes/No\n");
scanf("%s",ch);
}while(!strcmp(ch,"Yes"));
printf("The elements in the linked list are");
display(p);
printf("\n");
return 0;
}
/* adds a node at the end of a linked list */
void append ( node **q, int num ){
node *cursor;
if (*q == NULL) {
*q = create(num, NULL);
node *cursor = *q;
}
while(cursor->link != NULL) {
printf("1\n");
cursor = cursor->link;
}
node* newNode = create(num, NULL);
cursor->link = newNode;
}
void display ( node *q ){
node *cursor = q;
while(cursor->link != NULL) {
printf(" %d", q->data);
cursor = cursor->link;
}
printf(" %d", cursor->data);
}
As Ry mentioned, problem is with the cursor you are using in while loop, it's never initialized. Instead you are creating a new variable with the same name when *q is null. I see one more problem in your code, when list is empty you are adding new node twice. First in null check condition and then after while loop.
To fix move this line
"node *cursor = *q"
outside if condition and add a return instead. Also remove this line
"node *cursor"
Note:: I am assuming your create method has no issue.

C Function to leave only unique nodes in singly linked list

I'm having an issue: in a function, program needs to compare two nodes and delete one of them if the node values are the same (example: A -> B -> B -> C >>> A -> B -> C). In a few words: it have to leave only unique nodes.
Steps that I've done: created list from data given in data file and it prints out perfectly. Now I'm struggling comparing two nodes.
Steps that I'm thinking of doing: Put two nodes values in two different variables, then comparing those two and if latest node is equal to previous, delete the latest and somehow link previous node to next node. Then the cycle goes all over again.
Question: How do I compare node with further one?
Here's the code that I have right now:
#include <stdio.h>
#include <stdlib.h>
#define LENGTH 255
struct node {
int info;
struct node *next;
} *head = NULL;
int create(FILE **data){
char read[LENGTH];
printf("Write data file name: ");
scanf("%s", read);
*data = fopen (read, "r");
if (data == NULL) {
printf("Error reading given file.");
}
return 0;
}
int put_Symbols_into_list(FILE *data) {
struct node *new_node, *current;
char c;
printf("Data given: ");
while (!feof(data)){
new_node = (struct node*)malloc(sizeof (struct node));
c = fscanf(data, "%s", &new_node -> info);
printf("%s ", &new_node -> info);
if (head == NULL){
head = new_node;
current = new_node;
} else {
current -> next = new_node;
current = new_node;
}
}
}
int delete_Same_Symbols() {
}
int main() {
FILE *data;
struct node *n;
create(&data);
put_Symbols_into_list(data);
delete_Same_Symbols();
//display_List(n);
return 0;
}
An efficient way of remove duplicates is the following:
1. Sort the list
2. Run through the list once deleting any adjacent duplicates.
Whether this solution works for you depends on whether your data can be ordered.
Traverse the list from head to end and maintain a Hash table.
For every element,check whether value is in the hash table: if yes, remove the node; else put value in the hash table.
Time Complexity: O(n) on average (assuming that hash table access time is O(1) on average).
I'll give you the function that will remove the duplicates.
Assuming that your code is working fine and that the info is an int value
Note that if info is a string you will need strcmp function instead of head->info == info.
int exist(NODE *head, int info) {
while (head && head->info != info) // strcmp(info,head->info) != 0
head = head->next;
return head->info == info; // strcmp(info,head->info)
}
void removeDuplicates(NODE **phead, int info) {
NODE *tmp = *phead;
while (tmp->info != info) // strcmp(info,head->info) != 0
tmp = tmp->next;
NODE *tmp1 = tmp->next;
tmp->info = tmp1->info; // strcpy(tmp->info,tmp1->info)
tmp->next = tmp1->next;
free(tmp1);
}

Resources