Elegant implementation of circular singly-linked list in C? - c

Going through classic data structures and have stopped on linked lists.Just implemented a circular singly-linked list, but I'm under overwhelming impression that this list could be expressed in a more elegant manner, remove_node function in particular.
Keeping in mind efficiency and code readability, could anybody present a more concise and efficient solution for singly-linked circular list?
#include <stdio.h>
#include <stdlib.h>
struct node{
struct node* next;
int value;
};
struct list{
struct node* head;
};
struct node* init_node(int value){
struct node* pnode;
if (!(pnode = (struct node*)malloc(sizeof(struct node)))){
return NULL;
}
else{
pnode->value = value;
}
return pnode;
}
struct list* init_list(){
struct list* plist;
if (!(plist = (struct list*)malloc(sizeof(struct list)))){
return NULL;
}
plist->head = NULL;
return plist;
}
void remove_node(struct list*a plist, int value){
struct node* current, *temp;
current = plist->head;
if (!(current)) return;
if ( current->value == value ){
if (current==current->next){
plist->head = NULL;
free(current);
}
else {
temp = current;
do {
current = current->next;
} while (current->next != plist->head);
current->next = plist->head->next;
plist->head = current->next;
free(temp);
}
}
else {
do {
if (current->next->value == value){
temp = current->next;
current->next = current->next->next;
free(temp);
}
current = current->next;
} while (current != plist->head);
}
}
void print_node(struct node* pnode){
printf("%d %p %p\n", pnode->value, pnode, pnode->next);
}
void print_list(struct list* plist){
struct node * current = plist->head;
if (!(current)) return;
if (current == plist->head->next){
print_node(current);
}
else{
do {
print_node(current);
current = current->next;
} while (current != plist->head);
}
}
void add_node(struct node* pnode,struct list* plist){
struct node* current;
struct node* temp;
if (plist->head == NULL){
plist->head = pnode;
plist->head->next = pnode;
}
else {
current = plist->head;
if (current == plist->head->next){
plist->head->next = pnode;
pnode->next = plist->head;
}
else {
while(current->next!=plist->head)
current = current->next;
current->next = pnode;
pnode->next = plist->head;
}
}
}

Take a look at the circular linked list in the Linux kernel source: http://lxr.linux.no/linux+v2.6.36/include/linux/list.h
Its beauty derives from the fact that you don't have a special struct for your data to fit in the list, you only have to include the struct list_head * in the struct you want to have as a list. The macros for accessing items in the list will handle the offset calculation to get from the struct list_head pointer to your data.
A more verbose explanation of the linked list used in the kernel can be found at kernelnewbies.org/FAQ/LinkedLists (Sorry, I dont have enough karma to post two hyperlinks).
Edit: Well, the list is a double-linked list and not a single-linked one like you have, but you could adopt the concept and create your own single-linked list.

List processing (particularly of circular lists) gets way easier when you treat the list head like an element of the list (a so-called "sentinel"). A lot of special cases just disappear. You can use a dummy node for the sentinel, but if the next pointer is first in the struct, you don't need to do even that. The other big trick is to keep a pointer to the next pointer of the previous node (so you can modify it later) whenever you modify the list. Putting it all together, you get this:
struct node* get_sentinel(struct list* plist)
{
// use &plist->head itself as sentinel!
// (works because struct node starts with the next pointer)
return (struct node*) &plist->head;
}
struct list* init_list(){
struct list* plist;
if (!(plist = (struct list*)malloc(sizeof(struct list)))){
return NULL;
}
plist->head = get_sentinel(plist);
return plist;
}
void add_node_at_front(struct node* pnode,struct list* plist){
pnode->next = plist->head;
plist->head = pnode;
}
void add_node_at_back(struct node* pnode,struct list* plist){
struct node *current, *sentinel = get_sentinel(plist);
// search for last element
current = plist->head;
while (current->next != sentinel)
current = current->next;
// insert node
pnode->next = sentinel;
current->next = pnode;
}
void remove_node(struct list* plist, int value){
struct node **prevnext, *sentinel = get_sentinel(plist);
prevnext = &plist->head; // ptr to next pointer of previous node
while (*prevnext != sentinel) {
struct node *current = *prevnext;
if (current->value == value) {
*prevnext = current->next; // remove current from list
free(current); // and free it
break; // we're done!
}
prevnext = &current->next;
}
}
void print_list(struct list* plist){
struct node *current, *sentinel = get_sentinel(plist);
for (current = plist->head; current != sentinel; current = current->next)
print_node(current);
}

