UNIT I Material
UNIT I Material
UNIT-I- LISTS
Syllabus
Abstract Data Types (ADTs) – List ADT – Array-based implementation – Linked list
implementation – Singly linked lists – Circularly linked lists – Doubly-linked lists –
Applications of lists – Polynomial ADT – Radix Sort – Multilists.
Why Data Structures?
• Data Structure is the orderly arrangement of data in computers to use it in a
more efficient way.
• It is the collection of data objects that allows sorting, organizing and retrieving
of data on computers.
• It is the key component of computer science and largely used in the areas of
Artificial Intelligence, Operating systems, Graphics and etc.
• Real life Example: Searching cloth (data) in a messy wardrobe.
• Program= Data Structures + Algorithms
Data Structures- Definition
Data Structure is defined as the way of organizing data not only tell how data
is stored but also explains the relationships among them.
Ex: List, Stack, Queue, Tree, Graph and etc.
Data Structures- Classification
Linear Data Structures- In Linear Data Structures, the elements in the data structures
are accessed sequentially.
Ex: List, Stack, Queue
Non-Linear Data Structures- In Non-linear Data Structures, the elements in the data
structures are not accessed sequentially.
Ex: Tree, Graph
Abstract Data Type (ADT)
• The abstract datatype is a special kind of datatype, whose behavior is defined
by set of values and set of operations.
• The ADT is made of primitive datatypes, but operation logics are hidden from
the user.
• Ex: List, Stack, Queue, Tree, Graph and etc.
List ADT
• List is the group of elements and its general form is A1, A2, A3,…….A N
• The size of the list is N.
Operations in List:
• Printlist − print all the array elements one by one.
• Insertion − Adds an element at the given index.
• Deletion − Deletes an element at the given index.
• Search − Searches an element using the given index or by the value.
• Update − Updates an element at the given index.
Printlist Operation:
It is used to print the elements of the list one by one starting from the element
at index ‘0’ to index ‘n-1’.
Assume the array ‘a’ has ‘n’ elements. The print operation will print the
elements a[0], a[1], a[2], a[3],…..a[n-1]
void printlist(int a[], int n)
{
int i;
for (i=0; i<=n-1;i++)
{
printf(“%d”, a[i])
}
}
Search Operation:
We can perform two kinds of search.
1. Search by value and return the index of the element if it is present in the list
otherwise -1 is returned.
2. Search by position will return the element at the given position.
Search by value Operation:
The list and the element to be searched is given. If the element is present
in the list, the position (index) of the element is returned otherwise the value -1 is
returned.
return -1;
}
Insertion Operation:
Insertion operation inserts a new element to the list. For a given array with ‘n’
elements, the insertion operation inserts a new element in the specified location. If
there is an element at the specified location, then the elements in the list from the
specified location up to the end are moved backward one by one starting from the last
element. This makes the empty place at the specified location. The new element is
now inserted into the specified location. The size of the list is also increased into ‘n+1’
after the insertion of the element.
Example:
List a, n=6
Index 0 1 2 3 4 5 6 7 8 9
Element 55 35 26 78 63 49 - - - -
Insert(18,3)
Index 0 1 2 3 4 5 6 7 8 9
Element 55 35 26 78 63 49 - - - -
a[6]=a[5]
0 1 2 3 4 5 6 7 8 9
Element 55 35 26 78 63 - 49 - - -
a[5]=a[4]
Index 0 1 2 3 4 5 6 7 8 9
Element 55 35 26 78 - 63 49 - - -
a[4]=a[3]
Index 0 1 2 3 4 5 6 7 8 9
Element 55 35 26 - 78 63 49 - - -
a[3]=new
Index 0 1 2 3 4 5 6 7 8 9
Element 55 35 26 18 78 63 49 - - -
List a, n=7
void insert(int a[],int n,int x,int pos)
Note: X-New value to be inserted
{
int i;
if (n==size(a))
{
printf(“list is full and cannot insert”);
return;
}
else
{
i=n-1;
while(i>=pos)
{
a[i+1]=a[i];
i=i-1;
}
a[pos]=x;
n=n+1;
}
}
Deletion:
Deletion operation deletes an element from the list. For a given array with ‘n’
elements, the deletion operation deletes an element from the specified location. This
makes empty position at the specified location. After deletion, the elements from the
next of deleted position up to the last position are moved forward to enforce the
continuous storage of elements. The size of the list is decreased into ‘n-1’ after the
deletion of the element.
Example:
List a, n=6
Index 0 1 2 3 4 5 6 7 8 9
Element 55 35 26 78 63 49 - - - -
Delete(2)
Index 0 1 2 3 4 5 6 7 8 9
Element 55 35 - 78 63 49 - - - -
a[2]=a[3]
Index 0 1 2 3 4 5 6 7 8 9
Element 55 35 78 - 63 49 - - - -
a[3]=a[4]
Index 0 1 2 3 4 5 6 7 8 9
Element 55 35 78 63 - 49 - - -
a[4]=a[5]
Index 0 1 2 3 4 5 6 7 8 9
Element 55 35 78 63 49 - - - -
List a, n=5
int delete(int a[],int n, int pos)
{
int i, del;
if (n==0)
{
printf(“list is empty and cannot delete”);
return -1;
}
else
{
del=a[pos];
i=pos;
while(i<=n-1)
{
a[i]=a[i+1];
i=i+1;
}
n=n-1;
return del;
}
}
Note : If the list is empty, then the deletion operation will return the value -1.
Update Operation:
• Update operation updates the value of the element at the specified
location (i).
Diagrammatic Representation:
• In the above figure, the arrow represents the links. The data part of every node
contains the value of the elements. The address part of every node contains
the address of the next node in the list. The address of the last node is made
as null pointer. We can have as many elements as we require, in the linked list.
• Head is the special node whose address part is pointing the first data node of
the list.
Defining Node datatype of the singly linked list node:
struct snode
{
int data;
struct snode *next;
};
Declaration of Node:
struct snode *head, *p;
Allocating Space for Node:
p = (struct snode *)malloc(sizeof(struct snode));
Operations on Singly Linked List:
• Insertion
• Deletion
• Find
• Find previous
• Traverse
Print Operation:
• Each node of the list is visited at least once in order to perform printing and it
prints the data part of each node present in the list.
• The singly linked list (head address) is given as the input for print operation.
One pointer has to declare and it initially points the first element. After visiting
the first element, the pointer moves and points the second element and it is
moving continuously till the last node is reached.
Print Implementation:
void print(struct snode *head)
{
struct snode *p;
p=head->next;
while(p!=NULL)
{
printf(%d”,p->data);
p=p->next;
}
}
Find Operation:
• Find operation gets the singly linked list and the element to be searched as the
input. Each element of the list is matched with the given element. If the element
is found on any of the location, then location (address) of that element is
returned otherwise null is returned.
p=head->next;
while(p!=null)
{
if(x==p->data)
return(p);
else
p=p->next;
}
return null;
}
Find previous Operation:
• Find previous operation gets the singly linked list and the element to be
searched as the input. Each element of the list is matched with the given
element. If the element is found on any of the location, then location (address)
of the previous element is returned otherwise null is returned.
return(pre);
else
{
pre=p;
p=p->next;
}
}
return null;
}
Insertion Operation:
• Insertion at the beginning- It involves inserting any element at the front of the
singly linked list.
• Insertion at the end-It involves insertion at the end of the singly linked list. It is
necessary to traverse the singly linked list to reach the last node after which the
new node will be inserted.
• Insertion after the specified node-It involves insertion after the specified node
of the linked list. It is necessary to traverse the singly linked list to reach the
specified node after which the new node will be inserted.
Insertion at the beginning Operation:
• The list and the element to be inserted is given. The new element is inserted
at the front of the list.
• Initially first element is pointed by header node.
• After the insertion of new element, the new element will point the first element
and header node will point the new element.
• The new element becomes the first element in the list.
Before Insertion:
3100 (newnode)
• Insert the data 45 into the data part of the node
45
3100 (newnode)
• This new node should be inserted at the front of the list.
During Insertion:
Changes:
1. newnode->next=2000 (address of 10) (identified in the name of head->next)
2. head->next=3100 (address of 45) (identified in the name of newnode)
After Insertion:
Implementation:
• Insert the data 45 into the data part of the node and the next of newnode is set
as NULL.
During Insertion:
Changes:
1. (identified by traversing the list) (address of last node)
4300->next =3100 (address of 45) (identified in the name of newnode)
After Insertion:
Implementation:
p=head;
while(p->next!=null)
{
p=p->next;
}
p->next=newnode;
}
Insertion after the specified node Operation:
• The list and the element to be inserted is given. The new element is inserted
after the specified node of the linked list. It is necessary to traverse the node to
reach the specified node after which the new node will be inserted.
• Assume the specified node as ‘p’.
• After the insertion of new element, the new element will point the node which
was pointed by node ‘p’ and node ‘p’ will point the new element.
Before Insertion:
During Insertion:
Changes:
1. newnode->next=4300 (address of 30) (identified in the name of
p->next)
2. p->next=3100 (address of 45) (identified in the name of newnode)
After Insertion:
Implementation:
Assume the following
header head->next=NULL
head
Prepared By Dr.C.Callins Christiyana Professor and Head, CSE, SRM Madurai
21
Changes:
1. p=head->next=2000 (address of 10)
(identified in the name of head->next and called as ‘p’)
2. head->next=p->next=1500 (address of 20)
After Deletion:
Implementation:
Assume the following
Changes:
1. (identified by traversing the list) (address of last node) 4300
2. (identified by traversing the list) (address of previous to last node) 1500
3. 1500->next=NULL(4300->next) pre->next=p->next
After Deletion:
Implementation:
Assume the following
• Delete(20)
• It is necessary to identify the address of 20 and call it as ‘p’ and the address of
the previous node of 20 that is address of 10 and call it as ‘pre’.
During Deletion:
Changes:
1. (identified by traversing the list) (address of node to be deleted) 1500
2. (identified by traversing the list) (address of previous of the node to be
deleted) 2000
3. 2000->next=4300 pre->next=p->next
After Deletion:
Implementation:
Assume the following
pre=p;
p=p->next;
}
}
}
}
Advantages of Singly Linked List
1. Insertion and deletion operations are very easy in the singly linked list.
There is no need to move the elements forward and backward after the insertion
or deletion of an element, only the address present in the next pointer needs to
be updated.
2. In the singly linked list, efficient memory utilization can be achieved since
the size of the singly linked list can be increased or decreased at run time so
there is no memory wastage and there is no need to pre-allocate the memory.
Disadvantages of Singly Linked List
• In the above figure, the forward arrow represents the next address. The
backward arrow represents the prev address. The data part of every node
contains the value of the elements. The next address of the last node is set as
NULL. We can have as many elements as we require, in the doubly linked list.
Header is the special node (at head address) whose next address is pointing
the first node of the list. The prev address of it points NULL.
Defining Node datatype of Doubly Linked List:
struct dnode
{
int data;
struct dnode *prev;
struct dnode *next;
};
Declaration of Node:
struct dnode *head, *p;
• After the insertion of new element, the new element next address will point the
first element and its prev address will point the header node. The header node
next address is changed and it will points the new element and the prev address
of the first element is changed and points the new element. The new element
becomes the first element of the list.
Before Insertion:
Changes:
1. newnode->next=1500 (address of 10) (identified in the name of
head->next as p)
2. newnode->prev=head
3. p->prev=newnode (identified in the name of newnode)
4. head->next=newnode
After Insertion:
x is the element to
Implementation:
be inserted
void insertbegin(struct dnode *head, int x)
{ p is the address to hold
the address of the first
struct dnode *newnode,*p;
element
newnode=(struct dnode *)malloc(sizeof(struct dnode));
p=head->next;
newnode->data=x;
newnode->next=p;
newnode->prev=head;
p->prev=newnode;
head->next=newnode;
}
Insertion at the end Operation:
• The doubly linked list and the element to be inserted is given. The new element
is inserted at the end of the doubly linked list. The last node is identified by
traversing the list.
• The last node will point the new element after insertion. The new element will
point NULL address. The new element becomes the last element of the list.
Before Insertion:
• Insert the data 45 into the data part of the node and make the next address of
this newnode as NULL
During Insertion:
Changes:
1. (identified by traversing the list) (address of last node)
1700->next=2900 (address of 45) (identified in the name of newnode)
2. 2900->prev=1700
After Insertion:
Implementation:
x is the element to
void insertend(struct dnode *head, int x) be inserted
{
p is the address to hold
struct dnode *newnode,*p; the address of the first
newnode=(struct dnode *)malloc(sizeof(struct dnode)); element
p=head;
newnode->data=x;
newnode->next=NULL;
while(p->next!=NULL)
{
p=p->next;
}
newnode->prev=p;
p->next=newnode;
}
Insertion after the specified node Operation:
• The doubly linked list and the element to be inserted is given. The new element
is inserted after the specified node of the doubly linked list. It is necessary to
traverse the doubly linked list to reach the specified node after which the new
node will be inserted.
• Assume the specified node as ‘p’.
• After the insertion of new element, the new element will point the node which
was pointed by node ‘p’ and node ‘p’ will point the new element.
Before Insertion:
Changes:
1. 45->next=30 (p->next)
2. 30->prev=45
3. p->next=newnode
4.
Prepared By 45->prev=20(p)
Dr.C.Callins Christiyana Professor and Head, CSE, SRM Madurai
35
After Insertion:
Implementation:
Assume the following
• x is the element to be inserted;
• m is the element after which new node is inserted
• p is the node address holds the address of m
• q is the node address holds the address of next of p.
}
}
Deletion Operation:
• Deletion at the beginning- It involves deletion of a node from the beginning of
the doubly linked list.
• Deletion at the end-It involves deleting the last node of the doubly linked list. It
is necessary to traverse the doubly linked list to reach the last node.
• Deletion of the specified node-It involves deleting the specified node of the
doubly linked list. It is necessary to traverse the doubly linked list to reach the
specified node.
• It is necessary to check whether the doubly linked list is empty or not before
doing deletion
Configuration of Empty doubly linked list
header head->next=NULL
head
During Deletion:
Changes:
1. p=head->next=2000 (address of 10)
2. q=p->next(address of 20)
3. head->next=q (head->next=node 20)
4. q->prev=head (node 20->prev=head)
After Deletion:
Implementation:
Assume the following
free(p);
}
}
Deletion at the end Operation:
The doubly linked list is given. This operation deletes the last node from the
doubly linked list. The last node is identified by traversing the list. After the deletion of
the lastnode, the address of the previous node of last node is set as NULL.
Before Deletion:
Changes:
1. p=lastnode address
2. q=p->prev
3. q->next=null
After Deletion:
Implementation:
Assume the following
• Delete(20)
• It is necessary to identify the address of 20 and call it as ‘p’
During Deletion:
Changes:
1. (identified by traversing the list) (address of node to be deleted) 1000 as
‘p’
2. pr=p->prev
3. ne=p->next
4. pr->next=ne
5. ne->prev=pr
After Deletion:
Implementation:
Assume the following
{
if(x==p->data)
{
pr=p->prev;
ne=p->next;
pr->next=ne;
ne->prev=pr;
free(p);
return;
}
else
{
p=p->next;
}
}
}
}
Advantages of Doubly Linked List
1. Reversing the doubly linked list is very easy because doubly linked list is
bidirectional.
2. Deletion of nodes is easy as compared to a Singly Linked List. A singly
linked list deletion requires a pointer to the node and previous node to be
deleted but in the doubly linked list, it only required the pointer which is to be
deleted.
3. Insertion and deletion operations are very easy in the doubly linked list.
There is no need to move the elements forward and backward after the insertion
or deletion of an element, only the address present in the next pointer or prev
pointer needs to be updated.
4. In the doubly linked list, efficient memory utilization can be achieved since
the size of the singly linked list can be increased or decreased at run time so
there is no memory wastage and there is no need to pre-allocate the memory.
1. It uses extra memory when compared to the array and singly linked list.
2. Since elements in memory are stored randomly, direct access of elements is
not allowed.
printf(%d”,p->data);
p=p->next;
}
}
Find Operation:
• Find operation gets the single circularly linked list and the element to be
searched as the input. Each element of the list is matched with the given
element. If the element is found on any of the location, then location (address)
of that element is returned otherwise null is returned.
Insertion Operation:
• The single circularly linked list (head address), the element to be inserted (value
x) and the value of the node (value m) after which the new element is inserted
are given. In order to insert the new element at the beginning of the list, the
value of ‘m’ is given as ‘-1’.
• Initially first element is pointed by header node.
• It is necessary to traverse the single circularly linked list to reach the specified
node after which the new node will be inserted.
• Assume the specified node as ‘p’. After the insertion of new element, the new
element will point the node which was pointed by node ‘p’ and node ‘p’ will point
the new element.
Before Insertion:
During Insertion:
Changes:
1. newnode->next=4300 (address of 30) (identified in the name of
p->next)
2. p->next=3100 (address of 45) (identified in the name of newnode)
After Insertion:
Implementation:
Assume the following
head->next=head
header
head
Before Deletion:
• Delete(20)
• It is necessary to identify the address of 20 and call it as ‘p’ and the address of
the previous node of 20 that is address of 10 and call it as ‘pre’.
During Deletion:
Changes:
1. (identified by traversing the list) (address of node to be deleted) 1500
2. (identified by traversing the list) (address of previous of the node to be
deleted) 2000
3. 2000->next=4300 (pre->next=p->next)
After Deletion:
Implementation:
Assume the following
p=p->next;
}
}
}
}
Double Circularly Linked List Implementation
• In a double circularly linked list, the last node next address points the first node
of the list. The header node prev address points the last node.
• The double circularly linked list has no beginning and no ending. There is no
null value present in the next part and prev part of any of the nodes.
Diagrammatic Representation:
• In the above figure, the forward arrow represents the next address. The
backward arrow represents the prev address. The data part of every node
contains the value of the elements. The next address of the last node points to
header node and header node prev address points the last node. We can have
as many elements we require, in the double circular linked list.
Defining Node datatype of Double Circulary Linked List:
struct dcnode
{
int data;
struct dcnode *prev;
struct dcnode *next;
};
Declaration of Node:
struct dcnode *head, *p;
Find Operation:
• Find operation gets the double circularly linked list (head address) and the
element to be searched as the input. Each element of the list is matched with
the given element. If the element is found on any of the location, then location
(address) of that element is returned otherwise NULL is returned.
of next of ‘p’ will point the new element. The prev of new element will point node
‘p’ and next of node ‘p’ will point new element.
Before Insertion:
Changes:
1. 45->next=30 (p->next)
2. 30->prev=45
3. 20->next=45(newnode)
Prepared By
4. 45->prev=20(p)
Dr.C.Callins Christiyana Professor and Head, CSE, SRM Madurai
56
After Insertion:
Implementation:
Assume the following
{
if(m==p->data)
{
q=p->next;
newnode->next=q;
q->prev=newnode;
p->next=newnode;
newnode->prev=p;
}
else
p=p->next;
}
}
}
Deletion Operation:
• The double circularly linked list and the element to be deleted are given. It
involves deleting the specified node of the double circularly linked list. It is
necessary to traverse the double circularly linked list to reach the specified
node.
• Assume the specified node as ‘p’. It is necessary to address the previous node
of node ‘p’ and next node of ‘p’.
• After the deletion of the node ‘p’, the next of previous node of ‘p’ and prev of
next node of ‘p’ are changed.
• It is necessary to check whether the double circularly linked list is empty or not
before doing deletion
head->next=head
header
head
Before Deletion:
• Delete(20)
• It is necessary to identify the address of 20 and call it as ‘p’ as well as to mark
the addresses of 10 and 30 as pr and ne respectively.
During Deletion:
Changes:
1. (identified by traversing the list) (address of node to be deleted) 1000 as
‘p’
2. pr=p->prev
3. ne=p->next
4. pr->next=ne
5. ne->prev=pr
After Deletion:
Implementation:
Assume the following
return;
}
else
{
p=p->next;
}
}
}
}
Advantages of circularly Linked List
• The procedure is continued until either one of the linked list is exhausted. Then
the remaining nodes of other linked list is directly appended to the resultant
polynomial linked list.
Poly1:
Poly2:
ResulatantPoly2:
Implementation:
void polyadd(struct pnode *head1,struct pnode *head2)
{
struct pnode *p1,*p2,*head3,*newnode,*p3;
head3=(struct pnode *)malloc(sizeof(struct pnode));
head3->coeff=-1;
head3->exp=-1;
head3->next=NULL;
p3=head3;
p1=head1->next;
p2=head2->next;
while(p1!=NULL && p2!=NULL)
{
if (p1->exp > p2->exp)
{
if(p1== NULL)
{
while(p2!=NULL)
{
newnode=(struct pnode *)malloc(sizeof(struct pnode));
newnode->coeff=p2->coeff;
newnode->exp=p2->exp;
newnode->next= NULL;
p3->next=newnode;
p3=newnode;
p2=p2->next;
}
}
if(p2== NULL)
{
while(p1!=NULL)
{
newnode=(struct pnode *)malloc(sizeof(struct pnode));
newnode->coeff=p1->coeff;
newnode->exp=p1->exp;
newnode->next= NULL;
p3->next=newnode;
p3=newnode;
p1=p1->next;
}
}
}
Multiplying two polynomials:
Input: Poly1: 3x2 + 5x1 + 6,
Poly2: 6x1 + 8
Poly2:
Resultant Poly
Merged Poly
p3->next=newnode;
p3=newnode;
p2=p2->next;
}
p1=p1->next;
}
//merging
p3=head3->next;
while(p3!=NULL)
{
p4=p3->next;
newnode=(struct pnode *)malloc(sizeof(struct pnode));
newnode->coeff=p3->coeff;
newnode->exp=p3->exp;
newnode->next=null;
while(p4!=NULL)
{
if(p3->exp==p4->exp)
{
newnode->coeff= newnode->coeff +p4->coeff;
p4=p4->next;
}
else
{
p4=p4->next;
}
}
p3=p3->next;
p5->next=newnode;
p5=newnode;
}
}
Radix Sort:
Radix sort is sorting algorithm for integers. In Radix sort, there is digit by digit
sorting is performed starting from the least significant digit to the most significant digit.
Algorithmic Steps:
1. Find the maximum element in the given list.
2. Find the number of digits (d) in the maximum element.
3. Create ‘d’ buckets of size 0 to 9.
4. For i= 1 to d do
i. Sort the array elements using digits at the i th place
Example:
Sort the following array elements using radix sort
The maximum element in the array is ‘736’ and the number of digits in
the maximum element is ‘3’. Hence the algorithm will work for 3 passes.
Pass 1:
In the first pass, the list is sorted on the basis of the digits at 1's place.
Pass2:
In the Second pass, the list is sorted on the basis of the digits at 10 th place.
Pass3:
In the third pass, the list is sorted on the basis of the digits at 100th place.
After the third pass, the array elements are completely sorted
Spare Matrix
The sparse matrix can be represented by using a linked list for every row and column.
A node in a multi-linked list has four parts:
The first part stores the data.
The second stores the pointer to the next row.
Third for the pointer to the next column and
Fourth for storing the coordinate number of the cell in the matrix.