1. DATA STRUCTURE
Unit 3: Linked Lists and Trees ( 8 L)
• Linked Lists:
• Introduction to Dynamic Memory Allocation,
• Representation and Implementation of Single, Double, and Circular Linked Lists
• Operations on Linked List: Insert, Delete, Traverse etc.
• Applications of Linked List,
• Linked List representation of Stack and Queue.
• Trees:
• Basic Tree terminologies,
• Types of Trees:
• Binary Tree, Binary Search Tree (BST), AVL Tree, B-Tree, and Heap.
• Representation and Implementations of different types of trees,
• Tree Traversal algorithms,
• Operation on trees: Insert, Delete, etc., Applications of Tress.
2. Dynamic Memory Allocation
Since C is a structured language, it has some fixed rules for programming. One of it includes changing the size of an
array. An array is collection of items stored at continuous memory locations.
This procedure is referred to as Dynamic Memory Allocation in C.
Therefore, C Dynamic Memory Allocation can be defined as a procedure in which the size of a data structure (like
Array) is changed during the runtime.
There are 4 library functions provided by C defined under <stdlib.h> header file to facilitate dynamic memory
allocation in C programming. They are:
malloc(), calloc(), free(), realloc()
3. Dynamic Memory Allocation
malloc() method:
“malloc” or “memory allocation” method in C is used to dynamically allocate a single large block of memory with the
specified size. It returns a pointer of type void which can be cast into a pointer of any form. If space is insufficient,
allocation fails and returns a NULL pointer. It initializes each block with default garbage value.
Syntax: ptr = (cast-type*) malloc(byte-size)
For Example: ptr = (int*) malloc(100 * sizeof(int));
Let the size of int is 4 bytes. And, the pointer ptr holds the address of the first byte in the allocated memory.
4. Dynamic Memory Allocation
calloc() method:
“calloc” or “contiguous allocation” method in C is used to dynamically allocate the specified number of blocks of
memory of the specified type. It initializes each block with a default value ‘0’.
Syntax: ptr = (cast-type*)calloc(n, element-size);
For Example: ptr = (float*) calloc(25, sizeof(float));
Let the size of int is 4 bytes. And, the pointer ptr holds the address of the first byte in the allocated memory.
5. Dynamic Memory Allocation
re-alloc() method:
It is used to dynamically change the memory allocation of a previously allocated memory. re-allocation of memory
maintains the already present value and new blocks will be initialized with default garbage value..
Syntax: ptr = realloc(ptr, newSize);
6. Dynamic Memory Allocation
free() method:
“free” method in C is used to dynamically de-allocate the memory. The memory allocated using functions malloc() and
calloc() is not de-allocated on their own. Hence the free() method is used, whenever the dynamic memory allocation
takes place. It helps to reduce wastage of memory by freeing it.
Syntax: free(ptr);
7. Linked List
Linked List can be defined as collection of nodes that are randomly stored in the memory.
A node contains two fields i.e.
data stored at that particular address, and
the pointer which contains the address of the next node in the memory.
The last node of the list contains pointer to the null.
Why use linked list over array?
It allocates the memory dynamically. All the nodes of linked list are non-contiguously stored in the memory and linked
together with the help of pointers.
Sizing is no longer a problem since we do not need to define its size at the time of declaration. List grows as per the
program's demand and limited to the available memory space.
Creation of node of linked list:
/ A linked list node
struct Node
{
int data;
struct Node *next;
};
8. Linked List
Insertion in linked list can be done in three ways:
At the front of the linked list
After a given node.
At the end of the linked list.
9. Linked List
• Add a node at the front: (4 steps process)
• Time complexity = O(1).
Node* ins_first(Node* head, int item){
Node *new_node;
new_node=(Node*)malloc(sizeof(Node));
if(new_node==NULL){
printf("unable to allocate memory");
exit(0);
}
else{
new_node->data=item;
new_node->next=NULL;
new_node->next=head;
head=new_node;
}
return head;
}
10. Linked List
• Add a node after a given node: (5 steps process) ) Node *ins_after(Node *head, int item, int key){
Node *new_node,*tmp;
new_node=(Node*)malloc(sizeof(Node));
if(new_node==NULL){
printf("unable to allocate");
exit(0);
}
else{
new_node->data=item;
new_node->next=NULL;
tmp=head;
while(tmp->data!=key){
tmp=tmp->next;
}
new_node->next=tmp->next;
tmp->next=new_node;
}
return head;
}
• Time complexity = O(1).
11. Linked List
• Add a node at the end: (6 steps process)
Node* ins_last(Node* head,int item){
Node *new_node,*tmp;
new_node=(Node*)malloc(sizeof(Node));
if(new_node==NULL){
printf("unable to allocate");
exit(0);
}
else{
new_node->data=item;
new_node->next=NULL;
tmp=head;
while(tmp->next!=NULL){
tmp=tmp->next;
}
tmp->next=new_node;
}
return head;
}
• Time complexity = O(n).
12. Linked List
Deletion in linked list can be done in three ways:
at the beginning of the linked list
at the end
13. Linked List
at the beginning of the linked list Node* del_first(Node *head){
Node *ptr;
if(head==NULL){
printf("n underflow cnt delete");
}
else{
ptr=head;
head=ptr->next;
printf("ndeleted elemnet is->%d",ptr->data);
free(ptr);
}
return head;
}
14. Linked List
at the end of the linked list
Node* del_last(Node *head){
Node *ptr,*ptr1;
if(head==NULL){
printf("n underflow cnt delete");
}
else{
ptr1=head;
while(ptr1->next->next!=NULL){
ptr1=ptr1->next;
}
ptr=ptr1->next;
ptr1->next=NULL;
printf("ndeleted elemnet is->%d",ptr->data);
free(ptr);
}
return head;
}
15. Doubly Linked List
A Doubly Linked List (DLL) contains an extra pointer, typically called previous pointer, together with next pointer and data
which are there in singly linked list.
/* Node of a doubly linked list */
struct Node {
int data;
struct Node* next; // Pointer to next node in DLL
struct Node* prev; // Pointer to previous node in DLL
};
16. Doubly Linked List
Advantages over singly linked list
A DLL can be traversed in both forward and backward direction.
The delete operation in DLL is more efficient if pointer to the node to be deleted is given.
We can quickly insert a new node before a given node.
In singly linked list, to delete a node, pointer to the previous node is needed. To get this previous node, sometimes the
list is traversed. In DLL, we can get the previous node using previous pointer.
Disadvantages over singly linked list
Every node of DLL Require extra space for an previous pointer. It is possible to implement DLL with single pointer
though (See this and this).
All operations require an extra pointer previous to be maintained. For example, in insertion, we need to modify previous
pointers together with next pointers. For example in following functions for insertions at different positions, we need 1
or 2 extra steps to set previous pointer.
17. Insertion in DLL
Insertion in linked list can be done in three ways:
At the front of the DLL
After a given node.
At the end of the DLL
18. Insertion in DLL
• Add a node at the front: (A 5 steps process)
Node* ins_first(Node* head, int item){
Node *new_node;
new_node=(Node*)malloc(sizeof(Node));
if(new_node==NULL){
printf("unable to allocate");
exit(0);
}
else{
new_node->data=item;
new_node->next=NULL;
new_node->prev=NULL;
new_node->next=head;
head=new_node;
}
return head;
}
19. Insertion in DLL
• Add a node after a given node : Node *ins_after(Node *head, int item, int key){
Node *new_node,*tmp;
new_node=(Node*)malloc(sizeof(Node));
if(new_node==NULL){
printf("unable to allocate memory");
exit(0);
}
else{
new_node->data=item;
new_node->next=NULL;
new_node->prev=NULL;
tmp=head;
while(tmp->data!=key){
tmp=tmp->next;
}
new_node->next=tmp->next;
tmp->next->prev=new_node;
tmp->next=new_node;
new_node->prev=tmp;
}
return head;
}
20. Insertion in DLL
• Add a node at the end:
Node* ins_last(Node* head,int item){
Node *new_node,*tmp;
new_node=(Node*)malloc(sizeof(Node));
if(new_node==NULL){
printf("unable to allocate memory");
exit(0);
}
else{
new_node->data=item;
new_node->next=NULL;
new_node->prev=NULL;
tmp=head;
while(tmp->next!=NULL){
tmp=tmp->next;
}
tmp->next=new_node;
new_node->prev=tmp;
}
return head;
}
21. Insertion in DLL
• Add a node before a given node:
Node *ins_before(Node *head, int item, int key){
Node *new_node,*tmp;
new_node=(Node*)malloc(sizeof(Node));
if(new_node==NULL){
printf("unable to allocate");
exit(0);
}
else{
new_node->data=item;
new_node->next=NULL;
new_node->prev=NULL;
tmp=head;
while(tmp->data!=key){
tmp=tmp->next;
}
new_node->next=tmp;
tmp->prev->next=new_node;
new_node->prev=tmp->prev;
tmp->prev=new_node;
}
return head;
22. Deletion in DLL
The deletion of a node in a doubly linked list can be divided into three main categories:
Deletion at beginning
After the specified node
At the end
23. Deletion in DLL
• Deletion at beginning:
• Deletion in doubly linked list at the beginning is the simplest operation. We just need to copy the head pointer to pointer ptr
and shift the head pointer to its next.
Algorithm
•STEP 1: IF HEAD = NULL
WRITE UNDERFLOW
GOTO STEP 6
STEP 2: SET PTR = HEAD
•STEP 3: SET HEAD = HEAD → NEXT
•STEP 4: SET HEAD → PREV = NULL
•STEP 5: FREE PTR
•STEP 6: EXIT
24. Deletion in DLL
• After the specified node:
• In order to delete the node after the specified data
•Step 1: IF HEAD = NULL
Write UNDERFLOW
Go to Step 9
[END OF IF]
•Step 2: SET TEMP = HEAD
•Step 3: Repeat Step 4 while TEMP -> DATA != ITEM
•Step 4: SET TEMP = TEMP -> NEXT
[END OF LOOP]
•Step 5: SET PTR = TEMP -> NEXT
•Step 6: SET TEMP -> NEXT = PTR -> NEXT
•Step 7: SET PTR -> NEXT -> PREV = TEMP
•Step 8: FREE PTR
•Step 9: EXIT
25. Deletion in DLL
• At the End:
Step 1: IF HEAD = NULL
Write UNDERFLOW
Go to Step 7
[END OF IF]
Step 2: SET TEMP = HEAD
Step 3: REPEAT STEP 4 WHILE TEMP->NEXT != NULL
Step 4: SET TEMP = TEMP->NEXT
[END OF LOOP]
Step 5: SET TEMP ->PREV-> NEXT = NULL
Step 6: FREE TEMP
Step 7: EXIT
26. Deletion in DLL
• At the End:
Step 1: IF HEAD = NULL
Write UNDERFLOW
Go to Step 7
[END OF IF]
Step 2: SET TEMP = HEAD
Step 3: REPEAT STEP 4 WHILE TEMP->NEXT != NULL
Step 4: SET TEMP = TEMP->NEXT
[END OF LOOP]
Step 5: SET TEMP ->PREV-> NEXT = NULL
Step 6: FREE TEMP
Step 7: EXIT
27. Circular Linked List
Circular linked list is a linked list where all nodes are connected to form a circle. There is no NULL at the end. A circular
linked list can be a singly circular linked list or doubly circular linked list.
28. Circular Linked List
Advantages of Circular Linked Lists:
Can traverse the whole list by heading from any point. We just need to stop when the first visited node is visited again.
Circular lists are useful in applications to repeatedly go around the list.
For example, when multiple applications are running on a PC, it is common for the operating system to put the
running applications on a list and then to cycle through them, giving each of them a slice of time to execute, and
then making them wait while the CPU is given to another application. It is convenient for the operating system to
use a circular list so that when it reaches the end of the list it can cycle around to the front of the list.
Circular Doubly Linked Lists are used for implementation of advanced data structures like Fibonacci Heap.
29. Circular Linked List
Implementation:
To implement a circular singly linked list, we take an external pointer that points to the last node of the list. If we have a
pointer last pointing to the last node, then last -> next will point to the first node.
Why have we taken a pointer that points to the last node instead of first node ?
For insertion of node in the beginning we need traverse the whole list.
Also, for insertion at the end, the whole list has to be traversed.
If instead of head pointer we take a pointer to the last node then in both the cases there won’t be any need to traverse
the whole list. So insertion in the beginning or at the end takes constant time irrespective of the length of the list.
30. Insertion in CLL
A node can be added in three ways:
Insertion in an empty list
Insertion at the beginning of the list
Insertion at the end of the list
31. Insertion in CLL
struct Node *addToEmpty(struct Node *last, int data)
{
// This function is only for empty list
if (last != NULL)
return last;
// Creating a node dynamically.
struct Node *temp =
(struct Node*)malloc(sizeof(struct Node));
// Assigning the data.
temp -> data = data;
last = temp;
// Note : list was empty. We link single node to itself.
temp -> next = last;
return last;
}
32. Insertion in CLL
Insertion at the beginning of the list
1. Create a node, say T.
2. Make T -> next = last -> next.
3. last -> next = T.
struct Node *addBegin(struct Node *last, int data)
{
if (last == NULL)
return addToEmpty(last, data);
// Creating a node dynamically.
struct Node *temp = (struct Node *)malloc(sizeof(struct Node));
// Assigning the data.
temp -> data = data;
// Adjusting the links.
temp -> next = last -> next;
last -> next = temp;
return last;
}
33. Insertion in CLL
struct Node *addEnd(struct Node *last, int data)
{
if (last == NULL)
return addToEmpty(last, data);
// Creating a node dynamically.
struct Node *temp = (struct Node *)malloc(sizeof(struct Node));
// Assigning the data.
temp -> data = data;
// Adjusting the links.
temp -> next = last -> next;
last -> next = temp;
last = temp;
return last;
}
Insertion at the end of the list
34. Deletion in CLL
A node can be deleted in three ways:
First position.
Last Position
Particular node(same as singly linked list)
35. Deletion in CLL
Deletion at the beginning of the list
Step 1: IF HEAD = NULL
Write UNDERFLOW
Go to Step 8
[END OF IF]
Step 2: SET PTR = HEAD
Step 3: Repeat Step 4 while PTR → NEXT !=
HEAD
Step 4: SET PTR = PTR → NEXT
[END OF LOOP]
Step 5: SET PTR → NEXT = HEAD → NEXT
Step 6: FREE HEAD
Step 7: SET HEAD = PTR → NEXT
Step 8: EXIT
36. Deletion in CLL
Deletion in last
Step 1: IF HEAD = NULL
Write UNDERFLOW
Go to Step 8
[END OF IF]
Step 2: SET PTR = HEAD
Step 3: Repeat Steps 4 and 5 while PTR -> NEXT != HEAD
Step 4: SET PREPTR = PTR
Step 5: SET PTR = PTR -> NEXT
[END OF LOOP]
Step 6: SET PREPTR -> NEXT = HEAD
Step 7: FREE PTR
Step 8: EXIT