A few comments:
I think the remove function doesn't correctly adjust the circular list pointers when you delete the head node and the list is larger than 3 elements. Since the list is circular you have to point the last node in the list to the new head.
You might be able to shorten the remove function slightly by creating a "find_node" function. Since the list is circular, however, there will still be the edge case of deleting the head node which will be more complex than in a non-circular list.
Code "beauty" is in the eye of the beholder. As code goes yours is easy to read and understand which beats a lot of code in the wild.

I use the following to create a dynamic circular singly linked list. All it requires is the size.
Node* createCircularLList(int size)
{
Node *it; // to iterate through the LList
Node *head;
// Create the head /1st Node of the list
head = it = (Node*)malloc(sizeof(Node));
head->id = 1;
// Create the remaining Nodes (from 2 to size)
int i;
for (i = 2; i <= size; ++i) {
it->next = (Node*)malloc(sizeof(Node)); // create next Node
it = it->next; // point to it
it->id = i; // assign its value / id
if (i == 2)
head->next = it; // head Node points to the 2nd Node
}
// close the llist by having the last Node point to the head Node
it->next = head;
return head; // return pointer to start of the list
}
And i define Node ADT like so:
typedef struct Node {
int id;
struct Node *next;
} Node;

Related

Inserting at head of linked list?

Im trying to insert a node at the head of a linked list, and I'm not exactly sure why this function isn't working. I thought it was a fairly simple task, but I seem to be missing something here. I've also included my structs and a portion of main so you can get a clearer understanding of the code. Thanks
typedef struct node
{
struct node *next;
int data;
} node;
typedef struct LinkedList
{
node *head;
node *tail;
} LinkedList;
LinkedList *create_list(void)
{
return calloc(1, sizeof(LinkedList));
}
node *create_node(int data)
{
node *ptr = calloc(1, sizeof(node));
ptr->data = data;
return ptr;
}
void head_insert(LinkedList *list, int data) // problem
{
node *newHead = create_node(data);
newHead->next = list->head;
}
void print_list_helper(node *head)
{
if (head == NULL)
return;
printf("%d%c", head->data, (head->next == NULL) ? '\n' : ' ');
print_list_helper(head->next);
}
void print_list(LinkedList *list)
{
if (list == NULL || list->head == NULL)
return;
print_list_helper(list->head);
}
int main(void)
{
LinkedList *list = create_list();
head_insert(list, 8);
print_list(list); // print linked list function
return 0;
}
So I created a new Node, and set node->next to the head of the list. Im not sure what else im missing here. I have another function that prints the lists, thats why the function is void.
Add these lines at the end of your head_insert() function definition:
if (list->head == NULL)
{
list->tail = newHead;
}
list->head = newHead;
In your function, after adding new node at head the struct LinkedList still pointed to the previous head. You should change that head to the newly inserted head. And if there was no nodes in the list you should also set the newly created head
Here is the full function.
void head_insert(LinkedList *list, int data)
{
node *newHead = create_node(data);
newHead->next = list->head;
if (list->head == NULL)
{
list->tail = newHead;
}
list->head = newHead;
}

C: Problems with Reversing a linked list

