Remove adjacent duplicates in linked list in C - c

As the title mentioned, I have to remove adjacent duplicates in linked list such that if input is 'google', output should be 'le'. I'm supposed to code it in C. I've written 70% of the code, except that I don't know how to continuously loop till all adjacent duplicates are removed. I'm removing adjacent duplicates in remove_adjacent_duplicates() function, and since I don't know how to put terminating condition in loop, I've merely used if-else loop. But my code in remove_adjacent_duplicates() function might contain mistakes, so please rectify it if any and please give solution to looping till all adjacent duplicates are removed. Here's my code-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node //node creation
{
char data;
struct node *next;
};
void remove_adjacent_duplicates(struct node** head_ref)
{
struct node* current = *head_ref;
struct node* cnext = NULL; //the one next to current one
int flag=0;
cnext = current->next; //storing next
//printf("%c %c %d\n",current->data,cnext->data,flag);
if(cnext->data==current->data)
{
flag=1;
while(cnext->data==current->data)
{
cnext=cnext->next;
}
current=cnext;
cnext = current->next; //storing next
}
else
{
current=current->next;
cnext = current->next; //storing next
}
//printf("%c %c %d\n",current->data,cnext->data,flag);
if(flag) *head_ref = current;
}
void push(struct node** head_ref, char new_data)
{
struct node* new_node = (struct node*)malloc(sizeof(struct node));
new_node->data = new_data;
new_node->next = *head_ref;
*head_ref = new_node;
}
void printList(struct node* head)
{
if (head == NULL)
{
printf("NULL\n\n");
return;
}
printf("%c->",head->data);
printList(head->next);
}
int main()
{
char s[100];
int i;
struct node* a = NULL;
printf("Enter string: ");
scanf("%s",s);
for(i=strlen(s)-1;i>-1;i--){
push(&a, s[i]); //last in first out, so in reverse g is last but first to come out
}
printf("\nConverting string to linked list: \n");
printList(a);
//printf("%c",current->data); prints first letter of a
remove_adjacent_duplicates(&a);
printList(a);
return 0;
}

You could use recursion. That way you can check whether before the recursive call or after the recursive call there is something to remove:
void remove_adjacent_duplicates(struct node** head_ref)
{
struct node* current = *head_ref;
if (current == NULL || current->next == NULL) return;
int isEqual = current->data == current->next->data;
remove_adjacent_duplicates(&current->next);
if (current->next != NULL && current->data == current->next->data) {
// Duplicates! Remove pair
*head_ref = current->next->next;
free(current->next);
free(current);
} else if (isEqual) {
// Continue ongoing removal
*head_ref = current->next;
free(current);
}
}

