INTRODUCTION
A linked list is a linear data structure that includes a series of connected nodes, each node stores the data and address of the next node. While arrays can prove to be useful in computing, they still have some disadvantages when it comes to expanding arrays and memory arrays which is what linked list solves. The major difference between a linked list and an array is that data items are not stored in a contiguous location.
A linked list must always have a HEAD
pointer. The head pointer points to the first node of the linked list, this pointer is used to access the data in the linked and further transverse in the linked list.
To represent a linked list, we use another data structure called Structures
which is a user-defined data structure in C.
TYPES OF LINKED LIST
There are 4 types of linked lists, these linked lists can be modified to suit the project or the way data is to be structured by the developer.
Singly Linked List
Doubly Linked List
Circular Linked List
Doubly-Circular Linked List
Singly Linked List
Singly Linked List is the most common type of linked list, each node contains 2 parts; the data part and the address part. The data part contains the data stored in the node and the address part is a link to the next node. The last node of the linked list will point to NULL i.e. the last node doesn't point to any memory address.
The address of the first node is stored as the head pointer. The name singly linked list is because the nodes are having a single link to each other. This data structure cannot be transverse backward because it allows only forward sequential movement.
Representing a singly-linked list in C
struct node
{
int data;
struct node * next; /*the pointer to next node*/
}
Doubly Linked List
Doubly Linked List is a list that has two pointers to two different nodes, each node is made up of three parts i.e. two pointer parts and the data part. The first pointer points to the previous node and the second pointer points to the next node in the sequence. The pointers can also be known as forward and backward links.
Representing a doubly-linked list in C
struct node
{
int data;
struct node *prev; /*pointer to previous node*/
struct node *next; /*pointer to next node*/
}
In a doubly linked list, the first node's previous pointer *prev
is set to NULL because it doesn't point to any node since it is the first node of the list. The last node's next pointer *next
is set to NULL to indicate the end of the list.
Circular Linked List
Just as the name implies, this list is in a circular direction. It is a variation of a singly linked list, the difference is that the last node's address part *next
is set to store the address of the first node so that link between each node continues like a cycle.
Doubly-Circular Linked List
The doubly-circular linked list combines both the features of a circular linked list and a doubly linked list. In this type of list, the first node's previous pointer *prev
stores the address to the last node and the last node's next pointer *next
stores the address of the first node. Other node contains a link to the previous node, the next node and the data stored in the node.
DIFFERENCES BETWEEN AN ARRAY AND LINKED LIST
CASE STUDY | ARRAY | LINKED LIST |
Cost of accessing elements | An array allows random access to elements, once the base address is known e.g. arr[3] will access the fourth element of an array. | Random Access is not allowed, only sequential access is possible. |
Memory Utilization | Memory utilization is not efficient i.e. some memory allocated to an array may not be used. | It is very efficient. Memory is not wasted. |
Memory Requirement | The memory requirement of an array is less. e.g. storing 4 int elements in an array will cost 16bytes | The memory requirement is great. e.g. storing 4 int elements in a singly linked list may cost 36bytes. |
IMPLEMENTATION OF LINKED LIST
Let's write a simple program that takes four integer elements and stores them in a singly linked list.
Create 5 files; a header file
main.h
, our main function and 3 other C files to handle how functions. The header file will contain our function prototype./* This is the header file*/ #ifndef LIST_H #define LIST_H #include <stddef.h> #include <stdio.h> /** * struct listint_s - singly linked list * @n: integer * @next: points to the next node * * Description: singly linked list node structure * */ typedef struct listint_s { int n; struct listint_s *next; } listint_t; size_t print_list(const listint_t *h); listint_t *add_node_end(listint_t **head, const int n); void free_list(listint_t *head); #endif /*LIST_H*/
The first C file
print.c
will handle the printing of the data of each node in our linked list.#include "lists.h" /** * print_list - prints all the elements of a list_t. * @h: pointer to list. * * Return: the number of nodes. */ size_t print_list(const listint_t *h) { int count; count = 0; while (h != NULL) { printf("%d\n", h->n); h = h->next; count++; } return (count); }
The next C file
add_node_end
will handle the node, that is it will add any new node to the end of the previous node.#include "lists.h" #include <stdlib.h> /** * add_node_end - adds new node to end of list * @head: pointer to linked list * @n: number to bestored in linked list * Return: returns pointer to linked list */ listint_t *add_node_end(listint_t **head, const int n) { listint_t *newnode; listint_t *temp; temp = newnode = malloc(sizeof(listint_t)); if (newnode == NULL || temp == NULL) { return (NULL); } newnode->n = n; if (*head == NULL) *head = newnode; else { temp = *head; while (temp->next != NULL) temp = temp->next; temp->next = newnode; } return (newnode); }
This function will free the memory used by our function in creating the linked list, after the execution of the code.
#include "lists.h" #include <stdlib.h> /** * free_list - free the memory * @head: head pointer of linked list * Return: void */ void free_list(listint_t *head) { listint_t *temp; while (head != NULL) { temp = head; head = head->next; free(temp); } }
Now, the main function
#include "lists.h" /** * main - check the code * * Return: Always 0. */ int main(void) { listint_t *head; head = NULL; add_node_end(&head, 0); add_node_end(&head, 1); add_node_end(&head, 2); add_node_end(&head, 3); add_node_end(&head, 4); add_node_end(&head, 98); add_node_end(&head, 402); add_node_end(&head, 1024); print_list(head); free_list(head); head = NULL; return (0); }
Compile files in terminal
LINKED LIST IN THE REAL WORLD
Linked lists can also be used in the real world for:
Image viewer – Previous and next images are linked and can be accessed by the next and previous buttons. Previous and next page in a web browser – We can access the previous and next URL searched in a web browser by pressing the back and next buttons since they are linked as a linked list.
Music Player – Songs in the music player are linked to the previous and next songs. So you can play songs either from starting or ending of the list.
GPS navigation systems - Linked lists can be used to store and manage a list of locations and routes, allowing users to easily navigate to their desired destination.
Robotics - Linked lists can be used to implement control systems for robots, allowing them to navigate and interact with their environment.
Task Scheduling - Operating systems use linked lists to manage task scheduling, where each process waiting to be executed is represented as a node in the list.
Image Processing - Linked lists can be used to represent images, where each pixel is represented as a node in the list.
File Systems - File systems use linked lists to represent the hierarchical structure of directories, where each directory or file is represented as a node in the list.
Symbol Table - Compilers use linked lists to build a symbol table, which is a data structure that stores information about identifiers used in a program.
Undo/Redo Functionality - Many software applications implement undo/redo functionality using linked lists, where each action that can be undone is represented as a node in a doubly linked list.
Speech Recognition - Speech recognition software uses linked lists to represent the possible phonetic pronunciations of a word, where each possible pronunciation is represented as a node in the list.
Polynomial Representation - Polynomials can be represented using linked lists, where each term in the polynomial is represented as a node in the list.