I'm writing a program to create a linked list(a node), then reverse it. The linked list contains data and the address of the next.
typedef struct node{
int data;
struct node *next;
}node;
Firstly, I create the linked list.
struct node *Insert_value(int dataInput,node* head)
{
node *new_node=NULL;
new_node = malloc(sizeof(node));
new_node -> next = head;
new_node -> data = dataInput;
head = new_node;
return head;
}
After that, i create a function to print these data. (i called it PrintNode)
while(head!= NULL)
{
printf("%d\t",head->data);
head= head->next;
}
printf("\n");
}
Finally, a function created to reverse the linked list.
struct node* Reversing(node **head)
{
node *current, *previous, *first;
current = previous = first = *head;
first = first->next->next;
current = current->next;
previous ->next = NULL;
current->next = previous;
while(first != NULL)
{
previous = current;
current = first;
first = first -> next;
previous->next = current;
}
return current;
}
It's my full program.
#include <stdio.h>
#include <stdlib.h>
typedef struct node{
int data;
struct node *next;
}node;
struct node *Insert_value(int dataInput,node* head);
struct node * Reversing(node **head);
void PrintNode(node *head);
main()
{
node *head = NULL;
int i=0,dataInput;
while(i!=5)
{
printf("input your elements: ");
scanf("%d",&dataInput);
head = Insert_value(dataInput,head);
i++;
}
PrintNode(head);
head = Reversing(&head);
PrintNode(head);
}
struct node *Insert_value(int dataInput,node* head)
{
node *new_node=NULL;
new_node = malloc(sizeof(node));
new_node -> next = head;
new_node -> data = dataInput;
head = new_node;
return head;
}
struct node* Reversing(node **head)
{
node *current, *previous, *first;
current = previous = first = *head;
first = first->next->next;
current = current->next;
previous ->next = NULL;
current->next = previous;
while(first != NULL)
{
previous = current;
current = first;
first = first -> next;
previous->next = current;
}
return current;
}
void PrintNode(node* head)
{
while(head!= NULL)
{
printf("%d\t",head->data);
head= head->next;
}
printf("\n");
}
After debugging lots of times, I know that these functions are fine. However, after the reverse function, the address of the next node of the head variable is NULL. Can you explain and give me some pieces of advice?
The one line change that will solve your problem will be (you visualized it a bit wrong).
current->next =previous;
in place of
previous->next = current;
Your code will blowup for single element linked list. Add a proper check for that in the function Reversing(). In case there is single element first->next will be NULL. But you wrote first->next->next which will be undefined behavior in case first->next is NULL.
In earlier case you were just creating a linked list in Reversing() with the links unchanged but head was pointing to the last node. So the next of it was NULL.
Modify Reversing such that new nodes are appended at the end. When going through the list, you need to save the next node ahead of time (node *next = current->next)
struct node* Reversing(node **head)
{
node *current = *head;
node *reverse = NULL;
while(current)
{
node *next = current->next;
if(!reverse)
{
reverse = current;
reverse->next = NULL;
}
else
{
current->next = reverse;
}
reverse = current;
current = next;
}
return reverse;
}

Reversing a Linked List using recursion in C