A few issues ...
The first element of list (e.g. head) can never be a duplicate
The code leaks memory when removing a dup because it doesn't do free
The code only removes the first element.
The code uses next, cur, but not previous, so the algorithm needs refactoring.
Casting the return of malloc is bad. See: Do I cast the result of malloc?
scanf is problematic. %s can overrun the end of the array. Better to use (e.g.) %99s [or better yet: fgets].
Here is the refactored code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// node definition
struct node {
char data;
struct node *next;
};
void
remove_adjacent_duplicates(struct node **head_ref)
{
struct node *prev = *head_ref;
struct node *cur;
struct node *next;
// NOTE: first node can _never_ be a dup
if (prev != NULL)
cur = prev->next;
else
cur = NULL;
for (; cur != NULL; cur = next) {
// remember this in case we remove cur to prevent "use after free" bug
// when advancing cur
next = cur->next;
// remove duplicate
if (cur->data == prev->data) {
prev->next = next;
free(cur);
continue;
}
// point to last non-dup node
prev = cur;
}
}
void
push(struct node **head_ref, char new_data)
{
// NOTE/BUG: casting the result of malloc is bad
#if 0
struct node *new_node = (struct node *) malloc(sizeof(struct node));
#else
struct node *new_node = malloc(sizeof(*new_node));
#endif
new_node->data = new_data;
new_node->next = *head_ref;
*head_ref = new_node;
}
void
printList(struct node *head)
{
if (head == NULL) {
printf("NULL\n\n");
return;
}
printf("%c->", head->data);
printList(head->next);
}
int
main(void)
{
char s[100];
int i;
struct node *a = NULL;
printf("Enter string: ");
// NOTE/BUG: scanf is bad -- it can overrun the end of s
#if 0
scanf("%s", s);
#else
scanf("%99s", s);
#endif
// last in first out, so in reverse g is last but first to come out
for (i = strlen(s) - 1; i > -1; i--) {
push(&a, s[i]);
}
printf("\nConverting string to linked list: \n");
printList(a);
// printf("%c",current->data); prints first letter of a
remove_adjacent_duplicates(&a);
printList(a);
return 0;
}
In the above code, I've used cpp conditionals to denote old vs. new code:
#if 0
// old code
#else
// new code
#endif
#if 1
// new code
#endif
Note: this can be cleaned up by running the file through unifdef -k
UPDATE:
From the OP: "[ .. ] 'google', output should be 'le'.". Looks like both nodes are removed, and the effect compounds. –
Oka
Yes, it's much more complex. But, here is a version that removes all duplicates. I had some trouble myself, so I left in the debugging code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if DEBUG
#define dbgprt(_fmt...) \
printf(_fmt)
#else
#define dbgprt(_fmt...) \
do { } while (0)
#endif
// node definition
struct node {
char data;
#if DEBUG
int seq;
#endif
struct node *next;
};
#if DEBUG
int seq = 0;
#endif
void
remove_adjacent_duplicates(struct node **head_ref)
{
struct node *prev = *head_ref;
struct node *cur;
struct node *next;
// NOTE: first node can _never_ be a dup
if (prev != NULL)
cur = prev->next;
else
cur = NULL;
for (; cur != NULL; cur = next) {
// remember this in case we remove cur to prevent "use after free" bug
// when advancing cur
next = cur->next;
// remove duplicate
if (cur->data == prev->data) {
prev->next = next;
free(cur);
continue;
}
// point to last non-dup node
prev = cur;
}
}
void
remove_all_duplicates(struct node **head_ref)
{
struct node *oldhead = *head_ref;
struct node *addprev = NULL;
struct node *addnext;
// loop through all candidate nodes
for (struct node *addcur = oldhead; addcur != NULL; addcur = addnext) {
int dupflg = 0;
// start of search for duplicates to the right of the candidate
struct node *prevdup = NULL;
struct node *dupcur = addcur->next;
// find all duplicates to the right [towards tail] of candidate node
while (1) {
// find first duplicate to the right of candidate [if one exists]
struct node *dupnext = NULL;
for (; dupcur != NULL; dupcur = dupnext) {
dupnext = dupcur->next;
if (dupcur->data == addcur->data) {
dupflg = 1;
break;
}
prevdup = dupcur;
}
// no more duplicates to the right of current candidate
if (dupcur == NULL)
break;
// remove a duplicate on the right
if (prevdup != NULL)
prevdup->next = dupnext;
else
addcur->next = dupnext;
free(dupcur);
}
addnext = addcur->next;
// remove candidate because it's a dup
if (dupflg) {
if (addprev != NULL)
addprev->next = addnext;
else
oldhead = addnext;
free(addcur);
continue;
}
// remember last valid non-dup node
addprev = addcur;
}
*head_ref = oldhead;
}
void
push(struct node **head_ref, char new_data)
{
// NOTE/BUG: casting the result of malloc is bad
#if 0
struct node *new_node = (struct node *) malloc(sizeof(struct node));
#else
struct node *new_node = malloc(sizeof(*new_node));
#endif
new_node->data = new_data;
#if DEBUG
new_node->seq = seq++;
#endif
new_node->next = *head_ref;
*head_ref = new_node;
}
void
printList(struct node *head)
{
if (head == NULL) {
printf("NULL\n\n");
return;
}
#if DEBUG
printf("%c%d->", head->data, head->seq);
#else
printf("%c->", head->data);
#endif
printList(head->next);
}
int
main(int argc,char **argv)
{
char s[100];
int opt_a = 0;
int i;
struct node *a = NULL;
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
char *cp = *argv;
if (*cp != '-')
break;
switch (cp[1]) {
case 'a':
opt_a = ! opt_a;
break;
}
}
printf("Enter string: ");
// NOTE/BUG: scanf is bad -- it can overrun the end of s
#if 0
scanf("%s", s);
#else
fflush(stdout);
if (fgets(s,sizeof(s),stdin) == NULL)
s[0] = 0;
s[strcspn(s,"\n")] = 0;
#endif
// last in first out, so in reverse g is last but first to come out
for (i = strlen(s) - 1; i > -1; i--)
push(&a, s[i]);
printf("\nConverting string to linked list: \n");
printList(a);
// printf("%c",current->data); prints first letter of a
if (opt_a)
remove_adjacent_duplicates(&a);
else
remove_all_duplicates(&a);
printList(a);
return 0;
}
UPDATE:
As for your code I can't understand it properly especially those # statements since I'm just an average coder in C with no advanced knowledge. –
New
The # lines aren't really advanced coding. They are C preprocessor (i.e. cpp) directives, similar to #define, #ifdef, #ifndef, and #endif. See the compiler manpage and/or man cpp.
They include/eliminate code at compile time in a separate first stage of the compilation process (i.e. the cpp stage).
Otherwise, the code is well commented to explain the intent of what the code is doing.
Side note: When I was first learning to code, in addition to school assignments, I was looking at some complex OS kernel code [in assembly language]. I just kept going over it, sometimes adding my own comments, until I did understand it. I learned more by reading and understanding such code than I did from most assignments.
At the bottom of my answer: What is the error in this code that checks if the linklist is a palindrome or not? is a list of resources I recommend.
Here is a cleaned up version of the my code above that eliminates the conditional cpp directives:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// node definition
struct node {
char data;
struct node *next;
};
void
remove_adjacent_duplicates(struct node **head_ref)
{
struct node *prev = *head_ref;
struct node *cur;
struct node *next;
// NOTE: first node can _never_ be a dup
if (prev != NULL)
cur = prev->next;
else
cur = NULL;
for (; cur != NULL; cur = next) {
// remember this in case we remove cur to prevent "use after free" bug
// when advancing cur
next = cur->next;
// remove duplicate
if (cur->data == prev->data) {
prev->next = next;
free(cur);
continue;
}
// point to last non-dup node
prev = cur;
}
}
void
remove_all_duplicates(struct node **head_ref)
{
struct node *oldhead = *head_ref;
struct node *addprev = NULL;
struct node *addnext;
// loop through all candidate nodes
for (struct node *addcur = oldhead; addcur != NULL; addcur = addnext) {
int dupflg = 0;
// start of search for duplicates to the right of the candidate
struct node *prevdup = NULL;
struct node *dupcur = addcur->next;
// find all duplicates to the right [towards tail] of candidate node
while (1) {
// find first duplicate to the right of candidate [if one exists]
struct node *dupnext = NULL;
for (; dupcur != NULL; dupcur = dupnext) {
dupnext = dupcur->next;
if (dupcur->data == addcur->data) {
dupflg = 1;
break;
}
prevdup = dupcur;
}
// no more duplicates to the right of current candidate
if (dupcur == NULL)
break;
// remove a duplicate on the right
if (prevdup != NULL)
prevdup->next = dupnext;
else
addcur->next = dupnext;
free(dupcur);
}
addnext = addcur->next;
// remove candidate because it's a dup
if (dupflg) {
if (addprev != NULL)
addprev->next = addnext;
else
oldhead = addnext;
free(addcur);
continue;
}
// remember last valid non-dup node
addprev = addcur;
}
*head_ref = oldhead;
}
void
push(struct node **head_ref, char new_data)
{
struct node *new_node = malloc(sizeof(*new_node));
new_node->data = new_data;
new_node->next = *head_ref;
*head_ref = new_node;
}
void
printList(struct node *head)
{
if (head == NULL) {
printf("NULL\n\n");
return;
}
printf("%c->", head->data);
printList(head->next);
}
int
main(int argc,char **argv)
{
char s[100];
int opt_a = 0;
int i;
struct node *a = NULL;
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
char *cp = *argv;
if (*cp != '-')
break;
switch (cp[1]) {
case 'a':
opt_a = ! opt_a;
break;
}
}
printf("Enter string: ");
fflush(stdout);
if (fgets(s,sizeof(s),stdin) == NULL)
s[0] = 0;
s[strcspn(s,"\n")] = 0;
// last in first out, so in reverse g is last but first to come out
for (i = strlen(s) - 1; i > -1; i--)
push(&a, s[i]);
printf("\nConverting string to linked list: \n");
printList(a);
// printf("%c",current->data); prints first letter of a
if (opt_a)
remove_adjacent_duplicates(&a);
else
remove_all_duplicates(&a);
printList(a);
return 0;
}

