Linked List Operations and Memory Management
Linked List Operations and Memory Management
PREREQUISITES
Pointers
A pointer is a variable that stores the memory address of another variable.
At this point:
• p contains the address of a
• *p (called dereferencing) gives the value stored at that address
Memory Representation
Assume:
• a has value 10 and is stored at address 2000
• p is storing adress of a at address 4000
Then:
a = 10 → stored at 2000
p = 2000 → pointer stores address of a
*p = 10 → value at address 2000
&p = 4000 → address of pointer itself
This is why we can use a pointer to access array elements using pointer arithmetic.
Self-Referential Structure
A structure in C is a user-defined data type used to group different data types together.
Example:
struct Name {
int rollno;
int marks;
char* fullname;
};
• Here, struct Name groups different types: int, int, and char*.
struct Node {
int info;
struct Node *link;
};
• The member link is a pointer to the same structure type (struct Node). Ie link‘s data type
is type of struct node
• This allows one node to link to another node — a concept known as self-reference.
• This structure is called self-referential because it refers to itself.
Used to create dynamic data structures like: Singly Linked List, Doubly Linked List, Binary
Trees, Graphs
Static Memory Allocation
Example:
int a[100]; // or static int a[100];
int sum;
In Static Allocation:
• Size is fixed at compile time.
• Memory is allocated automatically at runtime (on stack or data segment).
🔹 Problem:
If we only need 10 elements during execution, then the remaining 90 elements' memory is
unused and wasted.
Dynamic Memory Allocation
Dynamic memory is allocated at runtime using special functions. These memory blocks are
accessed using pointers.
In Dynamic Allocation:
• Size is chosen at runtime (using user input, logic, etc.).
• Memory is allocated manually using functions like malloc(), calloc(), etc.
Example:
int *a; // Pointer to int
int n; // Variable to read size from user
Example:
If n = 4, and sizeof(int) = 4, then memory allocated = 4 × 4 = 16 bytes.
Applying to Structure:
struct node {
int info;
struct node *link;
};
Let’s say the memory allocated by malloc() starts at address 1000. Then:
• s contains 1000
• At address 1000, the structure block contains two parts:
info
link
S Info Link
2000 → 2000
🔹
Accessing Structure Members:
If using a structure variable (not pointer):
[Link];
[Link];
info link
Base Address
Example:
X
2 1000
2000
2000
HEAD
Assume:
• Base address of arr is 2000
• Each integer occupies 4 bytes
In linked list:
Each node stores:
• Data
• Address of the next node (link)
HEAD
2000
2 3000 4 4000 6 X
2000 3000 4000
• head = 2000
• Now, head and x both point to the same node
#include <stdio.h>
#include <stdlib.h>
struct node {
int info;
struct node *link;
};
int main() {
struct node *x, *y, *head = NULL;
return 0;
}
Types of Linked List
1. Singly Linked List: Each node points to the next node only. Traversal is one-way, from
head to NULL.
2. Doubly Linked List: Each node has two pointers: one to the next node and one to the
previous. Enables two-way traversal.
3. Circular Linked List: The last node points back to the first node. Can be singly or
doubly circular. No NULL at the end.
HEAD ptr
2000
2 3000 4 4000 6 X
2000 3000 4000
4. Now,
ptr->info; // gives 4 (value at 3000)
5. Repeat this until ptr becomes NULL (end of the list):
HEAD
2000
2 3000 4 4000 6 X
2000 3000 4000
while(ptr != NULL) {
printf("%d\n", ptr->info); // process current node
ptr = ptr->link; // move to next node
}
• This condition is correct for traversing all nodes, including the last node.
• The loop continues as long as the pointer ptr is not NULL.
• Last node is processed because the loop ends only after processing the node with link =
NULL.
while(ptr->link != NULL) {
printf("%d\n", ptr->info); // process current node
ptr = ptr->link; // move to next node
}
Step 5: Return
Insertion in Singly Linked List (SLL)
There are 3 possible insertion cases:
1. At the beginning
2. At the end
3. In between
You can call this function to get memory for any new node.
Example:
new = getnode(); // dynamically allocates memory for new node
1. Insertion at Beginning
HEAD
2000
2 3000 4 4000 6 X
2000 3000 4000
Step 1:
new->info = 8; //Store the value to be inserted.
8
5000
NEW
Step 2:
new->link = head;
8 2000
5000
NEW
Point the new node’s link to the current first node (which head points to).
Step 3:
head = new; //Now, update the head to point to the new node.
HEAD
5000 8 2000
5000
NEW
HEAD
5000
8 X
5000
NEW
This makes the new node both the first and last node.
HEAD
2000
2 3000 4 4000 6 X
2000 3000 4000
Idea:
• After traversal, the pointer will be at the last node
• Then, do: ptr->link = new;
Special Case:
• If the list is empty (head == NULL), simply make head = new.
Suppose we want to insert after the node with info = 4, and that node is located at base
address 2000.
HEAD
1000
2 2000 4 3000 6 X
1000 2000 3000
Steps:
1. Initialize a pointer
PTR = head → Start traversal from the beginning of the list.
2. Repeat the following until end of list or match found:
while (PTR != NULL && PTR->info != key) do
PTR = PTR->link
3. Return the result
→ If found, PTR points to the node with the key
→ If not found, PTR becomes NULL
HEAD ptr
1000
2 2000 4 3000 6 X
1000 2000 3000
8
5000
NEW
Algorithm: PART B
Input:
head: pointer to the first node
key: value after which new node should be inserted
item: value to insert
Output:
Inserts the new node with value item after the node containing `key`.
Steps:
1. PTR = Search(head, key) // Search for the node containing the key
2. If PTR == NULL
→ Display "Insertion not possible"
→ Return
3. new = getNode() // Dynamically allocate memory for the new node
4. new->info = item // Store value in the info field
5. new->link = PTR->link // Connect new node to the node after PTR
6. PTR->link = new // Link the current node to the new node
7. Return
8 3000
5000
NEW
HEAD ptr
1000
2 2000 4 3000 6 X
1000 2000 3000
finally,
HEAD
1000
6 X
3000
Deletion in Singly Linked List (SLL)
Deletion – 3 Possibilities:
1. At the beginning
2. At the end
3. A particular node (by value)
1. Deletion at Beginning
To delete the first node in a singly linked list:
• Make the head point to the second node
• Free the memory of the old first node
HEAD ptr
1000
2 2000 4 3000 6 X
1000 2000 3000
Special Cases:
1. Underflow – List is empty (head == NULL)
2. Only one node – After deletion, list becomes empty (head = NULL)
Algorithm
Input: head → pointer to the first node
Output: The value (info) of the deleted node
1. If head == NULL
→ Print "Underflow"
→ Return
After deleting,
HEAD
1000
4 3000 6 X
2000 3000
2. Deletion at End
In a singly linked list, we can’t move backwards, so to delete the last node, we must:
• Traverse the list to reach the last node
• Also keep track of the second last node (previous), since we need to update its link to
NULL
prev ptr
HEAD
1000
2 2000 4 3000 6 X
1000 2000 3000
Algorithm
Input: head → pointer to the first node
Output: Value (info) of the deleted node
1. If head == NULL
→ Print "Underflow"
→ Return
2. If head->link == NULL
→ item = head->info
→ free(head)
→ head = NULL
→ Return item
3. PTR = head
PREV = NULL
8 X
4000
• We traverse the list to find the node whose info matches the given key.
• We keep track of the previous node (PREV) because we need to change its link to skip
over the node to be deleted.
HEAD ptr
1000
2 2000 4 X
1000 2000
• If head->info == key, then the first node itself contains the key.
• In this case:
PTR = head;
head = head->link;
free(PTR);
We simply update the head to point to the second node and free the original node.
Structure of a Node:
struct node {
int info;
struct node* LLINK;
struct node* RLINK;
};
A node contains:
INFO → the data (e.g., 10)
LLINK → address of the previous node
RLINK → address of the next node
Example:
HEAD
1000
X 2 2000 1000 4 3000 2000 6 4000
1000 2000 3000
NODE
3000 8 X
4000
Node->INFO = 4;
Node->LLINK = 1000;
Node->RLINK = 3000;
This means:
NodeX stores 4 as data.
Its previous node is stored at address 1000.
Its next node is stored at address 3000.
The base address (B.A) of Node is 2000 (assumed here).
Disadvantages:
• Requires extra memory for LLINK
• Slightly more complex pointer management
• More prone to bugs if LLINK and RLINK aren't correctly maintained
HEAD
ptr
1000
3000 8 X
4000
Algorithm
Input: HEAD: pointer to the first node
Output: Visits and prints all node values in forward order
1. At the beginning
2. At the end
3. In between
1. Insertion at Beginning
HEAD
1000
3000 8 X
4000
9
5000
NEW
X 9
5000
NEW
Then:
new → RLINK = NULL → No next node either.
HEAD = new → Make new node the head.
HEAD
5000
X 2 X
5000
NEW
Step 4 (Else – List is NOT empty):
If the list already has elements:
HEAD
1000
3000 8 X
X 9 4000
5000
NEW
head → LLINK = new → Old first node now links back to new node.
new → RLINK = head → New node points to the old head.
head = new → Update head pointer to new node.
Algorithm
1. new = getnode() //Allocate memory for the new node.
3. new->llink = NULL //Since it's going to be the first node, its left link is set to NULL.
HEAD
1000
3000 8 X
4000
Steps:
4000 9 X
5000
NEW
Special Case:
If the list is empty (head == NULL):
new->RLINK = NULL
new->LLINK = NULL
head = new
HEAD
5000
X 2 X
5000
NEW
Algorithm
1. new = getnode() //Allocate memory for new node
2. new->info = ITEM //Store value
3. new->RLINK = NULL //Set right link of new node to NULL
4. If list is empty (head == NULL)
new->LLINK = NULL
head = new
Return
5. Else (list is not empty)
PTR = head
while (PTR->RLINK != NULL) //Traverse to the last node:
PTR = PTR->RLINK
(while end)
6. PTR->RLINK = new // link old last node to new
new->LLINK = PTR // link new node back to old last
7. Return
3. Insertion After a Given Element in DLL
To insert a node after a particular value (say 4): First, search for the node with info == key (e.g.,
4).
Then, insert the new node after it.
ptr
HEAD
1000
1. PTR = head
2. while (PTR != NULL && PTR->info != key)
PTR = PTR->RLINK
Part 2: Insertion
There are 3 possibilities:
- Inserting in between two nodes.
- Inserting at the end (i.e., PTR->RLINK == NULL).
- Key not present – Then exit with message: Insertion not possible.
ptr nxt
HEAD
1000
1. NXT = PTR->RLINK
4000
2000 9 3000
2. NEW->LLINK = PTR 5000
3. NEW->RLINK = NXT NEW
4. PTR->RLINK = NEW
HEAD ptr
1000
4000
1000 9 X
X 2 X 5000
NEW
1000
1. NEW->LLINK = PTR
2. NEW->RLINK = NXT (Already NXT = NULL)
3. PTR->RLINK = NEW
Algorithm: Search
1. PTR = HEAD
2. While PTR ≠ NULL && PTR->info ≠ key do
PTR = PTR->RLINK
3. Return PTR
Algorithm: Insertion
1. PTR = Search(key)
2. If PTR == NULL then
Display "Key not present"
Return
3. new = getnode()
4. new->INFO = ITEM
5. nxt = PTR->RLINK (3 steps are common)
6. new->LLINK = PTR
7. new->RLINK = nxt
8. PTR->RLINK = new
9. If nxt ≠ NULL then (If nxt ≠ NULL then only need to do this)
nxt->LLINK = new
10. Return
Deletion in DLL
There are 3 possible cases:
• At the beginning
• At the end
• In between
1000
Main Steps:
1. Check for Underflow – if list is empty (head is NULL), deletion not possible.
2. Check for Single Node – if only one node exists, make head NULL after storing info.
3. General Case (2 or more nodes) – update head, adjust LLINK, and free the deleted node.
Algorithm
1. If head == NULL then
Display "Underflow"
Return
2. PTR = head
4. Temp = PTR->INFO
5. head = PTR->RLINK
6. head->LLINK = NULL
7. Free(PTR)
8. Return Temp
2. Deletion of Last Node
List with 2 or More Nodes
prev
ptr
HEAD
1000
Special Case: If List Has Only One Node (head → RLINK == NULL)
- Save the INFO to a temporary variable
- Set head = NULL
- Free the only node using free(PTR)
- Return the deleted value
Algorithm
1. If HEAD == NULL then
1.1 Display "Underflow"
1.2 Return
2. PTR = HEAD
HEAD ptr
1000
ptr
HEAD
1000
HEAD ptr
2000
X 4 X
2000
ptr
HEAD
1000
1000
1000
Else
1. If (HEAD == NULL)
Print "Underflow" & Exit
2. PTR = HEAD
4. If (PTR == NULL)
Print "Key not present" & Exit
5. If (PTR → LLINK == NULL AND PTR → RLINK == NULL) // only one node
HEAD = NULL
Free(PTR)
Exit
8. Else
PREV = PTR → LLINK
NEXT = PTR → RLINK
PREV → RLINK = NEXT
NEXT → LLINK = PREV
Free(PTR)
9. Exit
CIRCULAR LINKED LIST
In a circular linked list, the last node doesn’t point to NULL — instead, it points back to the
head node, forming a circle.
HEAD
2000
2 3000 4 4000 6 X
2000 3000 4000
In a regular singly linked list, traversal stops at NULL. But here, we must stop when we loop
back to the head, i.e., PTR → LINK == head.
• Traversal
• Insertion
• Deletion
Traversal Of CLL
HEAD
2000
1. If (head == NULL)
Display "Empty" and Return
2. PTR = head
5. Return
Insertion in CLL
There are 3 possible insertion cases:
1. At the beginning
2. At the end
3. In between
1. Insertion at Beginning
HEAD
2000
Algorithm
1. Create a node new.
2. Set new → data = item .
3. If head = NULL (empty list):
1. head = new
2. new → link = new (self-loop since only one node)
4. Else (non-empty list):
1. Set ptr = head.
2. While ptr → link != head do
1. ptr = ptr → link (move to last node).
3. Set new → link = head.
4. Update head = new.
5. Set ptr → link = head (last node points to new head).
1. Insertion at End
HEAD
2000
Algorithm
1. Create a node new.
2. Set new→data = x.
3. If head = NULL (empty list):
1. new→link = new (self-loop).
2. head = new.
4. Else (non-empty list):
1. Set ptr = head.
2. While ptr→link != head do
1. ptr = ptr→link (move to last node).
3. ptr→link = new.
4. new→link = head.
1. Insertion After Specific Node
HEAD
2000
Algorithm
1. If head = NULL (empty list):
Print "List is empty. Insertion not possible."
Return.
2. Else:
Set ptr = head.
While ptr→data != key do //Traverse list to find key
ptr = ptr→link
4. If ptr→data == key:
Create a node new.
new→data = x.
new→link = ptr→link.
ptr→link = new.
5. Else:
Print "Search data not found. Insertion not possible."
Deletion in DLL
There are 3 possible cases:
• At the beginning
• At the end
• In between
1. Deletion From Beginning
HEAD
2000
Algorithm
1. If head = NULL then
Print "List is Empty. Deletion is not possible"
3. Else
ptr = head
While ptr→link != head do
ptr = ptr→link
temp = head
head = head→link
ptr→link = head
free(temp)
1. Deletion From End
HEAD
2000
Algorithm
1. If head = NULL then
Print "List is Empty. Deletion is not possible"
3. Else
prev = head
curr = head→link
While curr→link != head do
prev = curr
curr = curr→link
prev→link = head
free(curr)
1. Deletion After Specific Node
HEAD
2000
Algorithm
1. If head = NULL then
Print "List is Empty. Deletion is not possible"
4. Else
1. prev = head
2. curr = head→link
3. While curr→link != head and curr→data != key do
prev = curr
curr = curr→link
4. If curr→data == key then
prev→link = curr→link
free(curr)
5. Else
Print "Search data not found."
STACK USING LINKED LIST
HEAD / TOP
2000
2 3000 4 4000 6 X
2000 3000 4000
A stack is a linear data structure that follows the LIFO (Last In, First Out) principle.
• Insertion (PUSH) and Deletion (POP) are performed at the same end, called TOP.
• Using a linked list for implementing a stack allows dynamic memory allocation, unlike
arrays which require fixed memory size.
Representation
Each node contains:
Data (info) – the element stored.
Link (next pointer) – points to the next node.
• The TOP pointer always points to the most recently inserted node.
• When the stack is empty, TOP = NULL.
Unlike arrays, queues implemented with linked lists use dynamic memory allocation, so they
can grow/shrink as needed.
Representation
Each node contains:
Data (info) – the element stored.
Link (next pointer) – points to the next node.
HED / FRONT
2000
2 3000 4 4000 6 X
2000 3000 4000
REAR
4000
Structure of Node
Each node in the polynomial linked list contains three fields:
• Coefficient (Coeff) → stores the coefficient of the term.
• Exponent (Expo) → stores the exponent of the variable.
• Link → pointer to the next node.
HEAD
1000
4 3 2000 3 2 3000 2 0 X
1000 2000 3000
POLYNOMIAL ADDITION
Consider Example:
P : 6X3 + 3X + 6
Q : 4X4 + 2X
Basic Working:
Polynomial P:
P
P HEAD
1000
6 3 2000 3 1 3000 6 0 X
1000 2000 3000
Polynomial Q:
Q
Q HEAD
1000
4 4 2000 2 1 X
1000 2000
Algorithm
1. Initialize pointers:
P = Phead (first polynomial)
Q = Qhead (second polynomial)
Rhead = NULL (head of result polynomial)
(1x²) × Q
(1x²)(4x⁴) = 4x⁶
(1x²)(3x³) = 3x⁵
(1x²)(3x²) = 3x⁴
For x 7: 8x⁷
For x 6: 6 x 6 +4 x 6 =10 x 6
For x 5: 6 x 5 +3 x 5 =9 x 5
For x 4: 3x⁴
1000
2 3 2000 1 2 X
1000 2000
Q
P HEAD
1000
4 4 2000 3 3 3000 3 2 X
1000 2000 3000
2. While P ≠ NULL do
2. While Q ≠ NULL do
Create a new node new.
new→Coeff = P→Coeff × Q→Coeff // Multiply coefficients
new→Expo = P→Expo + Q→Expo // Add exponents
new→Link = NULL.
Insert into result list:
If Rhead == NULL → Rhead = R = new
Else → R→Link = new, R = new
Q = Q→Link // Move to next term in Q
3. P = P→Link // Move to next term in P
1. Set P = Rhead.
2. While P ≠ NULL do
prev = P
Q = P→Link
While Q ≠ NULL do
If P→Expo == Q→Expo then
P→Coeff = P→Coeff + Q→Coeff (combine terms)
prev→Link = Q→Link (unlink duplicate)
Free(Q)
Q = prev→Link
Else (if exponent are not same)
prev = Q
Q = Q→Link
Move P to next: P = P→Link.
• Since multiple processes compete for memory, the Operating System decides which part
of memory each process should occupy.
• Linked Lists are often used to represent free blocks and allocated blocks of memory.
Memory Allocation is an Application of Linked List.
When a process requests memory, the OS searches the Avail List and allocates a suitable block
based on an allocation scheme.
Example
Suppose three processes arrive:
- P1 needs 75 KB
- P2 needs 180 KB
- P3 needs 440 KB
The OS must decide where in memory to place these processes from the available free blocks.
This decision is made using allocation schemes.
1. First Fit
2. Best Fit
3. Worst Fit
First Fit
The process is allocated to the first free block that is large enough.
Example:
Free Memory:
Free blocks = 100 KB, 200 KB, 350 KB, 400 KB, then allocating of P1 (180 KB):
Advantages:
• Simple to implement.
• Faster than Best Fit and Worst Fit (search stops at first match).
• Reduces allocation time.
Disadvantages:
• Leads to external fragmentation (many small unusable holes near the beginning).
Example:
After P1 allocation → leftover = 20 KB. Next process P2 = 90 KB → goes in 100 KB block,
leaving 10 KB.
Now memory looks like: 10 KB, 20 KB, 350 KB, 400 KB.
Free Memory:
Advantages:
• Leaves larger free blocks available for bigger processes.
• Reduces large wastage of memory.
Disadvantages:
• Searching for the best fit takes more time (slow).
• Creates many small unusable fragments (external fragmentation).
Example:
P1 (180 KB) goes into 200 KB block → leftover = 20 KB. Over time → memory has lots of tiny
useless gaps.
Worst Fit
The process is allocated to the largest free block available.
Example:
Free Memory:
Advantages:
• Leaves medium and small blocks free for other processes.
• Reduces small fragmentation.
• May be useful if mostly small processes arrive.
Disadvantages:
• Wastes large memory blocks.
• A future large process may not fit.
Example:
After P1 allocation, If P2 = 370 KB arrives → cannot be allocated, even though total free memory
= 870 KB.
Comparison
Feature First Fit Best Fit Worst Fit
Allocates the first free Allocates the smallest
Allocates the largest
Definition block that is large free block that is large
free block available.
enough. enough.
Reduce wasted space Leave big blocks free for
Aim Fast allocation
(minimize leftover space) future processes
Sequential from Searches entire memory Searches entire memory
Search Method
beginning of memory list list
Fast (simple scan, stop Slow (must check all Slow (must check all
Speed
early) blocks) blocks)
Space Efficient, but may cause Poor, since it may leave
Moderate
Utilization many small fragments unusable small blocks
High external
External fragmentation External fragmentation,
Fragmentation fragmentation (many small
occurs large holes split
holes)
Free blocks: 100KB,
Same free blocks Same free blocks
300KB, 200KB
Request: 120KB → Request: 120KB →
Example Request: 120KB →
Allocated to 200KB Allocated to 300KB
Allocated to 300KB (first
(smallest suitable) (largest block)
fit found)
Fast and simple to Keeps large blocks
Advantages Efficient use of space
implement available
Time-consuming search, Poor space utilization,
May waste large blocks
Disadvantages leads to many small wastes large memory
early
unusable blocks blocks
→ If Worst Fit ties with another scheme: it is rarely preferred, since it usually causes poor
utilization.
Exam Tip:
Write First Fit = faster, Best Fit = efficient, Worst Fit = least preferred.
• If asked which to choose when both First Fit and Best Fit allocate the same → say: “Best
Fit is better in terms of memory utilization, but First Fit is faster in practice.”
MEMORY ALLOCATION ALGORITHMS
1. First Fit Algorithm
1. Mark all memory blocks as free.
2. For each process:
1. Start from the first free block.
2. If Process Size ≤ Block Size:
- Allocate the block to the process.
- Move to the next process.
3. Else:
- Continue checking the next free blocks.
Solution:
Allocated: 4/5
Free after: 52, 77, 1 (total 130)
Allocated: 4/5
Free after: 52, 77, 1 (total 130)
Worst Fit (choose the largest adequate block)
Allocated: 5/5
Free after: 2, 27, 1 (total 30)
Worst Fit is best for this case because it successfully allocates all 5 processes, while First
Fit and Best Fit both fail on the last 100 KB request.
SOME TO WORKOUT
1. Given five memory partitions of 300Kb, 700Kb, 400Kb, 500Kb, 800Kb (in order), how
would the first-fit, best-fit, and worst-fit algorithms place processes of 412Kb, 617 Kb, 112
Kb, and 626Kb (in order)? (6 MARKS, Ans: Best-Fit)
2. Given five memory partitions of 400Kb, 600Kb, 350Kb, 200Kb, 800Kb (in order), how
would the first-fit, best-fit, and worst-fit algorithms place processes of 520 Kb, 617 Kb, 200
Kb, and 750 Kb (in order)? (6 MARKS, Ans: Best-Fit – based on memory utilization)
MEMORY DEALLOCATION – COMPACTION
Compaction is a memory management technique used to collect scattered free memory
fragments into one large contiguous block, thereby removing external fragmentation.
Example
Suppose we have Main Memory = 1000 KB. Allocated processes and free spaces look like this:
Before Compaction:
Block Size (KB) Status
P1 200 Occupied
Hole 100 Free
P2 300 Occupied
Hole 50 Free
P3 250 Occupied
Hole 100 Free
But it is scattered → no process requiring >100 KB can be loaded. So, a process P4 of 200 KB
cannot be allocated.
After Compaction:
We shift all occupied processes upwards and collect free space at the end:
Advantages
• Removes external fragmentation.
• Efficient memory usage.
• Supports loading of large processes.
Disadvantages
• Time-consuming.
• CPU remains idle during compaction.
• Not always possible in real systems.
Garbage Collection
Garbage Collection (GC) is the process of automatically or manually reclaiming memory that is
no longer in use by the program so it can be reused.
Why Needed
• Prevent memory leaks (unused memory still occupied).
• Avoid dangling pointers and undefined behavior.
• Improve memory utilization and program reliability.
Techniques
Technique Description
Mark & Sweep Marks reachable objects and frees unmarked memory.
Reference Counting Keeps a count of references; frees memory when count is zero.
Copying Copies live objects to another space, leaving garbage behind.
All other Algorithms are equally important, Please try to study all. It is worth to study DSA !