I'm fairly new to C and I am trying to create a function to reverse a linked list, passing only the List itself as a parameter. Is this possible to do without passing a node as a parameter?
Here is my code so far, I know it does not work correctly because I cannot figure out how to make the recursive call on the rest of the list.
void reverse(LL_t *L) {
if (L->head->next == NULL) {
return;
}
node_t *rest = L->head->next;
reverse(rest);
node_t *q = rest->next;
q->next = rest;
rest->next = NULL;
}
As well here are my type definitions.
typedef struct {
node_t *head;
node_t *tail;
} LL_t;
typedef struct _node {
int data;
struct _node *next;
} node_t;
You can reverse the list with a simple loop, recursion is not needed and given your API, not appropriate.
Here is a modified version of your function:
void reverse(LL_t *L) {
node_t *prev = NULL;
node_t *curr = L->head;
L->tail = curr;
while (curr != NULL) {
node_t *next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
L->head = prev;
}
If you are required to use recursion, you can test if the list is empty or limited to a singleton and do nothing, otherwise remove the head element, reverse the resulting list and append the element to the end:
void reverse(LL_t *L) {
if (L->head != L->tail) {
/* at least 2 elements */
node_t *node = L->head;
L->head = node->next;
node->next = NULL;
reverse(L);
L->tail = L->tail->next = node;
}
}
Note that this recursive approach may have undefined behavior if the list is too long as reverse will recurse too many times and cause a stack overflow.
struct node {
int value;
struct node* next;
};
Non-recursive definition operating in constant stack space:
void reverse(struct node** ptr) {
struct node* prev_ptr;
struct node* node_ptr;
if (prev_ptr = * ptr) {
node_ptr = prev_ptr -> next;
prev_ptr -> next = NULL;
while (node_ptr) {
struct node* temp = node_ptr -> next;
node_ptr -> next = prev_ptr;
prev_ptr = node_ptr;
node_ptr = temp;
}
* ptr = prev_ptr;
}
}
Extensionally equivalent recursive definition:
void reverse(struct node** ptr) {
struct node* node_ptr;
if (node_ptr = * ptr) {
node_ptr -> next = NULL;
* ptr = reverse_rec(node_ptr, node_ptr -> next);
}
}
struct node* reverse_rec(struct node* prev_ptr, struct node* node_ptr) {
if (! node_ptr) { return prev_ptr; }
struct node* temp = reverse_rec(node_ptr, node_ptr -> next);
node_ptr -> next = prev_ptr;
return temp;
}
This works, but using recursion to reverse a list requires O(n) stack space overhead. The concept here is to advance the static instance of L->head, while keeping a local copy of head for each level of recursion. Recursion continues until the end of the list is reached, then the list is reversed using the local instances of head as reverse() returns backup the call chain.
void reverse(LL_t *L)
{
node_t *head;
if(L->head == NULL || L->head->next == NULL)
return;
head = L->head;
L->head = head->next;
reverse(L);
head->next->next = head; // reverse the nodes
head->next = NULL;
L->tail = head; // ends up setting tail to what was 1st node
}
//A simple program to reverse a Linked List
void reverse(struct node* head_ref)
{
struct node* first;
struct node* rest;
if (head_ref == NULL)
return;
first = head_ref;
rest = first->next;
if (rest == NULL)
return;
reverse(rest);
first->next->next = first;
first->next = NULL;
head_ref = rest;
}

Reuseable linked list implementation

Hi I'm trying to implement a generic linked list. I've got something working using the following code but I can't see an obvious and neat way to remove the dependance on the global pointers (curr and root,) and thus allow multiple linked lists to be defined. If I were using c++ I would probably just wrap the whole thing in a class, but as it is I can only see one solution which is manually handling and passing root and curr to the functions that need them. I'm sure there is a better way than this so how would you go about this.
Thanks
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
struct Node{
int value;
struct Node *next;
};
struct Node * curr = NULL;
struct Node * root = NULL;
struct Node * createList(int val){
struct Node *n = malloc(sizeof(struct Node));
if(n==NULL){
printf("Node creation failed\n");
return NULL;
}
n->value = val;
n->next = NULL;
root=curr=n;
return n;
}
struct Node * extendList(int val, bool end){
if(curr == NULL){
return createList(val);
}
struct Node * newNode = malloc(sizeof(struct Node));
if(newNode==NULL){
printf("Node creation failed\n");
return NULL;
}
newNode->value = val;
newNode->next = NULL;
if(end){
curr->next = newNode;
curr = newNode;
}
else{
newNode->next = root;
root=newNode;
}
return curr;
}
void printList(void){
struct Node *ptr = root;
while(ptr!=NULL){
printf("%d\n",ptr->value);
ptr = ptr->next;
}
return;
}
struct Node * pos_in_list(unsigned int pos, struct Node **prev){
struct Node * ptr = root;
struct Node * tmp = NULL;
unsigned int i = 0;
while(ptr!=NULL){
if(i == pos){
break;
}
tmp = ptr;
ptr=ptr->next;
i++;
}
*prev = tmp;
return ptr;
}
void deletefromlist(int pos){
struct Node * del = NULL;
struct Node * prev = NULL;
del = pos_in_list(pos,&prev);
if(del == NULL)
{
printf("Out of range\n");
}
else
{
if(prev != NULL)
prev->next = del->next;
if(del == curr)
{
curr = prev;
}
else if(del == root)
{
root = del->next;
}
}
free(del);
del = NULL;
}
void deleteList(){
struct Node * del = root;
while(curr!=NULL){
curr = del->next;
free(del);
del=curr;
}
root = NULL;
curr = NULL;
}
int main(void)
{
int i;
for(i=0;i<10;i++){
extendList(i,true);
}
for(i=10;i>0;i--){
extendList(i,false);
}
printList();
deletefromlist(5);
printList();
deleteList();
return 0;
}
Create a Structure of Node * root and Node * curr
struct LinkedList{
struct Node * curr;
struct Node * next;
};
You can create another struct to hold the curr and root. This struct will function like a "linked-list object" frontend, while your node structs will be the backend. As an added benefit, you can store other attributes about the linked-list, like the number of elements in the list.
struct LinkedList {
int numElements;
struct Node * curr;
struct Node * root;
};
You can modify your functions to work with this struct, and once you are done, the benefit is that the end-user can create many linked-lists, and all they have to do is call the functions and pass in their pointers to the LinkedList struct.
The way this is usually done is by giving each function an argument for the linked list pointer. Like this:
struct Node * extendList(struct Node * head, int val, bool end){
if(head == NULL){
return createList(val);
}
struct Node * newNode = malloc(sizeof(struct Node));
if(newNode==NULL){
printf("Node creation failed\n");
return NULL;
}
newNode->value = val;
newNode->next = NULL;
struct Node * tail = head;
while (tail->next) tail = tail->next;
tail->next = newNode;
tail = newNode;
return newNode; // return the new node
}
Which removes any need for a global pointer and allows for an arbitrary number of lists. In fact, I would strongly advise you to avoid the use of global variables in this context.
I had submitted a review for a linked list implementation you can check out. You may want to check the criticisms to, the ones that may apply to your own implementation.
I have implemented a generic list in C.
It is intended to be used as a static library. List operations (on generic data) are exposed from a list service. As you have asked,
neat way to remove the dependance on the global pointers (head)
Defining multiple linked lists.
This list service accomplish both these features in following way,
Upon creating a new Linked list this service returns a unique identifier representing it instead of traditional Linked list head pointer. This way client code can't directly corrupt linked list. this list service allows creation of multiple linked lists. Each having unique id. It is upto client to free lists when they are done and service can re-use that slot later when creating a new one. Maintaining global head pointer for each list is mandatory in any approach, but here is it hidden inside list service.
Following is my implementation :
https://github.com/rajan-goswami/glist/wiki
Take a look at the Berkeley-derived generic implementations for some other ideas on how to do it.
Documentation queue(3)
Source OpenBSD, Linux libc

trouble updating tail pointer in queue adt using singly linked list

i am trying to make a queue library that is based on a linked list library i already made. specifically i am having troubles updating the tail pointer in the queue structure after i add a new node to the linked list.
linked list structure:
struct listNode {
int nodeLength;
int nodeValue;
struct listNode *next;
};
typedef struct listNode node;
queue structure:
struct QueueRecord {
node *list;
node *front;
node *back;
int maxLen;
};
typedef struct QueueRecord queue;
so here is my add function in the queue library
void add(queue currentQueue, int data){
addTail(currentQueue.list, data, data+5);
currentQueue.back = currentQueue.back->next;
}
and the addTail function from the linked list library
void addTail (node *head, int value, int length) {
node *current = head;
node *newNode = (struct listNode *)malloc(sizeof(node));
newNode = initNode(value, length);
while (current->next != NULL)
current = current->next;
newNode->next = NULL;
current->next = newNode;
}
so again my problem is the tail pointer is not getting set to the last node in the list. it is remaining in the same place as the head pointer. ive been researching this for hours trying to see if im just missing something small but i cant find it. if more code or explanation is needed to understand my problem i can provide it.
how a queue is created:
queue createQueue(int maxLen){
queue newQueue;
newQueue.list = createList();
newQueue.front = newQueue.list;
newQueue.back = newQueue.list;
newQueue.maxLen = maxLen;
return newQueue;
}
node *createList (){
node *head = NULL;
head = (struct listNode *)malloc(sizeof(node));
head->next = NULL;
return head;
}
node *initNode (int value, int length){
node *newNode = NULL;
newNode = (struct listNode *)malloc(sizeof(node));
newNode->nodeValue = value;
newNode->nodeLength = length;
newNode->next = NULL;
return newNode;
}
void add(queue currentQueue, int data){
You are passing a copy of the queue struct to add, so only the copy's members are changed. You need to pass a queue* to the function to be able to change the members of the queue itself.
void add(queue *currentQueue, int data){
if (currentQueue == NULL) {
exit(EXIT_FAILURE);
}
addTail(currentQueue->list, data, data+5);
currentQueue->back = currentQueue->back->next;
}
and call it as add(&your_queue);
In your addTail function, you should check whether head is NULL too.
And with
node *newNode = (struct listNode *)malloc(sizeof(node));
newNode = initNode(value, length);
in addTail, you have a serious problem. With the assignment newNode = initNode(value, length);, you are losing the reference to the just malloced memory.
If initNode mallocs a new chunk of memory, it's "just" a memory leak, then you should remove the malloc in addTail.
Otherwise, I fear initNode returns the address of a local variable, à la
node * initNode(int val, int len) {
node new;
new.nodeValue = val;
new.nodeLength = len;
new.next = NULL;
return &new;
}
If initNode looks similar to that, that would cause a problem since the address becomes invalid as soon as the function returns. But your compiler should have warned you, if initNode looked like that.
Anyway, without seeing the code for initNode, I can't diagnose the cause.
But if you change your addTail to
void addTail (node *head, int value, int length) {
if (head == NULL) { // violation of contract, die loud
exit(EXIT_FAILURE);
}
node *current = head;
node *newNode = malloc(sizeof(node));
if (newNode == NULL) {
exit(EXIT_FAILURE); // or handle gracefully if possible
}
newNode->nodeValue = value;
newNode->nodeLength = length;
newNode->next = NULL;
while (current->next != NULL)
current = current->next;
current->next = newNode;
}
it should work.
However, since you have pointers to the first and the last node in the list, it would be more efficient to use the back pointer to append a new node,
void add(queue *currentQueue, int data){
node *newNode = malloc(sizeof *newNode);
if (newNode == NULL) {
exit(EXIT_FAILURE); // or handle gracefully if possible
}
newNode->nodeValue = data;
newNode->nodeLength = data+5;
newNode->next = NULL;
currentQueue->back->next = newNode;
currentQueue->back = newNode;
}
since you needn't traverse the entire list to find the end.
A simple sample programme
#include <stdlib.h>
#include <stdio.h>
struct listNode {
int nodeLength;
int nodeValue;
struct listNode *next;
};
typedef struct listNode node;
struct QueueRecord {
node *list;
node *front;
node *back;
int maxLen;
};
typedef struct QueueRecord queue;
node *createList (){
node *head = NULL;
head = (struct listNode *)malloc(sizeof(node));
head->next = NULL;
return head;
}
void addTail (node *head, int value, int length) {
if (head == NULL) { // violation of contract, die loud
exit(EXIT_FAILURE);
}
node *current = head;
node *newNode = malloc(sizeof(node));
if (newNode == NULL) {
exit(EXIT_FAILURE); // or handle gracefully if possible
}
newNode->nodeValue = value;
newNode->nodeLength = length;
newNode->next = NULL;
while (current->next != NULL)
current = current->next;
current->next = newNode;
}
queue createQueue(int maxLen){
queue newQueue;
newQueue.list = createList();
newQueue.front = newQueue.list;
newQueue.back = newQueue.list;
newQueue.maxLen = maxLen;
return newQueue;
}
void add(queue *currentQueue, int data){
if (currentQueue == NULL) {
exit(EXIT_FAILURE);
}
addTail(currentQueue->list, data, data+5);
currentQueue->back = currentQueue->back->next;
}
int main(void) {
queue myQ = createQueue(10);
for(int i = 1; i < 6; ++i) {
add(&myQ, i);
printf("list: %p\nfront: %p\nback: %p\n",
(void*)myQ.list, (void*)myQ.front, (void*)myQ.back);
}
node *curr = myQ.front->next;
while(curr) {
printf("Node %d %d, Back %d %d\n", curr->nodeValue,
curr->nodeLength, myQ.back->nodeValue, myQ.back->nodeLength);
curr = curr->next;
}
while(myQ.list) {
myQ.front = myQ.front->next;
free(myQ.list);
myQ.list = myQ.front;
}
return 0;
}
works as expected, also with the alternative add implementation.
i think you never initialized back, so back->next is some random pointer?

Resources