Related

Polynominal with doubly linked list - pointer problem

I made some polynomial code with a doubly-linked list. for example, if
you write 1 and 2 then 1 is a degree and 2 is coefficient. 1x^2 insert
to doubly linked list. the problem is that when I check my code, the Node
head->degree is changing. if I write 1x^2 then head->degree is 1 next,
I write 2x^1 then head-> degree should maintain 1 but head-> degree
change to 2 I think there is some problem in the head pointer.
#include <stdio.h>
#include <stdlib.h>
// struct
struct Node {
int degree;
int coefficient;
struct Node* next;
struct Node* prev;
};
// global variables
int de; // degree
int co; // coefficient
int flag;
Node** head = (Node**)malloc(sizeof(Node)); //
Node** head1 = (Node**)malloc(sizeof(Node)); //
Node** head2 = (Node**)malloc(sizeof(Node)); //
Node** head3 = (Node**)malloc(sizeof(Node)); //
Node* newNode = (Node*)malloc(sizeof(Node)); //
// function
Node* inputpoly(void);
void printNode(Node* inp);
Node* multiply(Node* a, Node* b);
// main
int main() {
// head null
(*head1) = NULL;
(*head2) = NULL;
(*head3) = NULL;
while (1) {
printf("Input (degree) (coefficient) : ");
scanf_s("%d %d", &de, &co);
if (de * co < 0) { continue; }
if (de < 0 && co < 0) {
printf("Done!\n");
break;
}
*head = inputpoly();
}
printNode(*head);
//multiply(*head1, *head2);
free(head1);
free(head2);
free(head3);
free(newNode);
free(head);
}
Node* inputpoly(void) {
// create Node
newNode->degree = de;
newNode->coefficient = co;
newNode->next = NULL;
newNode->prev = NULL;
// case1
if (flag == 0) {
// list
if ((*head1) == NULL) {
*head1 = newNode;
}
// list x
else {
Node* horse = (*head1);
// front of head
// ------------------There is some problem
printf("%d\n", 1);
printf("--%d\n", newNode->degree);
printf("--%d\n", horse->degree);
if (horse->degree > newNode->degree) {
newNode->next = horse;
horse->prev = newNode;
*head1 = newNode;
}
// barward of head
else {
int num = 0;
while (horse->next != NULL) {
horse = horse->next;
if (horse->degree > newNode->degree) {
horse->prev->next = newNode;
newNode->next = horse;
newNode->prev = horse->prev;
horse->prev = newNode;
num = 1;
break;
}
}
// behind tail
if (num == 0) {
horse->next = newNode;
newNode->prev = horse;
}
}
}
return *head1;
}
}
void printNode(Node* inp) {
Node* horse = inp;
if (horse == NULL)
{
return;
}
while (horse != NULL) {
if (horse->prev == NULL) {
if (horse->degree == 1) {
printf("%d", horse->coefficient);
}
else {
printf("%d x^%d", horse->coefficient, horse->degree);
}
}
else {
if (horse->degree == 1) {
printf(" + %d", horse->coefficient);
}
else {
printf(" + %d x^%d", horse->coefficient, horse->degree);
}
}
}
printf("\n");
}
"i think there is some head pointer problem, and if I fixed it I can this problem. so I want to maintain this code as possible. I want some
advice or solution to my head pointer"
The code posted in your example does not compile:
Before you can fix a head pointer problem the code must compile. This list of errors is detailing 2 things:
first, functions cannot be called outside of a function, eg:
Node** head = (Node**)malloc(sizeof(Node)); //
Node** head1 = (Node**)malloc(sizeof(Node)); //
Node** head2 = (Node**)malloc(sizeof(Node)); //
Node** head3 = (Node**)malloc(sizeof(Node)); //
Node* newNode = (Node*)malloc(sizeof(Node)); //
should be called from within main(void){...} or some other function.
second, every occurrence of Node should be prepended with struct. eg:
struct Node** head = malloc(sizeof(struct Node *));
(have also removed the cast, and modified the size of what you are creating memory for, i.e. a pointer)
Rather then fix these and other problems, here is an example of a doubly linked list that can demonstrate the structure of a simple working program. You can adapt the following to match your needs:
struct Node {
int deg;
int coef;
struct Node* next; // Pointer to next node in DLL
struct Node* prev; // Pointer to previous node in DLL
};
void inputpoly(struct Node** head_ref, int deg, int coef)
{
//allocate node
struct Node *new_node = malloc(sizeof(*new_node));
//assign data
new_node->deg = deg;
new_node->coef = coef;
//set next as new head and prev to null
new_node->next = (*head_ref);
new_node->prev = NULL;
//change prev of head to new */
if ((*head_ref) != NULL)
(*head_ref)->prev = new_node;
//point head to the new node */
(*head_ref) = new_node;
}
void printList(struct Node* node)
{
struct Node* last;
printf("\nread forward\n");
while (node != NULL) {
printf(" %d,%d ", node->deg,node->coef);
last = node;
node = node->next;
}
printf("\nread reverse\n");
while (last != NULL) {
printf(" %d,%d ", last->deg,last->coef);
last = last->prev;
}
}
int main(void)
{
//start with empty list
struct Node* head = NULL;
//create and populate new nodes
inputpoly(&head, 7, 2);
inputpoly(&head, 1, 4);
inputpoly(&head, 4, 6);
//ouput list
printList(head);
getchar();
return 0;
}
Note that this code is offered as a basic demonstration of creating doubly linked list, and illustrate how to traverse both directions. Because it does not free allocated memory, it is not recommended that it be used for any production purpose without addressing that omission.

