2. Syllabus
Linked List: Limitations of array implementation, Memory Management: Static
(Stack) and Dynamic (Heap)Memory Allocation, Memory management functions.
Definition, Representation, Operations: getnode() and Freenode() operations, Types:
Singly Linked List. Linked list as a data Structure, Inserting and removing nodes from
a list, Linked implementations of stacks, Header nodes, Array implementation of lists.
3. Limitations of Array
Implementation
The array implementation of a linked list has several limitations compared to a traditional linked list
structure
• Fixed Size: Arrays have a fixed size, meaning that the size of the linked list is limited to the size of
the array at the time of its creation. If the linked list needs to grow beyond the array's capacity, it
requires resizing the array, which can be inefficient.
• Memory Wastage: Arrays require contiguous memory allocation. If the size of the array is initially
large but the linked Memory Wastage list doesn't use the entire allocated space, it results in memory
wastage.
• Insertions and Deletions: Insertions and deletions at arbitrary positions in the linked list using an array
require shifting elements, which can be inefficient, especially for large lists. For example, inserting an
element at the beginning or middle of the list might involve moving many elements to accommodate
the new element.
• Dynamic Memory Allocation: Arrays need contiguous memory allocation, which might not always be
available in the memory. This can limit the size of the list that can be created.
• Inflexibility: Arrays are not flexible in terms of size. Once created, the size cannot be easily changed
without creating a new array and copying elements, which can be time-consuming.
4. Static (Stack) and Dynamic (Heap)Memory
Allocation
Static Memory Allocation:
• Static memory allocation is performed
during the compilation process.
• In this method, memory is allocated for
the entire lifetime of the program.
• The memory is allocated on the stack,
which is a region of memory that
grows and shrinks as functions are
called and return.
• The stack is managed by the operating
system, and it follows the "Last In, First
Out" (LIFO) principle.
• It is represented by an array.
Dynamic Memory Allocation:
• Dynamic memory allocation is performed
at runtime, allowing for the allocation
and deallocation of memory as needed.
• This method is used when the size of the
data is not known at compile time or
when the data size can change during the
program's execution.
• Dynamic memory allocation is
performed using the heap, which is a
region of memory managed by the
operating system.
• The heap follows the "First In, First Out"
(FIFO) principle.
• It is represented by a pointer.
5. Memory management functions
• malloc():Allocates a single block of requested memory.
• calloc():Allocates multiple blocks of requested memory.
• realloc():Reallocates the memory occupied by malloc() or calloc() functions.
• free(): Frees the dynamically allocated memory.
6. malloc(): Allocates a single block of requested memory.
Syntax: ptr = (cast_type *) malloc (size_type);
Example:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *ptr;
int n = 5;
ptr =
(int*)malloc(n *
sizeof(int)); //
Allocates memory
for 5 integers
if (ptr == NULL)
{
printf("Memory allocation failedn");
exit(1);
}
// Use the allocated memory
free(ptr); // Freeing the allocated
7. calloc():Allocates multiple blocks of requested memory and initializes them to
zero.
Syntax: ptr = (cast-type*)calloc(size_type);
);
Example:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *ptr;
int n = 5;
ptr = (int*)calloc(n, sizeof(int)); // Allocates memory for 5
integers if (ptr == NULL)
{
printf("Memory allocation failedn");
exit(1);
}
// Use the allocated memory
free(ptr); // Freeing the allocated memory
return 0;
}
8. realloc():Reallocates the memory occupied by malloc() or calloc()
functions. Syntax: ptr = realloc (ptr,newsize);
Example:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *ptr;
int n = 5;
ptr =
(int*)malloc(n *
sizeof(int));
// Allocates
memory for 5
integers
if (ptr == NULL)
{
printf("Memory allocation failedn");
exit(1);
}
// Use the allocated memory
if (ptr == NULL) {
printf("Memory reallocation failedn");
exit(1);
} // Use the reallocated memory
free(ptr); // Freeing the allocated memory
return 0;
}
9. free():Frees the dynamically allocated memory.
Syntax: void free(void* ptr);
Example:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *ptr;
int n = 5;
ptr =
(int*)ma
lloc(n *
sizeof(in
t)); //
Allocate
s
memory
for 5
integers
if (ptr
==
NULL)
10. What is linked List?
A linked list is a linear data structure used for storing collections of data in the form of nodes. Each
node
in a linked list store two elements – data and address(link) of next node.
Representation of Node:
11. Representation of linked list:
Suppose, we want to store a list of numbers:20,25,30,35
But how to access the first node of the linked list ?
12. Getnode() and Freenode() operations
getNode() and freeNode() functions are typically used for memory
management.
getNode():
• This function allocates memory for a new node in the linked list.
• It initializes the node with the provided data and sets its next pointer to NULL.
• It returns a pointer to the newly created node.
Ex: struct Node* getNode(int data)
{
struct Node* newNode = (struct
Node*)malloc(sizeof(struct Node));
if (newNode != NULL)
{
newNode->data = data;
newNode->next = NULL;
}
return newNode;
}
13. freeNode():
• This function deallocates memory for a node in the linked list.
• It takes a pointer to the node that needs to be deallocated.
• After freeing the memory, it sets the pointer to NULL to avoid dangling pointers.
Ex: void freeNode(struct Node* node)
{
if (node != NULL)
{ free(node);
node = NULL;
}
}
NOTE: Dangling pointers refer to pointers that continue to point to a memory location
after
that memory has been deallocated or freed.
15. What is self referential structure?
Self referential structure is a structure which contains a pointer to a structure of the same type
struct abc
{
int a;
char b;
struct abc *self;
}
we will use self referential structure for creating a node of the single linked list
We have already seen that a node consists of data as well as link part, that means its combination of
two
different types. Now question is how to combine two different type into single type
It may be any data type
Addressing the next node
21. Algorithm insertAtBeginning(data):
Step 1: newNode = Allocate memory for a new
node
Step 2: if newNode is NULL:
Print "Memory allocation failed"
Return
Step 3: end if
Step 4: Set newNode's data field to data
or value
Set newNode's next pointer to
head
Set head to newnode
Step 5: end procedure void insertAtBeginning(int data)
{
struct Node* newNode = (structNode*)malloc(sizeof(struct Node));
if (newNode == NULL)
{ printf("Memory allocation failed
n"); return;
}
newNode->data = data;
newNode->next = head;
head = newNode;
}
22. //(For your Reference)
void insertAtbegining()
{
struct node *newnode;
int value;
newnode=(struct node *) malloc(sizeof(struct node *));
if(newnode==NULL)
{
printf("nOVERFLOW");
}
else
{
printf("n Enter valuen");
scanf("%d", &value);
newnode->data=value;
newnode->next=head;
//first link
head=newnode; //
second link
}
23. void insertAtEnd(int data)
{
struct Node* newNode = (struct
Node*)malloc(sizeof(struct Node));
if (newNode == NULL)
{ printf("Memory allocation failed
n"); return;
}
newNode->data = data;
newNode->next = NULL;
if (head == NULL) {
head = newNode;
return;
}
struct Node* temp = head;
while (temp->next !=
NULL) {
temp = temp->next;
}
temp->next = newNode;
}
Algorithm insertAtEnd(data):
Step 1:newNode = Allocate memory for a new
node
Step 2: if newNode is NULL:
Print "Memory allocation failed"
Return
Step 3: Set newNode's data field to data
Set newNode's next pointer to
NULL
Step 4: if head is NULL:
Set head to newNode
Return
Step 5 : temp = head
Step 6 : while temp's next pointer is not
NULL:
Move temp to temp's next node
end while
Set temp's next pointer to
newnode
Step 7: end procedure
25. Algorithm insertAtPosition(data, position):
Step 1: if position < 1:
Print "Invalid position"
Return
Step 2: if position == 1:
Call
insertAtBeginning(data
)
Return
Step 3:Allocate memory for a
new node, newNode
Step 4: if newNode is NULL:
Print "Memory
allocation failed"
Return
Set newNode's data
field to data
Step 5: temp = head
Step 6: for i from 1 to position
- 1:
Step 7: if temp is NULL:
Print "Position is
26. void insertAtPosition(int data, int position)
{
if (position < 1)
{ printf("Invalid position
n"); return;
}
if (position == 1)
{ insertAtBeginning(dat
a); return;
}
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
if (newNode == NULL)
{ printf("Memory allocation failed
n"); return;
}
newNode->data = data;
struct Node* temp = head;
for (int i = 1; i < position - 1 && temp !
= NULL; i++)
{
temp = temp->next;
}
if (temp == NULL) {
printf("Position is beyond the end of the list
n"); free(newNode);
return;
}
newNode->next = temp->next;
temp->next = newNode;
}
27. void deleteAtBeginning(struct Node* head)
{
// Check if the list is empty
if (head == NULL)
{
printf("List is already empty.n");
return NULL;
}
struct Node* temp = head;
head = head->next;
// Free the memory of the old head
free(temp);
printf("Node deleted from the beginning successfully.n");
return head;
}
deleteAtBeginning(head) :
Algorithm:
Step 1:deleteAtBeginning(head):
Step 2:if head is NULL:
Print "List is already empty."
Return NULL
Step 3: temp = head
Step 4: head = head->next
Step 5: Free memory allocated for temp
Step 6: Print "Node deleted from the
beginning
successfully."
Step 7:Return head
28. void deleteAtEnd(struct Node* head) {
if (head == NULL)
{ printf("Linked list is empty.
n"); return;
}
// If there is only one node
if (head->next == NULL) {
free(head);
return;
}
struct Node* prev = NULL;
struct Node* temp = head;
while (temp->next != NULL) {
prev = temp;
temp = temp->next;
}
// Delete the last node
free(temp);
prev->next = NULL;
}
deleteAtEnd( head)
Algorithm:
Step 1:deleteAtEnd(head):
Step 2: if head is NULL:
Print "Linked list is empty."
Return
Step 3: if head->next is NULL:
Free memory allocated for
head
Return
Step 4: prev = NULL
temp = head
Step 5:while temp->next is not
NULL:
prev = temp
temp = temp->next
Step 6:Free memory allocated for temp
Step 7: Set prev->next to NULL
Step 8: end
29. void deleteNode(struct Node* head, int position) {
if (head == NULL) // Check if the list is
empty return;
// If position is 0, then delete the head node
if (position == 0)
{
struct Node* temp = head;
head = head->next;
free(temp);
return;
}
// Find the previous node of the
node to be deleted
struct Node* temp = head;
for (int i = 0; temp != NULL && i < position - 1; i++)
temp = temp->next;
// If position is more than the number of
nodes if (temp == NULL || temp->next ==
NULL)
return
// Node temp->next is the node to be deleted
// Store a pointer to the next of the node to be
deleted
free(temp->next);
temp->next = next;
}
30. Advantages Linked lists
Dynamic Memory Allocation: Unlike arrays, linked lists do not require contiguous memory allocation. Nodes can be
dynamically allocated and linked together using pointers.
Insertion and Deletion: Linked lists excel at insertion and deletion operations, especially when performed at the
beginning or end of the list. These operations typically involve updating a few pointers, making them efficient.
Variable Size: Linked lists can dynamically grow or shrink in size as elements are added or removed, unlike fixed-size
arrays.
Traversal: Traversing a linked list involves following the pointers from one node to the next until reaching the end of
the list. This allows sequential access to the elements.
Search: While searching for an element in a linked list, one typically has to traverse the list sequentially, making linear
search less efficient compared to other data structures like binary search trees or hash tables.
Memory Overhead: Linked lists have a higher memory overhead compared to arrays due to the additional memory
required for storing pointers.
31. A doubly linked list is a type of linked list data structure where each
node contains not only a reference to the next node in the sequence but also a
reference to the previous node. In contrast, a singly linked list only contains a
reference to the next node.
Doubly Linked List
struct node
{
int data;
struct node* next;
struct node* prev;
}
struct node* head;
This is how we declare:
32. #include<stdio.h>
#include<stdlib.h
> struct node {
int data;
struct node*
next;
struct node*
prev;
};
struct node* head
= NULL; //
Initialize head to
NULL
struct node*
newnode;
void create()
{
newnode = (struct
node*)malloc(size
printf("Enter the data: ");
scanf("%d", &newnode->data);
newnode->prev = NULL;
// Initialize prev pointer to
NULL
newnode->next = NULL;
// Initialize next pointer to
NULL
if (head == NULL)
{
head = newnode;
}
else {
head->next = newnode;
newnode->prev = head;
}
}
Implementation of Double linked list:
33. Circular linked list
“A circular linked list is a variation of a linked list where the last node points back to the first node,
creating a continuous loop. Unlike a regular linked list that terminates with a null pointer, a circular
linked list has no definitive beginning or end.”
Types of Circular Linked Lists:
Circular Singly Linked List: Here, the address of the last node consists of the address of the first
node.
Circular Doubly Linked List: Here, in addition to the last node storing the address of the
first
node, the first node will also store the address of the last node.
34. Operation on circular linked list
We can perform the following operations on a circular linked list.
Insertion
Inserting at Beginning of the list.
Inserting at End of the list.
Insert at a Specific location in the list.
Deletion
Deleting from the Beginning of the
list.
Deleting from End of the list.
Deleting a Specific Node from the
list
35. Advantages of circular linked list in C
Any node of the list can act as the head as the list does not end.
Access to the first node from the last node is easy and time-saving.
Queues can be easily implemented with a circular linked list.
We can traverse the whole list from any node.
36. Linked implementations of stacks
Linked lists are a great choice for implementing stacks because they offer dynamic memory allocation.
This means the stack can grow or shrink as needed, unlike arrays which have a fixed size. Here's how a
stack can be implemented using a singly linked list
1. Define the Node Structure: You need a structure to represent each node in the linked list. This
structure will contain two parts: the data to be stored in the stack and a pointer to the next node.
struct Node
{
int data;
struct Node* next;
};
2.Initialize the Stack: You need to keep track of the top of the stack, which is simply a pointer to the top
node.
Node* top = NULL; // Initially, the stack is empty
37. 3. Implement Stack Operations:
Push Operation: To push an element onto the stack, you create a new node and make it the new top of
the
stack.
void push(int value) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = value;
newNode->next = top;
top = newNode;
}
Pop Operation: To pop an element from
the stack, you remove the top node and
return its data. Don't
forget to free the memory of the popped
node.
int pop(struct Node** top) {
if (*top == NULL) {
printf("Stack underflow!
n");
exit(1);
}
struct Node* temp = *top;
*top = (*top)->next;
int popped = temp->data;
free(temp);
return popped;
}
38. Header nodes
In a linked list, the header node (also known as the dummy node) is the first node in the list. It
serves as the entry point for accessing the rest of the nodes in the list. The header node typically contains a
reference or pointer to the first actual data node in the list.
why header nodes are useful?
Easier Access to the List: With a header node, you always have a direct pointer to the
beginning of the
list. This makes operations like insertion, deletion, or traversal much simpler.
Avoiding Empty List Checks: Since the header node always exists, you can assume the list
is never
empty, which eliminates the need for explicit checks for an empty list in many operations.
Are Header Nodes Always Used?
No, linked lists can function without header nodes. However, their absence can make
some operations trickier, especially when dealing with an empty list or finding the list's beginning.
39. Array implementation of lists.
Array: A set of data elements of same data type is called array. Array is a static data structure i.e., the
memory should be allocated in advance and the size is fixed. This will waste the memory space when used
space is less than the allocated space.
An array implementation allows the following operations.
The basic operations are:
a. Creation of a List.
b. Insertion of a data in the List
c. Deletion of a data from the List
d. Searching of a data in the list
Global Declaration:
int list[MAX_SIZE], index= -1;
Note: The initial value of index is -1.
40. Create Operation:
Procedure
The list is initially created with a set of elements.
Get the no. of elements (n) to be added in the list.
Check n is less than or equal to maximum size. If yes,
add the elements to the list.
Otherwise, give an error message
void create() {
int n, i;
printf("n Enter the number of elements to be added in the list: ");
scanf("%d", &n);
if (n <= MAX_SIZE) {
for (i = 0; i < n; i++) {
scanf("%d", &list[++index]);
}
} else {
printf("nThe size is limited. You cannot add data into the listn");
}
}
41. Insert Operation:
Procedure:
Get the data element to be inserted.
Get the position at which element is to be
inserted.
If index is less than or equal to MAX_SIZE,
then Make that position empty by altering the
position of the elements in the list.
Insert the element in the position.
Otherwise, it implies that the list is empty.
void insert() {
int i, data, pos;
printf("nEnter the data to be inserted: ");
scanf("%d", &data);
printf("nEnter the position at which element to
be inserted: ");
scanf("%d", &pos);
if (index < MAX_SIZE - 1)
{
for (i = index; i >= pos - 1; i--)
{
list[i + 1] = list[i];
}
index++;
list[pos - 1] = data;
}
else {
printf("nThe list is fulln");
}
}
42. Deletion
Procedure
Get the position of the element to be deleted.
Alter the position of the elements by performing
an assignment operation, list[i-1]=list[i], where i
value ranges from position to the last index of the
array.
void del() {
int i,
pos;
printf("
nEnter
the
position
of the
data to
be
deleted:
");
43. Display
Procedure
Formulate a loop, where i value ranges from 0 to
index (index denotes the index of the last element in
the array.
Display each element in the array.
v
o
i
d
d
i
s
p
l
a
y
(
)
44. The future belongs to those who believe in
the beauty of their dreams.
-Eleanor Roosevelt
THANK YOU