Unit 4
Unit 4
Topics to be covered
Linked Lists: Introduction to Linked lists
Representation of linked list
Operations on linked list
Comparison of Linked Lists with Arrays and Dynamic Arrays
Types of Linked Lists and operations-Circular Single Linked
List, Double Linked List, Circular Double Linked List
Skip List-Definition and uses
In array(or lists) are simple data structures used to hold sequence of data.
int a[ ]= {50,42,85,71,99};
An element in a linked list is known as a node. A node contains a data part and one
or two pointer part which contains the address of the neighborhood nodes in the list.
Node structure-
Types of linked list
Depending on the pointers are maintained by node and accordingly linked list
can be classified into three groups
1. Singly linked lists
2. Circular linked lists
3. Doubly linked lists
4. Circular doubly linked list
1. Singly linked list
in singly linked list, each node has two parts one is data part and other is address
part.
- data part stores the data values.
- address part contains the address of its next node.
Linked List
Structure of singly linked list
2000
Header
The head or header always points to the first node in the list.
10 NULL
Creating a node
1000
2000 10 1500 20 2050 30
1000 1500 2050
2
1
5 1000
2000
Insert new node at end of the linked list
Algorithm
Step1- create a new node
Step2- ptr=header
Step3- while(ptr.link!=None)
3.1. ptr=ptr.link
Step4- ptr.link=new
Step5- new.data=item
Step6- new.link=None
Step7-stop
Insert new node at end of the linked list
header ptr
2400 2450
2300 10 20 30 2500
2300 2400 2450
1 New
Algorithm
Step1- create a new node
40
Step2- ptr=header
Step3- while(ptr.link!=None)
2500
3.1. ptr=ptr.link
Step4- ptr.link=new
Step5- newnode.data=item
Step6- newnode.link=null
Step7-stop
Insert new node at any position in linked list
Algorithm
1.Create new node
2. ptr=header
3. Enter the position
4. for(i=1;i<pos-1;i++)
4.1 ptr=ptr.ink;
5. newnode.ink=ptr.link;
6. ptr->link=new; Inserted position is : 3
7. new->data=item
2000 ptr
8.stop
Header
10 2500 20 1000
2600 30 2367 40 NULL
2000 2500 2600 2367
5 2600
New node
1000
Deletion of a node from singly linked list
1500
1800 1500
if (header = = None)
else
{
ptr = header;
header = header.link;
free(ptr);
}
header
Deleting a node at the end
ptr1 ptr1 ptr1
1500
1400
1500 1800 1200
ptr
1800
1200
1400
1500
ptr = header;
while(ptr.link != None)
{
ptr1=ptr;
ptr = ptr.link;
}
Ptr1.link = None;
free(ptr);
Deleting a node at the given position
ptr1
ptr
header
1200
1500 1500
1800 Delete position : 3
10 1800 20 1400
1200 30 1400 40 NULL
1400
1500 1800 1200
ptr = header ;
for(i=1;i<pos-1;i++)
ptr = ptr.link;
ptr1 = ptr.link;
ptr.link = ptr1.link;
free(ptr1);
Traversing an elements of a list
header ptr
1500
1500
if(header = = None)
else
for (ptr = header ; ptr != None ; ptr = ptr.link)
Reverse of a linked list
header
1500
Else:
ptr=header
before=after=None
while(ptr!=None):
after=ptr.next
ptr.next=before
before=ptr
ptr=after
header=before
SLL program
#include<stdio.h>
#include<malloc.h>
void search();
void traverse();
void deletion();
void insertion();
int choice,i,pos,item;
struct node
{
int data;
struct node *link;
}*header,*ptr,*ptr1,*new;
int main(){
SLL program
header=NULL;
printf("****Menu****\n");
printf("\n1.insertion\n 2.deletion\n 3.traverse \n4.search
\n5.exit\n");
while(1)
{
printf("\nenter ur choice");
scanf("%d",&choice);
switch(choice){
case 1: insertion();
break;
case 2: deletion();
break;
case 3: traverse();
break;
case 4:search();
break;
case 5:exit(0);
default:printf("\nwrong choice\n");
}//switch}//while}//main
if(choice==1){
new->link=header;
header=new;
}//if
//insertion function if(choice==2)
void insertion() {
{ ptr=header;
new=malloc(sizeof(struct node)); printf("enter the position to place
printf("\n enter the item to be inserted\n"); item\n");
scanf("%d",&item); scanf("%d",&pos);
new->data=item; for(i=0;i<pos-1;i++)
if(header==NULL) ptr=ptr->link;
{ new->link=ptr->link;
new->link=NULL; ptr->link=new;
header=new; }//if
}//if if(choice==3)
else {
{ ptr=header;
printf("\nenter the place to insert the item\n"); while(ptr->link!=NULL)
printf("1.start\n 2.middle\n 3. end\n"); ptr=ptr->link;
scanf("%d",&choice); new->link=NULL;
ptr->link=new;
}//if}//else}//insertion
if(choice==2){
printf("\n enter the position to delete
//deletion function the element from the list");
void deletion() scanf("%d",&pos);
{ for(i=0;i<pos-1;i++)
ptr=header; {ptr1=ptr;
if(header==NULL) ptr=ptr->link;
{ }
printf("\nthe list is empty"); printf("\n the deleted element is -
} >%d",ptr->data);
else ptr1->link=ptr->link;
{ }//if
printf("\n1.start \n2.middle \n3.end"); if(choice==3){
printf("\n enter the place to delete the while(ptr->link!=NULL){
element from list"); ptr1=ptr;
scanf("%d",&choice); ptr=ptr->link;
if(choice==1) }//while
{ printf("\nthe deleted element from the
printf("\nthe deleted item from the list list is ->%d", ptr->data);
is -> %d",ptr->data); ptr1->link=NULL;
header=header->link; }}}
}//if
void search()
{
int loc=0; //traverse function
ptr=header; void traverse()
printf("\n enter the element to {
be searched in the list"); if(header==NULL)
scanf("%d",&item); printf("list is empty\n");
while((ptr->data!=item)&&(ptr- else
>link!=NULL)) {
{ printf("\n the elements in the list are");
ptr=ptr->link; for(ptr=header;ptr!=NULL;ptr=ptr->link)
loc++; ->data);
} }//else
If((ptr->link==NULL)&&(ptr- }//traverse
>data!=item))
\
else
printf("\n the element found
at location %d",loc);
}//search()
Comparison of linked list and array
Linked list and arrays are used to store collection of data. Both
purpose is same but differ in their usage.
Arrays:
- 1. to access an array element, the address of an element
computed by using base address and multiply position with
element size then added to base address. Hence, it takes
constant time to access an array element.
- 2. the size of the array is fixed
- 3. random access is possible.
- 4. inserting new element is expensive as it takes shifting
operation.
- 5. takes less space to store elements
- 6. memory allocated during compile time.
- 7. wastage of memory is more.
Linked list
Accessing linked list elements are slower as it takes time proportional
to i to find the i-th member of a linked list by skipping over the
first i
Dynamic size.
Insertion and deletion operations are easy.
No possibility of random accessing.
Extra space is required as it points to the next element.
Memory allocated during run time.
No wastage of memory
Dynamic arrays
Dynamic array is also called as resizable array, growable array
, mutable array or arraylist.
Dynamic array is a random access and variable size list data
structure and enables to add or remove elements.
The size of the array grows up automatically when we try to
insert new element when there is no space. Array size will be
doubled.
Dynamic array starts with predefined size and as soon as array
become full, array size would get doubled of the original size.
Similarly array size reduced to half when elements in the array
are less then the half.
Dynamic array
Comparision of linked list with arrays and dynamic arrays
A variable, top, holds the address of the first cell in the list.
50 1500 1100
40 1800 1500
30 1200 1800
20 1400 1200
A doubly linked list is a two-way list because one can move in either
direction. That is, either from left to right or from right to left.
Deletion at front
Deletion at any position
Deletion at end
Insertion of a node at the front
else:
if(header==None):
newnode.next=ptr;
ptr.prev=new;
newnode.prev=None;
newnode.prev=NULL;
newnode.next=None;
header=newnode;
header=newnode;
}
header
header
1050 ptr
header 2020
ptr ptr
1010
2020 50 1000
2200 new
header Before deleting a node at beginning
1010
Algorithm:
1.ptr=header
2.ptr1=ptr.next;
3.header=ptr1;
4.if(ptr1!=NULL)
1.ptr1.prev=NULL;
5. del ptr
6. gc.collector()
Before deleting a node at end
header
1010
pt1 ptr
header
1000 2000
1010 After deleting a node at end
Algorithm
1. ptr=header
1.for(i=0;i<pos-1;i++)
1. ptr=ptr.next;
2. ptr1=ptr.prev;
3. ptr2=ptr.next;
4. ptr1.next=ptr2;
5. ptr2.prev=ptr1;
6. del ptr
7. gc.collecor()
Before deleting a node at position 3
header
1010 1010
ptr ptr
4.2ptr=ptr.prev;
5. End while
7.end else
header ptr
1010 1010
Forward Order : 10 20 30 40
Reverse Order : 40 30 20 10
Implementation of Doubly Linked List
#include<stdio.h> switch(choice)
#include<stdlib.h> {
struct node case 1:
{ insertion_beginning();
struct node *prev; break;
struct node *next; case 2:
int data; insertion_last();
}; break;
struct node *head; case 3:
void insertion_beginning(); insertion_specified();
void insertion_last(); break;
void insertion_specified(); case 4:
void deletion_beginning(); deletion_beginning();
void deletion_last(); break;
void deletion_specified(); case 5:
void display(); deletion_last();
void search(); break;
void main () case 6:
{ deletion_specified();
int choice =0; break;
while(choice != 9) case 7:
{ search();
printf("\n*********Main Menu*********\n"); break;
printf("\nChoose one option from the following list ...\n"); case 8:
display();
printf("\n============================================= break;
==\n"); case 9:
printf("\n1.Insert in begining\n2.Insert at last\n3.Insert at any exit(0);
random location\n4.Delete from Beginning\n5.Delete from break;
last\n6.Delete the node after the given default:
data\n7.Search\n8.Show\n9.Exit\n"); printf("Please enter valid choice..");
printf("\nEnter your choice?\n"); }
scanf("\n%d",&choice); }
}
Implementation of Doubly Linked List
void insertion_beginning() void insertion_last()
{
{
struct node *ptr; struct node *ptr,*temp;
int item; int item;
ptr = (struct node *)malloc(sizeof(struct node)); ptr = (struct node *) malloc(sizeof(struct node));
if(ptr == NULL)
if(ptr == NULL)
{ { printf("\nOVERFLOW");
printf("\nOVERFLOW"); }
else
}
else {
{ printf("\nEnter value");
printf("\nEnter Item value"); scanf("%d",&item);
ptr->data=item;
scanf("%d",&item);
if(head == NULL)
if(head==NULL) {
{ ptr->next = NULL;
ptr->prev = NULL;
ptr->next = NULL;
ptr->prev=NULL; head = ptr;
ptr->data=item; }
else
head=ptr;
{
}
else temp = head;
{ while(temp->next!=NULL)
{
ptr->data=item;
temp = temp->next;
ptr->prev=NULL;
ptr->next = head; }
head->prev=ptr; temp->next = ptr;
ptr ->prev=temp;
head=ptr;
} ptr->next = NULL;
printf("\nNode inserted\n"); }
} }
printf("\nnode inserted\n");
}
}
Implementation of Doubly Linked List
void insertion_specified() void deletion_beginning()
{ {
struct node *ptr,*temp; struct node *ptr;
int item,loc,i; if(head == NULL)
ptr = (struct node *)malloc(sizeof(struct node)); {
if(ptr == NULL) printf("\n UNDERFLOW");
{ }
printf("\n OVERFLOW"); else if(head->next == NULL)
} {
else head = NULL;
{ free(head);
temp=head; printf("\nnode deleted\n");
printf("Enter the location"); }
scanf("%d",&loc); else
for(i=0;i<loc;i++) {
{ ptr = head;
temp = temp->next; head = head -> next;
if(temp == NULL) head -> prev = NULL;
{ free(ptr);
printf("\n There are less than %d elements", loc); printf("\nnode deleted\n");
return; }
}
} }
printf("Enter value");
scanf("%d",&item);
ptr->data = item;
ptr->next = temp->next;
ptr -> prev = temp;
temp->next = ptr;
temp->next->prev=ptr;
printf("\nnode inserted\n");
}
}
Implementation of Doubly Linked List
void deletion_last() else
{ {
struct node *ptr; ptr = head;
if(head == NULL) head = head -> next;
{ head -> prev = NULL;
printf("\n UNDERFLOW"); free(ptr);
} printf("\nnode deleted\n");
else if(head->next == NULL) }
{
head = NULL; }
free(head); void deletion_last()
printf("\nnode deleted\n"); {
} struct node *ptr;
else if(head == NULL)
{ {
ptr = head; printf("\n UNDERFLOW");
if(ptr->next != NULL) }
{ else if(head->next == NULL)
ptr = ptr -> next; {
} head = NULL;
ptr -> prev -> next = NULL; free(head);
free(ptr); printf("\nnode deleted\n");
printf("\nnode deleted\n"); }
} else
} {
void deletion_beginning() ptr = head;
{ if(ptr->next != NULL)
struct node *ptr; {
if(head == NULL) ptr = ptr -> next;
{ }
printf("\n UNDERFLOW"); ptr -> prev -> next = NULL;
} free(ptr);
else if(head->next == NULL) printf("\nnode deleted\n");
{ }
head = NULL; }
free(head);
printf("\nnode deleted\n");
}
Implementation of Doubly Linked List
void deletion_specified() void search()
{ struct node *ptr, *temp; {
struct node *ptr;
int val; int item,i=0,flag;
printf("\n Enter the data after which the node is to be deleted : "); ptr = head;
scanf("%d", &val); if(ptr == NULL)
ptr = head; {
while(ptr -> data != val) printf("\nEmpty List\n");
}
ptr = ptr -> next;
else
if(ptr -> next == NULL) {
{ printf("\nCan't delete\n"); printf("\nEnter item which you want to search?\n");
} scanf("%d",&item);
else if(ptr -> next -> next == NULL) while (ptr!=NULL)
{
{ ptr ->next = NULL;
if(ptr->data == item)
} {
else printf("\nitem found at location %d ",i+1);
{ flag=0;
temp = ptr -> next; break;
}
ptr -> next = temp -> next;
else
temp -> next -> prev = ptr; {
free(temp); flag=1;
printf("\nnode deleted\n"); }
} i++;
ptr = ptr -> next;
}
}
void display() if(flag==1)
{ {
struct node *ptr; printf("\nItem not found\n");
printf("\n printing values...\n"); }
}
ptr = head;
while(ptr != NULL) }
{ printf("%d\n",ptr->data);
ptr=ptr->next;
}
}
Disadvantage of doubly linked list
Uses extra pointer as it keep track of
previous and next nodes, requires extra
space.
Insertion and deletion operations takes
more time(needs more pointer operations)
Applications of doubly linked list
Disadvantage
1. Goes into infinite loop, if proper care is not taken
2. It is not easy to reverse the elements.
Applications of cll
Used in operating system. When multiple applications are running in
PC 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.
To repeat songs in the music player.
Escalator which will run circularly uses the circular linked list.
/* Write a c program to implement circular linked list*/
#include<stdio.h> #include<conio.h> #include<malloc.h>
#include<stdlib.h>
int choice,i,item;
struct node {
int data;
struct node *link;
}*front,*rear,*new,*ptr1,*ptr;
main() {
front=rear=NULL;
printf("\n select menu\n");
while(1) {
printf("\n1.Enqueue \n2.Dequeue \n3.Display \n4.Exit");
printf("\nEnter ur choice: ");
scanf("%d",&choice);
switch(choice) {
case 1: enqueue(); break;
case 2: dequeue(); break;
case 3: display(); break;
case 4: exit(0);
default: printf("\nWrong choice.");
}/*end of switch*/
}/*end of while*/
}/*end of main*/
int enqueue(){
// insert new node at end
new=malloc(sizeof(struct node));
printf("\nEnter the item: ");
scanf("%d",&item);
new->data=item; dequeue()
if(front==NULL) { // delete first node in cll
front=new; if(front==NULL)
else printf("\nThe circular list is empty.");
rear->link=new; else
rear=new; if(front==rear)// cll has single element
rear->link=front; {
return; printf("\nThe deleted element is: %d",front->data)
}/*end of enqueue()*/ front=rear=NULL;
}
else
{
printf("\nThe deleted element is: %d",front->data)
front=front->link;
rear->link=front;
}
return;
}/*end of dequeue*/
display()
{
ptr=front;
if(front==NULL)
printf("\nThe circular list is empty.");
else
{
printf("\nElements in the list are: ");
while(ptr!=rear)
{
printf(" %d",ptr->data);
ptr=ptr->link;
}/*end of while*/
->data);
return;
}/*end of else*/
}/*end of display*/
Circular LL
// insert new node as first element
void insert()
{
new=malloc(sizeof(struct node));
printf("\nEnter the item: ");
scanf("%d",&item);
new->data=item;
if(first==NULL)
first=new;
else{
new->link=first;}
first=new;
last->link=new;
}
Circular LL
// delete last node
void deletion() Consider front as first
{ rear as last
if(first==NULL)
else
if(first==last)
first=last=NULL
else
{ ptr=first->link;
while(ptr!=last)
{
ptr1=ptr;
ptr=ptr->link;
}
ptr1->link=first;
last=ptr1;
free(ptr);}
}//deletion
Circular doubly linked list
- Circular doubly linked list last node next pointer points to first node address
and first node prev pointer points to last node address.
- There is no concept of NULL pointer.
Applications
}
return;
}/*end of dequeue*/
Linked List
Application of linked list : polynomial
expression
Linked lists can be particularly useful for representing
polynomial expressions in various applications due to their
dynamic nature and efficient operations. how linked
lists can be applied to polynomial expressions:
1. Representation of Polynomials:
A polynomial can be represented as a linked list where each
node contains the coefficient and exponent of a term.
For example, the polynomial 3x2+5x+2, 3x^2 + 5x + 2
3x2+5x+2 can be represented as:
Node(3, 2) -> Node(5, 1) -> Node(2, 0) -> NULL
2. Dynamic Size:
Linked lists allow for easy insertion and deletion of terms. If you need to
add or remove terms from a polynomial, you can simply adjust pointers
without needing to resize an array.
3. Efficient Operations:
Addition: To add two polynomials, traverse both linked lists, combining
terms with the same exponent and creating new nodes for the result.
Multiplication: You can multiply two polynomials by iterating through each
term in the first polynomial and multiplying it by every term in the second
polynomial, creating new nodes for the resulting terms.
4. Evaluation:
A linked list can facilitate polynomial evaluation at a given value by iterating
through the list and calculating the sum of each term evaluated at that
5. Sparse Representation:
Polynomials with many zero coefficients can be efficiently represented
using linked lists, storing only the non-zero terms, thus saving space.
Implementation of Polynomial Expression
#include <stdio.h> if (poly1 && (!poly2 || poly1->exponent > poly2->exponent)) {
#include <stdlib.h> newTerm = createTerm(poly1->coefficient, poly1->exponent);
typedef struct Term { poly1 = poly1->next;
int coefficient; } else if (poly2 && (!poly1 || poly1->exponent < poly2-
int exponent;
>exponent)) {
struct Term* next;
} Term; newTerm = createTerm(poly2->coefficient, poly2->exponent);
// Function to create a new term poly2 = poly2->next;
Term* createTerm(int coefficient, int exponent) { } else { // poly1->exponent == poly2->exponent
Term* newTerm = (Term*)malloc(sizeof(Term)); int coeffSum = poly1->coefficient + poly2->coefficient;
newTerm->coefficient = coefficient; if (coeffSum != 0) { // Only add non-zero terms
newTerm->exponent = exponent; newTerm = createTerm(coeffSum, poly1->exponent);
newTerm->next = NULL; }
return newTerm; } poly1 = poly1->next;
// Function to print the polynomial
poly2 = poly2->next;
void printPolynomial(Term* head) {
if (!head) { }
printf("0\n"); if (newTerm) {
return; *lastPtrRef = newTerm;
} lastPtrRef = &newTerm->next;
Term* current = head; } }
while (current) { return result;
printf("%dx^%d ", current->coefficient, current->exponent); }
current = current->next;
int main() {
if (current) {
// Creating first polynomial: 3x^2 + 5x + 2
printf("+ ");
} } Term* poly1 = createTerm(3, 2);
printf("\n"); poly1->next = createTerm(5, 1);
} poly1->next->next = createTerm(2, 0);
// Function to add two polynomials // Creating second polynomial: 4x^1 + 6
Term* addPolynomials(Term* poly1, Term* poly2) { Term* poly2 = createTerm(4, 1);
Term* result = NULL; poly2->next = createTerm(6, 0);
Term** lastPtrRef = &result; // Pointer to the last pointer in the result list printf("Polynomial 1: ");
Term* addPolynomials(Term* poly1, Term* poly2) { printPolynomial(poly1);
Term* result = NULL;
printf("Polynomial 2: ");
Term** lastPtrRef = &result; // Pointer to the last pointer in the result list
while (poly1 || poly2) { printPolynomial(poly2);
Term* newTerm = NULL; // Adding the two polynomials
if (poly1 && (!poly2 || poly1->exponent > poly2->exponent)) { Term* result = addPolynomials(poly1, poly2);
newTerm = createTerm(poly1->coefficient, poly1->exponent); // Print the result
poly1 = poly1->next; printf("Resultant Polynomial: ");
// Function to add two polynomials printPolynomial(result);
Term* addPolynomials(Term* poly1, Term* poly2) { // Freeing memory (not shown here for brevity, but should be
Term* result = NULL;
implemented)
Term** lastPtrRef = &result; // Pointer to the last pointer in the result list
return 0;
while (poly1 || poly2) {
Term* newTerm = NULL; }