Cannot sort a linked list of dynamically assigned nodes

My program takes in any number of words from the user, and stops only when the user types three asterisks (***). These words will be stored in a linked list and sorted, but the elements in the list are not sorted when I try to print the list. Why is this happening?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_STRING_LEN 32 // Limit on length of each string
/* Link list node */
struct Node
{
int data;
struct Node* next;
};
// Function to insert a given node in a sorted linked list
void sortedInsert(struct Node**, struct Node*);
// function to sort a singly linked list using insertion sort
void insertionSort(struct Node **head_ref)
{
// Initialize sorted linked list
struct Node *sorted = NULL;
// Traverse the given linked list and insert every
// node to sorted
struct Node *current = *head_ref;
while (current != NULL)
{
// Store next for next iteration
struct Node *next = current->next;
// insert current in sorted linked list
sortedInsert(&sorted, current);
// Update current
current = next;
}
// Update head_ref to point to sorted linked list
*head_ref = sorted;
}
/* function to insert a new_node in a list. Note that this
function expects a pointer to head_ref as this can modify the
head of the input linked list (similar to push())*/
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)->data >= new_node->data)
{
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->data < new_node->data)
{
current = current->next;
}
new_node->next = current->next;
current->next = new_node;
}
}
/* BELOW FUNCTIONS ARE JUST UTILITY TO TEST sortedInsert */
/* Function to print linked list */
void printList(struct Node *head)
{
struct Node *temp = head;
while(temp != NULL)
{
printf("%s \n ", temp->data);
temp = temp->next;
}
}
/* A utility function to insert a node at the beginning of linked list */
void push(struct Node** head_ref, int new_data)
{
/* allocate node */
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
/* put in the data */
new_node->data = new_data;
/* link the old list off the new node */
new_node->next = (*head_ref);
/* move the head to point to the new node */
(*head_ref) = new_node;
}
// Main function
int main()
{
struct Node *a = NULL;
int index=1;
int i;
char * strings[MAX_STRINGS]; // Array of pointers
do
{
strings[index] = malloc(MAX_STRING_LEN * sizeof(char));
printf("Please input a word : ", index);
fgets(strings[index],MAX_STRING_LEN,stdin);
strtok(strings[index], "\n")=='\0';
}
while(strcmp(strings[index++], "***")!=0);
printf("\nThe input set, in alphabetical order:\n");
for (i = 1; i < index-1; i++)
{
push(&a, strings[i]);
}
insertionSort(&a);
printList(a);
free(strings[i]);
return 0;
}
Input:
pear
apple
***
Given output:
pear
apple
Expected output:
apple
pear
Hii I spent some time thinking what you wanted to do. And saw many problems with your code. I think you want something like this.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_STRING_LEN 32 // Limit on length of each string
#define MAX_STRINGS 100 // Limit the number of strings
struct Node {
char *data;
struct Node *next;
};
void sortedInsert(struct Node **head_ref, struct Node* new_node) {
struct Node *counter = *head_ref;
struct Node *previous = NULL;
while (counter != NULL && strcmp(counter->data,new_node->data) < 0){
previous = counter;
counter = counter->next;
}
if (previous != NULL) {
previous->next = new_node;
new_node->next = counter;
} else {
new_node->next = *head_ref;
*head_ref = new_node;
}
}
void push(struct Node **head_ref, char *new_data) {
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
new_node->data = new_data;
new_node->next = NULL;
if (!head_ref) {
*head_ref = new_node;
return;
}
sortedInsert(head_ref,new_node);
}
void printList(struct Node *head) {
struct Node *temp = head;
while(temp != NULL) {
printf("%s\n", temp->data);
temp = temp->next;
}
}
void freeLinkedList(struct Node *head) {
struct Node *next;
while(head) {
next = head;
head = head->next;
free(next);
}
}
// Main function
int main() {
struct Node *a = NULL;
int index = 0;
int i;
char * strings[MAX_STRINGS]; // Array of pointers
do {
strings[index] = malloc(MAX_STRING_LEN * sizeof(char));
printf("Please input a word %d: ", index);
scanf("%s",strings[index]);
fflush(stdin);
} while(strcmp(strings[index++], "***") != 0 && index < MAX_STRINGS);
printf("\nThe input set, in alphabetical order:\n");
for (i = 0; i < index-1; i++) push(&a, strings[i]);
printList(a);
return 0;
}
I have tested it and it works fine.
If you have any doubts I would like to clear them.
If you want to know what's buggy in your code please feel free to ask.

