I use the following code snippet to add an element to the back of my doubly circular linked list.
typedef struct node
{
int nb;
struct node *prev;
struct node *next;
} st_node;
void add_back(st_node *origin, st_node *node)
{
st_node *tmp;
if (!origin || !node)
exit(1);
tmp = origin;
while (tmp->next != origin)
tmp = tmp->next;
tmp->next = node;
node->prev = tmp;
node->next = origin;
origin->prev = node;
}
Then I print my list with the folling function :
void printer(st_node *origin)
{
st_node *node;
node = origin;
while (node->next != origin)
{
printf("%d\n", node->nb);
node = node->next;
}
printf("%d\n", node->nb);
}
I got the origin value with printf and then random values in a loop. I don't know what to do and I realized origin->prev = node; was causing the problem inside the add_back function but I don't know why.
Here's the main:
int main(int ac, char **av)
{
st_node *stack;
int i;
if (ac <= 2)
return (1);
stack = create_element(atoi(av[1]));
i = 2;
while (i < ac)
add_back(stack, create_element(atoi(av[i++])));
printf("Stack:\n");
printer(stack);
}
st_node *create_element(int nb)
{
st_node *element;
element = malloc(sizeof(st_node *));
element->nb = nb;
element->next = element;
element->prev = element;
return (element);
}
Your create_element() function is wrong. It does not allocate enough memory for each node. This ...
st_node *element;
element = malloc(sizeof(st_node *));
... should be ...
st_node *element;
element = malloc(sizeof(st_node));
... or, better ...
st_node *element;
element = malloc(sizeof(*element));
With that correction, and adding a closing brace to main(), your program works for me.
Several bugs:
malloc in create_element is wrong
In add_back, the order of the link setting is wrong
In add_back, no need to loop to find the tail node. It is origin->prev
The printer function will segfault on an empty list because it is dereferencing node before checking whether it is non-null
The first if in main is too strict: It does not allow: ./myprogram 1 (i.e. a list with one element)
Here is the refactored/working code. It is annotated with the bugs/fixes:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int nb;
struct node *prev;
struct node *next;
} st_node;
st_node *
create_element(int nb)
{
st_node *element;
// NOTE/BUG: does _not_ allocate enough space (causing UB/undefined behavior)
#if 0
element = malloc(sizeof(st_node *));
#else
element = malloc(sizeof(*element));
#endif
element->nb = nb;
element->next = element;
element->prev = element;
return (element);
}
void
add_back(st_node *origin, st_node *node)
{
st_node *tmp;
if (!origin || !node)
exit(1);
// NOTE/BUG: no need to traverse -- origin->prev is the back
#if 0
tmp = origin;
while (tmp->next != origin)
tmp = tmp->next;
#else
tmp = origin->prev;
#endif
// NOTE/BUG: order and set is incorrect -- causes self loop
#if 0
tmp->next = node;
node->prev = tmp;
node->next = origin;
#else
node->prev = tmp;
node->next = tmp->next;
tmp->next = node;
#endif
origin->prev = node;
}
void
printer(st_node *origin)
{
st_node *node;
// NOTE/BUG: this will segfault on an empty list
#if 1
node = origin;
while (node->next != origin) {
printf("%d\n", node->nb);
node = node->next;
}
printf("%d\n", node->nb);
#else
node = origin;
if (node != NULL) {
while (1) {
printf("%d\n", node->nb);
node = node->next;
if (node == origin)
break;
}
}
#endif
}
int
main(int ac, char **av)
{
st_node *stack;
int i;
// NOTE/BUG: does _not_ allow for list of only one element
#if 0
if (ac <= 2) {
#else
if (ac < 2) {
#endif
printf("main: too short\n");
return (1);
}
stack = create_element(atoi(av[1]));
// NOTE/BUG: for loop is cleaner
#if 0
i = 2;
while (i < ac)
add_back(stack, create_element(atoi(av[i++])));
#else
for (i = 2; i < ac; ++i)
add_back(stack, create_element(atoi(av[i])));
#endif
printf("Stack:\n");
printer(stack);
}
In the above, I used cpp conditionals to denote old/broken vs. new/fixed code:
#if 0
// old code
#else
// new code
#endif
The above code fixed most of the bugs, but the program could not create an empty list.
Here's some more cleanup/refactoring to make the program more general. In particular, I generalized add_back to allow adding a node to an empty list. In the original code, it treated this as a fatal exit condition.
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int nb;
struct node *prev;
struct node *next;
} st_node;
st_node *
create_element(int nb)
{
st_node *element;
element = malloc(sizeof(*element));
element->nb = nb;
element->next = element;
element->prev = element;
return (element);
}
st_node *
add_back(st_node *origin, st_node *node)
{
st_node *tmp;
if (node == NULL)
exit(1);
do {
// add to empty list
if (origin == NULL) {
origin = node;
break;
}
tmp = origin->prev;
node->prev = tmp;
node->next = tmp->next;
tmp->next = node;
origin->prev = node;
} while (0);
return origin;
}
void
printer(st_node *origin)
{
st_node *node;
node = origin;
if (node != NULL) {
while (1) {
printf("%d\n", node->nb);
node = node->next;
if (node == origin)
break;
}
}
}
int
main(int ac, char **av)
{
st_node *stack = NULL;
int i;
for (i = 1; i < ac; ++i)
stack = add_back(stack, create_element(atoi(av[i])));
printf("Stack:\n");
printer(stack);
}
Related
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(¤t->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;
}
lengthOfLinkedList() below counts the number of nodes in a linked list, but the runtime is linear which I do not want. How can I reduce it to a constant runtime function? Are there any library functions I can use?
typedef struct node {
int val;
struct node *next;
} NODE;
struct list_struct {
NODE *front;
NODE *back;
};
int lengthOfLinkedList(LIST *l) {
NODE *n = l->front;
int count = 0;
while (n != NULL) {
count++;
n = n->next;
}
return count;
}
You cannot achieve constant time size calculation with your current struct definition. Now, if you add a size_t member to the struct and use it to store the length, modifying it on any additions or deletions, you can access the length in constant time.
typedef struct node {
int val;
struct node *next;
size_t length;
} NODE;
Define the head-node struct accordingly.
For int value type the list-node remains same:
typedef struct _node {
int val;
struct _node* next;
} listNode_t;
We alter the head-node to suit our needs:
typedef struct {
// add members as scenario demands
int size; // updated after every insert/delete
int min; // updated/checked after every insert/delete/update
int max; // updated/checked after every insert/delete/update
long sum; // updated after every insert/delete/update
listNode_t* first; // to insert/delete from beginning (LIFO-Stack)
listNode_t* last; // to insert at the end (can't delete though)
} listHead_t;
Then you can get those values in O(1), provided they're updated consistently.
listHead_t* head;
...
int listLength = list_getSize (head);
int listMin = list_getMin (head);
int listMax = list_getMax (head);
long listSum = list_getSum (head);
float listAvg = list_getAverage (head); // (float)sum/size
/* List Methods */
list_prefix (head, value); // add value as the first node
list_suffix (head, value); // add value as the last node
That makes list_prefix() like:
...
#include <limits.h>
...
listHead_t* head = list_init_head ();
...
...
listHead_t* list_init_head () {
listHead_t* head = malloc (sizeof(listHead_t));
if (!head) {
perror("list_init_head-malloc");
exit (1);
}
head->size = head->sum = 0;
head->first = head->last = NULL;
head->min = INT_MAX;
head->max = INT_MIN;
return head;
}
int list_prefix (listHead_t* head, int val) {
if (!head) return -1; // invalid call
listNode_t* node = malloc (sizeof(listNode_t));
if (!node) {
perror("list_prefix-malloc");
exit (1);
}
node->val = val;
// update list-head stats
++head->size;
head->sum += val;
if (val < head->min) head->min = val;
if (val > head->max) head->max = val;
if (!head->first) {
node->next = NULL;
head->first = head->last = node;
} else {
node->next = head->first;
head->first = node;
}
return 0;
}
I'm trying to implement a queue in C using a linked list. I ran my code through a C visualizer and it seems that the values A-E aren't being saved. As in, one node will contain the letter A then when queue_enqueue is called again, another node is created that holds the letter B and then the previous node that contained A just, disappears... My code contains other functions like dequeue and one to check if the queue is empty, but I took them out to keep my code short and they are independent of the functions provided here.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
struct node {
struct node *next;
struct node *prev;
char *value;
};
// The type for a list.
typedef struct list {
struct node head;
} List;
typedef struct queue {
List *list;
} Queue;
Queue *queue_create(void) {
Queue *q = (Queue*)malloc(sizeof(struct queue));
List *ptr = (List*)malloc(sizeof(struct list));
q->list = ptr;
q->list->head.next = NULL;
return q;
}
void queue_destroy(Queue *q) {
free(q->list->head.value);
free(q);
}
void queue_enqueue(Queue *q, const char *value) {
struct node *temp;
temp = malloc(sizeof(struct node));
temp->value = strdup(value);
temp->next = NULL;
q->list->head.next = temp;
q->list->head.value = temp;
}
int main(void) {
// Create an empty queue.
Queue *q = queue_create();
// Add the values A, B, ..., Z to the queue.
char str[] = "A";
for (char ch = 'A'; ch <= 'E'; ch++) {
str[0] = ch;
queue_enqueue(q, str);
}
// Clean up.
queue_destroy(q);
return 0;
}
To simplify your problem you should begin with a single-linked list and in your example there is no need to use char* as node value:
struct node {
struct node* next;
char value;
};
You also might want to add a element counter for your list:
typedef struct list {
struct node *head;
size_t num;
}
and a function to create a new node with the given value:
struct node *node_create(char value) {
struct node *nd = malloc(sizeof(struct node));
if (nd)
nd->value = value;
return nd;
}
The magic happens in the insert function but it is no rocket science at all. You either create your new node where head is pointing (empty list) or at the end of the list.
void list_insert(List *list, char value) {
if (!list)
return;
if (!list->head) {
// first element of list
list->head = node_create(value);
if (list->head)
list->num++;
}
else {
// move to the end of the list
struct node *nd = list->head;
while (nd->next) {
nd = nd->next;
}
nd->next = node_create(value);
if (nd->next)
list->num++;
}
}
Also make sure to properly initialize your list with some list_create function and when cleaning the list take care to free all list elements before releasing the memory of the list itself
You are not linking the chain pointers correctly.
And, setting q->list->head.value = temp; won't even compile.
For a doubly linked list, reusing a node struct as the front/back pointers (e.g prev/next) is doable but unclear. Better to redefine List slightly to use front/back--it's clearer.
Your destroy code is also wrong.
When appending to a list, the first time is slightly different than subsequent ones.
Here's the refactored code.
Since your code didn't change any of the list's next/prev pointers or temp's next/prev pointers, it wasn't clear whether you wanted to enqueue to the front or the back of the list, so I added both functions.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
struct node {
struct node *next;
struct node *prev;
char *value;
};
// The type for a list.
typedef struct list {
struct node *front;
struct node *back;
size_t count;
} List;
typedef struct queue {
List *list;
} Queue;
Queue *
queue_create(void)
{
Queue *q = malloc(sizeof(*q));
q->list = calloc(1,sizeof(List));
return q;
}
void
queue_destroy(Queue *q)
{
List *list = q->list;
struct node *cur;
struct node *next;
if (list != NULL)
cur = list->front;
else
cur = NULL;
for (; cur != NULL; cur = next) {
next = cur->next;
free(cur->value);
}
free(list);
free(q);
}
struct node *
node_create(const char *value)
{
struct node *temp = calloc(1,sizeof(*temp));
temp->value = strdup(value);
return temp;
}
void
queue_enqueue_front(Queue *q,const char *value)
{
struct node *temp = node_create(value);
List *list = q->list;
temp->next = list->front;
if (list->front != NULL)
list->front->prev = temp;
list->front = temp;
if (list->back == NULL)
list->back = temp;
list->count += 1;
}
void
queue_enqueue_back(Queue *q,const char *value)
{
struct node *temp = node_create(value);
List *list = q->list;
temp->prev = list->back;
if (list->back != NULL)
list->back->next = temp;
list->back = temp;
if (list->front == NULL)
list->front = temp;
list->count += 1;
}
void
queue_print_fwd(Queue *q,const char *who)
{
List *list = q->list;
struct node *cur;
if (who != NULL)
printf("%s:\n",who);
for (cur = list->front; cur != NULL; cur = cur->next)
printf(" %s\n",cur->value);
}
void
queue_print_rev(Queue *q,const char *who)
{
List *list = q->list;
struct node *cur;
if (who != NULL)
printf("%s:\n",who);
for (cur = list->back; cur != NULL; cur = cur->prev)
printf(" %s\n",cur->value);
}
int
main(void)
{
// Create an empty queue.
Queue *q = queue_create();
// Add the values A, B, ..., Z to the queue.
char str[] = "A";
for (char ch = 'A'; ch <= 'E'; ch++) {
str[0] = ch;
queue_enqueue_back(q, str);
#ifdef DEBUG
queue_print_fwd(q,"pushback");
#endif
}
for (char ch = 'K'; ch >= 'F'; ch--) {
str[0] = ch;
queue_enqueue_front(q, str);
#ifdef DEBUG
queue_print_fwd(q,"pushfront");
#endif
}
queue_print_fwd(q,"Forward");
queue_print_rev(q,"Reverse");
// Clean up.
queue_destroy(q);
return 0;
}
Here's the program output:
Forward:
F
G
H
I
J
K
A
B
C
D
E
Reverse:
E
D
C
B
A
K
J
I
H
G
F
UPDATE:
Here's a slightly cleaned up version.
There's probably no need to allocate q->list--It could just be declared as List list; instead of List *list;
Just for grins, I also added a node removal function (e.g. queue_unlink).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
typedef struct node Node;
struct node {
Node *next;
Node *prev;
char *value;
};
// The type for a list.
typedef struct list {
Node *front;
Node *back;
size_t count;
} List;
typedef struct queue {
List list;
} Queue;
Queue *
queue_create(void)
{
Queue *q = calloc(1,sizeof(*q));
return q;
}
void
queue_destroy(Queue *q)
{
List *list = &q->list;
Node *cur;
Node *next;
for (cur = list->front; cur != NULL; cur = next) {
next = cur->next;
free(cur->value);
list->count -= 1;
}
free(q);
}
void
queue_unlink(Queue *q,Node *cur)
{
List *list = &q->list;
do {
if (cur == NULL)
break;
Node *prev = cur->prev;
Node *next = cur->next;
if (prev != NULL)
prev->next = next;
if (next != NULL)
next->prev = prev;
if (list->front == cur)
list->front = next;
if (list->back == cur)
list->back = prev;
cur->prev = NULL;
cur->next = NULL;
list->count -= 1;
} while (0);
}
Node *
node_create(const char *value)
{
Node *temp = calloc(1,sizeof(*temp));
temp->value = strdup(value);
return temp;
}
void
queue_enqueue_front(Queue *q,const char *value)
{
Node *temp = node_create(value);
List *list = &q->list;
Node *front = list->front;
temp->next = front;
if (front != NULL)
front->prev = temp;
list->front = temp;
if (list->back == NULL)
list->back = temp;
list->count += 1;
}
void
queue_enqueue_back(Queue *q,const char *value)
{
Node *temp = node_create(value);
List *list = &q->list;
Node *back = list->back;
temp->prev = back;
if (back != NULL)
back->next = temp;
list->back = temp;
if (list->front == NULL)
list->front = temp;
list->count += 1;
}
int
queue_print_node(Node *cur,int totlen)
{
int curlen;
curlen = strlen(cur->value);
if ((totlen + curlen + 1) >= 78) {
fputc('\n',stdout);
totlen = 0;
}
fputc(' ',stdout);
totlen += 1;
fputs(cur->value,stdout);
totlen += curlen;
return totlen;
}
void
queue_print_fwd(Queue *q,const char *who)
{
List *list = &q->list;
Node *cur;
int totlen = 0;
if (who != NULL)
printf("%s:\n",who);
for (cur = list->front; cur != NULL; cur = cur->next)
totlen = queue_print_node(cur,totlen);
if (totlen > 0)
fputc('\n',stdout);
}
void
queue_print_rev(Queue *q,const char *who)
{
List *list = &q->list;
Node *cur;
int totlen = 0;
if (who != NULL)
printf("%s:\n",who);
for (cur = list->back; cur != NULL; cur = cur->prev)
totlen = queue_print_node(cur,totlen);
if (totlen > 0)
fputc('\n',stdout);
}
int
main(void)
{
// Create an empty queue.
Queue *q = queue_create();
// Add the values A, B, ..., Z to the queue.
char str[] = "A";
for (char ch = 'A'; ch <= 'E'; ch++) {
str[0] = ch;
queue_enqueue_back(q, str);
#ifdef DEBUG
queue_print_fwd(q,"pushback");
#endif
}
for (char ch = 'K'; ch >= 'F'; ch--) {
str[0] = ch;
queue_enqueue_front(q, str);
#ifdef DEBUG
queue_print_fwd(q,"pushfront");
#endif
}
for (int iter = 1; iter <= 10; ++iter) {
char buf[35];
int len = (rand() % (sizeof(buf) - 1)) + 1;
int idx = 0;
for (; idx < len; ++idx) {
int chr = (rand() % 26) + 'a';
buf[idx] = chr;
}
buf[idx] = 0;
queue_enqueue_back(q, buf);
}
queue_print_fwd(q,"Forward");
queue_print_rev(q,"Reverse");
// Clean up.
queue_destroy(q);
return 0;
}
It's the very first time I am trying to use a adjacency list and I am really confused with its declaration
This is my node structure and the list for using as my first node, what I called head
typedef struct node
{
int NodeNum;
struct node *next;
}node;
typedef struct list
{
node *head;
}list;
and here is where I try to allocate the correct amount of memory for the array of heads that the user wants
int n;
scanf("%d", &n);
list *NodList[n] = {0};
for(int i = 0; i < n; i++)
{
NodList[i] = (list*)malloc(sizeof(list));
NodList[i]->head = NULL;
}
Here is the thing, I want the user to tell me how many nodes I'll have and then allocate the correct amount of memory for it, but apparently I am getting something wrong here
Expanding a little bit on Antonin GAVREL's answer. Basically using the same linked list he brought up, and introducing an AListEntry used to represent the adjacency list. Each AListEntry points to a vertex and that vertex's adjacent vertices. It also points to the next AListEntry.
You could, instead, also just replace the AListEntry with a dynamically allocated array of Node pointers if you know the number of vertices ahead of time. Each index in the array will correspond to a vertex, and the pointer will point to the head Node pointer of your adjacent vertices for that vertex, which will a linked list. You'll end up with an array of linked lists.
#include <stdio.h>
#include <stdlib.h>
typedef struct Node
{
int value;
struct Node* next;
} t_Node;
t_Node* createNode(int value)
{
t_Node* node = (t_Node*)malloc(sizeof(t_Node));
node->value = value;
node->next = NULL;
return node;
}
t_Node* addNode(int value, t_Node* node)
{
node->next = createNode(value);
return node->next;
}
typedef struct AListEntry
{
t_Node* vertex;
t_Node* adjacentVertices;
struct AListEntry* next;
} t_AListEntry;
t_AListEntry* createAListEntry(
t_Node* vertex,
t_Node* adjacentVertices)
{
t_AListEntry* entry = (t_AListEntry*)malloc(sizeof(t_AListEntry));
entry->vertex = vertex;
entry->adjacentVertices = adjacentVertices;
entry->next = NULL;
return entry;
}
void printAListEntries(t_AListEntry* aList)
{
while (aList != NULL)
{
printf("%d -> [ ", aList->vertex->value);
t_Node* node = aList->adjacentVertices;
while (node != NULL)
{
printf("%d ", node->value);
node = node->next;
}
printf("]\n");
aList = aList->next;
}
}
int main()
{
t_Node* v1 = createNode(1);
t_Node* v1Adjacents = createNode(2);
addNode(3, v1Adjacents);
t_AListEntry* aList = createAListEntry(v1, v1Adjacents);
t_Node* v2 = createNode(2);
t_Node* v2Adjacents = createNode(1);
addNode(3, v2Adjacents);
aList->next = createAListEntry(v2, v2Adjacents);
t_Node* v3 = createNode(3);
t_Node* v3Adjacents = createNode(1);
addNode(2, v3Adjacents);
aList->next->next = createAListEntry(v3, v3Adjacents);
printAListEntries(aList);
return 0;
}
Example where the array is declared on the stack as a VLA:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct Node
{
int value;
struct Node *next;
} t_Node;
bool build_linked_list(t_Node **head, int n) {
t_Node *node;
t_Node *tmp;
static int a = 1024; // just for test purposes
if (!(node = (t_Node*)malloc(sizeof(t_Node))))
return false;
node->value = a;
*head = node;
for(int i = 1; i < n; i++)
{
if (!(tmp = (t_Node*)malloc(sizeof(t_Node))))
return false;
tmp->value = i + a;
node->next = tmp;
node = tmp;
}
a <<= 1; // so that other nodes have different values
return true;
}
int main(void) {
int n;
scanf("%d", &n);
t_Node *nodes[n];
for (int i = 0; i < n; i++) {
if (!build_linked_list(&nodes[i], n)) {
perror("Failed to malloc node");
return 1;
}
}
for (int i = 0; i < n; i++) {
while (nodes[i]) {
printf("%d\n", nodes[i]->value);
nodes[i] = nodes[i]->next;
}
}
return 0;
}
Let me know if you have any question
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 */
}