Current node not resetting to head node it is referenced to

I have created 2 linked lists. Node and Codex. Codex is a spell checker.
Eye I
eye I
chequer checker
Pea P
Sea C
plane plainly
lee skip
four for
revue review
Miss Mistakes
Steaks skip
knot not
sea see
quays keys
whirred word
weight wait
Two To
two to
Weather Whether
write right
oar or
aweigh away
threw through
Your You're
shore sure
two to
no know
Its It's
vary very
weigh way
tolled told
sew so
bless blessed
freeze frees
yew you
lodes loads
thyme time
right write
stiles styles
righting writing
aides aids
rime rhyme
frays phrase
come composed
posed skip
trussed trusted
too to
bee be
joule jewel
cheque check
sum some
The other linked list is a text file of words. Looks like this.
Eye have a spelling chequer,
It came with my Pea Sea.
It plane lee marks four my revue,
Miss Steaks I can knot sea.
Eye strike the quays and type a whirred,
And weight four it two say,
Weather eye am write oar wrong,
It tells me straight aweigh.
Eye ran this poem threw it,
Your shore real glad two no.
Its vary polished in its weigh.
My chequer tolled me sew.
A chequer is a bless thing,
It freeze yew lodes of thyme.
It helps me right all stiles of righting,
And aides me when eye rime.
Each frays come posed up on my screen,
Eye trussed too bee a joule.
The chequer pours over every word,
Two cheque sum spelling rule.
Now when you find Eye in the data file, you would replace it with I. As you can see in the codex file they are right next to each other.
My code works when inserting the text into the linked lists. But when I pass the head of both linked lists to my function called LIST_CORRECT, the head node of the codex gets stuck at the node with the word sum(second to last word in codex). I have tried setting a pointer to both heads of the linked lists and make those currents but that still does not work. Any suggestions on what to do?
Here is the code.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
// A complete working C program to demonstrate all insertion methods
// on Linked List
// A linked list node
struct Node;
void push(struct Node **head_ref, char *new_data);
void insertAfter(struct Node *prev_node, char *new_data);
void append(struct Node **head_ref, char *new_data);
void printList(struct Node *node);
//void LIST_CORRECT(struct Codex **head_refC,struct Node **head_ref);
//void pushC(struct Codex **head_ref, char *new_data);
//void insertAfterC(struct Codex *prev_node, char *new_data);
//void appendC(struct Codex **head_ref, char *new_data);
//void printListC(struct Codex *node);
int LINECOUNT(FILE *(*stream), char *filename);
struct Node {
char *data;
struct Node *next;
};
struct Codex {
char *word1;
char *word2;
struct Codex *next;
};
/* Given a reference (pointer to pointer) to the head of a list and
an int, inserts a new node on the front of the list. */
void push(struct Node **head_ref, char *new_data) {
/* 1. allocate node */
struct Node* new_node = (struct Node *)malloc(sizeof(struct Node));
/* 2. put in the data */
new_node->data = new_data;
//printf("push data:%s ", new_data);
/* 3. Make next of new node as head */
new_node->next = (*head_ref);
/* 4. move the head to point to the new node */
(*head_ref) = new_node;
}
void pushC(struct Codex **head_ref, char *new_word,char *new_word2) {
/* 1. allocate node */
struct Codex* new_node = (struct Codex *)malloc(sizeof(struct Codex));
struct Codex* new_node2 = (struct Codex *)malloc(sizeof(struct Codex));
/* 2. put in the data */
new_node->word1 = new_word;
//printf("push data:%s ", new_data);
/* 3. Make next of new node as head */
new_node->next = (*head_ref);
/* 4. move the head to point to the new node */
(*head_ref) = new_node;
//------------------------//
/* 5. put in the data */
new_node2->word2 = new_word;
//printf("push data:%s ", new_data);
/* 6. Make next of new node as head */
new_node2->next = (*head_ref);
/* 7. move the head to point to the new node */
(*head_ref) = new_node2;
}
/* Given a reference (pointer to pointer) to the head
of a list and an int, appends a new node at the end */
// This function prints contents of linked list starting from head
void printListC(struct Codex *node) {
while (node != NULL) {
printf("%s ", node->word1);
node = node->next;
}
}
void LIST_INSERT_POEM(struct Node **head_ref, char *new_data) {
/* 1. allocate node */
struct Node* new_node = (struct Node *)malloc(sizeof(struct Node));
struct Node *last = *head_ref; /* used in step 5*/
/* 2. put in the data */
new_node->data = new_data;
//printf("push data:%s ", new_data);
/* 3. This new node is going to be the last node, so make next of
it as NULL*/
new_node->next = NULL;
/* 4. If the Linked List is empty, then make the new node as head */
if (*head_ref == NULL) {
*head_ref = new_node;
return;
}
/* 5. Else traverse till the last node */
while (last->next != NULL)
last = last->next;
/* 6. Change the next of last node */
last->next = new_node;
return;
}
void LIST_INSERT_CODEX(struct Codex **head_ref, char *new_data) {
/* 1. allocate node */
struct Codex* new_node = (struct Codex *)malloc(sizeof(struct Codex));
//if(x==1){
struct Codex *last = *head_ref; /* used in step 5*/
/* 2. put in the data */
new_node->word1 = new_data;
//printf("push data:%s ", new_data);
/* 3. This new node is going to be the last node, so make next of
it as NULL*/
new_node->next = NULL;
/* 4. If the Linked List is empty, then make the new node as head */
if (*head_ref == NULL) {
*head_ref = new_node;
return;
}
/* 5. Else traverse till the last node */
while (last->next != NULL)
last = last->next;
/* 6. Change the next of last node */
last->next = new_node;
return;
}
// This function prints contents of linked list starting from head
void printList(struct Node *node) {
while (node != NULL) {
printf("%s ", node->data);
node = node->next;
}
}
int LINECOUNT(FILE *(*stream), char *filename) {
int size = 0;
size_t chrCount;
char *text;
if ((*stream = fopen(filename, "r")) == NULL) {
printf("LC Could not open hw8 data file.\n");
exit(0);
}
while (1) {
text = NULL;
getline(&text, &chrCount, *stream);
free(text); /*free text*/
if (feof(*stream))
break;
size++;
}
rewind(*stream);
return size;
}
void LIST_CORRECT(struct Codex **head_refC,struct Node **head_ref,int lc,int x){
int t;int e;printf("\nlc for codex:%d\n",lc);
//struct Codex **currentC; struct Node **CurrentH;
struct Codex **currentC = (struct Codex **)malloc(sizeof(struct Codex*));
struct Node** currentH = (struct Node **)malloc(sizeof(struct Node*));
currentC=head_refC;
currentH=head_ref;
printf("\ncurrentC:%s\n",(*currentC)->word1);
printf("currentH:%s\n",(*currentH)->data);
t = strcmp( ((*currentC)->word1) , ((*currentH)->data) );
printf("t:%d\n",t);
if(t==0){printf("(t==0)");((*currentH)->data)=(((*currentC)->next)->word1);}
if(t!=0){for(int i = 0;i<lc-1;i++){printf("\ti:%d\tcurrentC:%s\t",i,(*currentC)->word1);(*currentC)=(*currentC)->next->next;printf("currentC:%s\n",(*currentC)->word1);}}
}
int main(void) {
char *fn = "hw8data.txt";
char *fn2 = "hw8codex.txt";
int lineCount;
int lineCount2;
FILE *stream;
FILE *stream2;
lineCount = LINECOUNT(&stream, fn);
lineCount2= LINECOUNT(&stream2,fn2);
//int lineArr[lineCount];
//int lineArr[];//lineArr[0] = 4 would say the first line has 4 words. using this data for strtok
//lineArr = wordCount(&stream, fn, lineCount);
//-------------------------------------
char ch;
int wordcount = 0;
int charcount = 0;
int wordcount2 = 0;
int charcount2 = 0;
stream = fopen("./hw8data.txt", "r");
int x = 0;
int lineArr[lineCount];
for (int i = 0; i < lineCount; i++) {
lineArr[i] = 0;
}
if (stream) {
while ((ch = getc(stream)) != EOF) {
if (ch != ' ' && ch != '\n') {
charcount++;
}
if (ch == ' ' || ch == '\n') {
wordcount++;
lineArr[x] = lineArr[x] + 1;
}
if (ch == '\n') {
x++;
}
}
printf("\nwc:%d\n",wordcount);
//if (charcount > 0) { wordcount++; charcount++; }
} else {
printf("Failed to open the file1\n");
}
//----------------------------------------------//
stream2 = fopen("./hw8codex.txt", "r");
int y = 0;
int lineArr2[lineCount2];
for (int i = 0; i < lineCount2; i++) {
lineArr2[i] = 0;
}
if (stream) {
while ((ch = getc(stream)) != EOF) {
if (ch != ' ' && ch != '\n') {
charcount2++;
}
if (ch == ' ' || ch == '\n') {
wordcount2++;
lineArr2[y] = lineArr2[y] + 1;
}
if (ch == '\n') {
y++;
}
}
//if (charcount > 0) { wordcount++; charcount++; }
} else {
printf("Failed to open the file2\n");
}
//----------------------------------------------//
/* Start with the empty list */
struct Node *head = NULL;
struct Codex *headC = NULL;
struct Node **headP = &head;
struct Codex **headCP = &headC;
printf("\n%p\t",&head); printf("%p\n",headP);
printf("\n%p\t",&headC); printf("%p\n",headCP);
rewind(stream);
rewind(stream2);
//char *sArr = malloc(42 * sizeof(char));
//printf("List-----------------------------\n\n");
for(int i =0; i<wordcount;i++){
char *sArr = malloc(42 * sizeof(char));
fscanf(stream, "%s ", sArr);
//printf("%s ", sArr);
LIST_INSERT_POEM(&head, sArr);
i++;
}
//printf("\n\nCodex-----------------------------\n\n");
char *sArr2 = malloc(42 * sizeof(char));
for(int i =0; i<lineCount2+lineCount2;i++){
char *sArr = malloc(42 * sizeof(char));
char *sArr2 = malloc(42 * sizeof(char));
fscanf(stream2, "%s %s", sArr,sArr2);
//printf("%s %s ", sArr,sArr2);
LIST_INSERT_CODEX(&headC, sArr);
LIST_INSERT_CODEX(&headC, sArr2);
i++;
}
//printf("\n\n-----------------------------\n\n");
printListC(headC);
printf("\n\n");
printf("head->data:%s\theadC->word1:%s",(head)->data,(headC)->word1);
for(int i = 0;i<wordcount;i++){
printf("\nLIST_CORRECT CALL #%d\n",i+1);
//LIST_CORRECT(&headC,&head,lineCount2,i);
LIST_CORRECT(*(&headCP),*(&headP),lineCount2,i);
printf("head->data:%s\theadC->word1:%s",(head)->data,(headC)->word1);
}
printList(head);
return 0;
}

How to delete nodes of a linked list between two indices?

I have the following linked list implementation:
struct _node {
char *string;
struct _node *next;
}
struct _list {
struct _node *head;
struct _node *tail;
}
I want to make the following function:
void deleteList(struct _list *list, int from, int to) {
int i;
assert(list != NULL);
// I skipped error checking for out of range parameters for brevity of code
for (i = from; i <= to; i++) {
deleteNode(list->head, i);
}
}
// I ran this function with this linked list: [First]->[Second]->NULL
like this deleteNodes(list, 1, 1) to delete the second line and got
[First]->[Second]->NULL but when I run it like this deleteList(list, 0, 1) with this input [First]->[Second]->[Third]->NULL I get a seg fault.
Here is my deleteNode function
void deleteNode(struct _node *head, int index) {
if (head == NULL) {
return;
}
int i;
struct _node *temp = head;
if (index == 0) {
if (head->next == NULL) {
return;
}
else {
head = head->next;
free(head);
return;
}
}
for (i = 0; temp!=NULL && i<index-1; i++) {
temp = temp->next;
}
if (temp == NULL || temp->next == NULL) {
return;
}
Link next = temp->next->next;
free(temp->next);
temp->next = next;
}
I wrote a separate function to delete the head of the linked list if from or to = 0:
void pop(struct _node *head) {
if (head == NULL) {
return;
}
struct _node *temp = head;
head = head->next;
free(temp);
}
but it gives me seg fault or memory error Abort trapL 6.
It's all good to use just one struct, a node for your purpose.
struct node {
char *string;
struct node *next;
};
Then your loop for removing elements between two indices will not delete the right elements if you don't adjust the index according to the changing length of the list. And you must also return the new head of the list.
struct node *deleteList(struct node *head, unsigned from, unsigned to) {
unsigned i;
unsigned count = 0;
for (i = from; i <= to; i++) {
head = delete_at_index(head, i - count);
count++;
}
return head;
}
The help function delete_at_index looks as follows.
struct node *delete_at_index(struct node *head, unsigned i) {
struct node *next;
if (head == NULL)
return head;
next = head->next;
return i == 0
? (free(head), next) /* If i == 0, the first element needs to die. Do it. */
: (head->next = delete_at_index(next, i -
1), head); /* If it isn't the first element, we recursively check the rest. */
}
Complete program below.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
char *string;
struct node *next;
};
void freeList(struct node *head) {
struct node *tmp;
while (head != NULL) {
tmp = head;
head = head->next;
free(tmp->string);
free(tmp);
}
}
struct node *delete_at_index(struct node *head, unsigned i) {
struct node *next;
if (head == NULL)
return head;
next = head->next;
return i == 0
? (free(head), next) /* If i == 0, the first element needs to die. Do it. */
: (head->next = delete_at_index(next, i -
1), head); /* If it isn't the first element, we recursively check the rest. */
}
struct node *deleteList(struct node *head, unsigned from, unsigned to) {
unsigned i;
unsigned count = 0;
for (i = from; i <= to; i++) {
head = delete_at_index(head, i - count);
count++;
}
return head;
}
void pushvar1(struct node **head_ref, char *new_data) {
struct node *new_node = malloc(sizeof(struct node));
new_node->string = strdup(new_data);
new_node->next = (*head_ref);
(*head_ref) = new_node;
}
void printListvar1(struct node *node) {
while (node != NULL) {
printf(" %s ", node->string);
node = node->next;
}
printf("\n");
}
int main(int argc, char **argv) {
struct node *head = NULL;
for (int i = 0; i < 5; i++) {
char str[2];
sprintf(str, "node%d", i);
pushvar1(&head, str);
}
puts("Created Linked List: ");
printListvar1(head);
head = deleteList(head, 0, 2);
puts("Linked list after deleted nodes from index 0 to index 2: ");
printListvar1(head);
freeList(head);
return 0;
}
Test
Created Linked List:
node4 node3 node2 node1 node0
Linked list after deleted nodes from index 0 to index 2:
node1 node0
every programming problem can be solved by adding an extra level of indirection: use a pointer to pointer ...
unsigned deletefromto(struct node **head, unsigned from, unsigned to)
{
unsigned pos,ret;
struct node *this;
for (pos=ret=0; this = *head;pos++) {
if (pos < from) { head = &(*head)->next; continue; }
if (pos > to) break;
*head = this->next;
free(this);
ret++;
}
return ret; /* nuber of deleted nodes */
}

anagram detecting using linked lists in c

I'm trying to write a code that'll check 2 words if they are anagrams,using linked lists.To do that,I guess it should receive 2 words from the user and pass every letter they contain to linked list's nodes,and compare the nodes if they have the same letter,if so,remove the same letter from the second word.When the process is done,if the second list is empty,then they are anagrams.Even if 1 letter is not matching,it should return 0,but I don't know how to determine the length of these words,here is what I wrote so far
#include <stdio.h>
#include <stdlib.h>
struct node
{
struct node *prev;
struct node *next;
char data;
};
typedef struct node *NODE,NOD;
NODE last(NODE list)
{
if(list!=NULL)
while(list->next!=NULL)
list=list->next;
NODE lst;
lst=list;
return lst;
}
void insert( char letter, NODE list)
{
NODE nod;
nod=(NODE)malloc(sizeof(NOD));
nod->next=NULL;
nod->prev=NULL;
nod->data=letter;
if(list==NULL)
{
list=nod;
}
else
{
nod->prev=last(list);
last(list)->next=nod;
}
}
Just check that each word has the same number of each letter in it.
int anagrams(const char *a, const char *b) {
int counts[256] = {0};
while (*a) counts[*a++]++;
while (*b) counts[*b++]--;
for (int i = 0; i < 256; i++) {
if (counts[i]) return 0;
}
return 1;
}
Why use linked lists for such an easy problem?
O(N) solution:
Calculate frequencies of every letter for each word and then compare these 2 histograms. If they're equal, then one word can be obtained from another.
If you want to use your linked-list-based solution, then, the length of the word is, indeed:
Length of each input word (they must have the same length) - it can be calculated with a single traversal from the linked list head to the tail.
Amount of removed symbols
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct node {
char data;
struct node *prev;
struct node *next;
} NODE;
NODE *newNode(char ch){
NODE *p = malloc(sizeof(NODE));
if(p){
p->data = ch;
p->prev = p->next = NULL;
}
return p;
}
void insert(NODE **list, NODE *node){
if(*list == NULL){
*list = node;
return ;
}
NODE *curr = *list;
while(curr){
if(curr->data >= node->data){//insert sort
if(curr->prev == NULL)
*list = node;
else
curr->prev->next = node;
node->prev = curr->prev;
curr->prev = node;
node->next = curr;
break;
}
if(curr->next == NULL){
curr->next = node;
node->prev = curr;
break;
} else
curr = curr->next;
}
}
NODE *input_word(){
NODE *word=NULL;
int ch;
while(EOF!=(ch=getchar()) && ch != '\n'){
insert(&word, newNode(ch));
}
return word;
}
bool isAnagram(NODE *word1, NODE *word2){
while(word1 && word2){
if(word1->data != word2-> data)
return false;
word1 = word1->next;
word2 = word2->next;
}
return word1 == NULL && word2 == NULL;
}
int main(){
NODE *word1, *word2;
printf("input word : ");
word1 = input_word();
printf("input other word : ");
word2 = input_word();
if(isAnagram(word1, word2))
printf("YES\n");
else
printf("NO\n");
//drop(word1);drop(word2);
return 0;
}

Resources