DS Module-3 Notes
DS Module-3 Notes
MODULE – 3
Linked Lists: Definition, Representation of linked lists in Memory, Memory allocation; Garbage
Collection. Linked list operations: Traversing, Searching, Insertion, and Deletion. Doubly Linked
lists, Circular linked lists, and header linked lists. Linked Stacks and Queues. Applications of Linked
lists – Polynomials, Sparse matrix representation. Programming Examples
Introduction
Linked list is a collection of zero or more nodes ,where each node has some information. Given the
address of the first node, any node in the list can be obtained. Every node consis of two parts one is
the information part and the other is the address of the next node. The pointer of the last node
contains a special value called NULL.
Representation of linked list: Each item in the list is called a node and contains two fields
Information field - The information field holds the actual elements in the list
Link field- The Link field contains the address of the next node in the list
To create a linked list of integers the node can be defined as follows using a self referential
structure.
Sruct Node
{
int info;
struct Node * link;
};
Typedef struct Node NODE;
After the node is created we have to create a new empty list as follows
node * first=NULL;
The pointer first stores the address of the first node in the list. With this information we
will be able to access the location of all the other nodes in the list.
To obtain a node we use the statement
First=(node*) malloc(sizeof(node)
To place the information 5 ,we can use the statement Firs->info= 5;
As there are no other nodes in the list the link part can be made NULL as follow
First->link=NULL
First 5
The maintenance of linked lists in memory assumes the possibility of inserting new nodes
into the lists and hence requires some mechanism which provides unused memory space
for the new nodes. Similarly a mechanism is required which makes the deleted node
available for future use.
Together with the linked list in memory, a special list is maintained which consist of
unused memory cells.
This list which has its own pointer is called the list of available space or the free storage
list or the free pool. Such a list is also called AVAIL
Instead of using the malloc function the following getnode() function can be used to get a new
node
NODE * getNode(void)
{
/* provide a node for use */
NODE * new;
if (avail)
{
new = avail;
avail = avail→link;
return new;
}
else
{
new=( NODE *)malloc(sizeof(NODE));
return new;
}
}
Instead of the free function the following retnode function can be used
Garbage collection
Suppose some memory space becomes reusable because a node is deleted from a list or an
entire list is deleted from a program, we can make this space to be available for future use.
One way is to immediately reinsert the space into the free storage list.
This is done when a list is implemented by linear arrays. But this method may be too time
consuming for the operating system of the computer. So an alternate method is devised.
The operating system of a computer may periodically collect all the deleted space on to the
free storage list this technique si called garbage collection
temp->link=NULL;
if (first==NULL)
first=temp;
else
{
cur=first
while(cur->link!=NULL)
cur=cur->link;
cur->link=temp
}
}
}
}
Delete the nodes from a linked list pointed by first whose information part is specified is item
cur=first;
while (cur!=NULL)
{
If (cur->info==item)
{
prev->link=cur->link;
free(cur);
return(first);
}
else
{
prev=cur;
cur=cur->link;
}
}
Printf(“node with item not found”)
return(first);
}
Delete the NODE present at location loc, the NODE that precedes is present at location locp. If
there is only one NODE then locp=NULL
if (first==NULL)
printf(“list is empty);
else
Dept. of ISE, SVIT Page 7
18CS32 DSA Notes
{
cur=first
while(cur!=NULL)
{
Printf(“%d \t”, cur->info);
cur=cur->link;
}
}
if (first==NULL)
{
printf(“list is empty);
return(0)
}
cur=first
while(cur!=NULL)
{
count++
cur=cur->link;
}
return(count)
}
retrun;
}
cur =cur->link;
}
}
Printf(“search unsuccessfull”);
}
printf("queue overflow\n");
return(first)
}
temp->info=item;
temp->link=NULL;
if (front==NULL)
{
rear=temp;
front=temp;
}
else
{
rear->link=temp;
rear=temp;
}
}
Function deletes the NODE in the front and returns the item
int del_front(NODE * front)
{
NODE cur;
int itemdel;
if(front==NULL)
{
printf("Queue underflow\n");
return front;
}
cur=front;
itemdel=cur->info;
front=front->link;
free(cur);
return(itemdel);
}
stack * top[MAX_STACKS]
We assume that the initial condition for the stacks is: top[i] = NULL, 0≤i < MAX_STACKS
and the boundary condition is: top[i] = NULL if the ith stack is empty
Function push creates a new NODE, temp, and inserts the NODE in front of the ith stack.
Function pop returns the top element and changes top to point to the address contained in its
link field.
int pop(int i)
{/* remove top element from the ith stack */
int itemdel;
Stack * temp;
if (top[i]==NULL)
return stackEmpty();
temp = top[i];
itemdel = temp→data;
top[i] = top[i]→link;
free(temp);
return item;
}
We assume that the initial condition for the queues is: front[i] = NULL, ,rear[i]=NULL0 ≤ i
< MAX_QUEUES
and the boundary condition is: front[i] = NULL iff the ith queue is empty
{
front[i] = temp;
rear[i] = temp;
}
else
{
rear[i]→link = temp;
rear[i]=temp;
}
}
Function deleteq deletes the item in the front of the ith queue
int deleteq(int i)
{/* delete an element from queue i */
Queue * temp;
int itemdel
if (front[i]==NULL)
return queueEmpty();
temp = front[i];
itemdel = temp→data;
front[i]= front[i]→link;
free(temp);
return itemdel;
}
A singly linked list in which the last NODE has a null link is called a chain. If the link field of the
last NODE points to the first NODE in the list, then such a linked list is called a circular list.
last
By keeping a pointer at the last instead of the front we can now insert easily at the front and end of
the list
if (last==NULL)
{
/* list is empty, change last to point to new entry */
last = new;
last→link = last;
}
else
{
/* list is not empty, add new entry at front */
new→link = last→link;
last→link = new;
}
}
if (last==NULL)
{
/* list is empty, change last to point to new entry */
last = new;
last→link = last;
}
else
{
/* list is not empty, add new entry at front */
New→link = last→link;
last→link = New;
last=New;
}
}
count++;
temp = temp→link;
}
return count;
}
A header linked list is a linked list which always contains a special NODE, called the header NODE,
at the beginning of the list. There are two types of header list.
Note: Unless stated it is assumed that the linked list is circular header list.
If we are pointing to a specific NODE, say p, then we can move only in the direction of the
links. The only way to find the NODE that precedes p is to start at the beginning of the list.
If we wish to delete an arbitrary NODE from a singly linked list. Easy deletion of an arbitrary
NODE requires knowing the preceding NODE.
Can traverse only in one direction.
Difficult to delete arbitrary NODEs.
A doubly linked list may or may not be circular. The data field of the header NODE usually contains
no information.
struct NODE
{
strunct NODE * llink;
int data;
struct NODE * rlink;
};
The function dinsert() inserts a newNODE into a doubly linked list after a NODE pointed by
ptr
next=ptr->rlink;
ptr->rlink=newNODE;
newNODE->llink=ptr;
newNODE->rlink=next;
next->llink=newNODE;
}
The function ddelete() deletes a NODE from a doubly linked list pointed by head
Space Efficiency: We have the overhead of storing two pointers for each element.
Polynomials Polynomial
Representation
We should be able to represent any number of different polynomials as long as memory is available.
In general, A polynomial is represented as :
A(x)= am-1 xm-1 + ............ a0x0
where the ai are nonzero coefficients and the ei are nonnegative integer exponents such that
e m-1 > em-2 >..................... > e1 > e0 ≥ 0.
We represent each term as a NODE containing coefficient and exponent fields, as well as a pointer
to the next term. Assuming that the coefficients are integers, the type declarations are:
struct polyNode {
int coef;
int expon;
struct polyNode * link;
};
Typedef struct polyNode POLY;
Consider the polynomials a = 3x14 + 2x8 + 1x+2 and b = 8x12- 3x10 + 10x5 +3 It can be represented as
follows
a 3 14 2 8 1 1 2 0
b 8 12 3 10 10 5 3 0
Adding Polynomials
To add two polynomials, we examine their terms starting at the NODEs pointed to by a and b.
1. If a→expon = b→expon, we add the two coefficients a→coef + b→coef and create a new
term for the result c. a = a→link; b = b→link;
2. If a→expon < b→expon, then we create a duplicate term of b, attach this term to the
result,called c, and b = b→link;
3. If a→expon > b→expon, then we create a duplicate term of a, attach this term to the result,
called c, and a = a→link;
POLY *Pointer padd(POLY * a, POLY * b) /* return a polynomial which is the sum of a and
b */
{
POLY * c,*tempa, *tempb,*lastc;
int sum;
c= (POLY*)malloc(sizeof(POLY))
c->link=NULL
tempa=a
tempb=b
lastc=c;
while (tempa!=NULL && tempb!=NULL)
{
switch (COMPARE(tempa→expon, tempb→expon))
{
case -1: lastc=attach(tempb→coef, tempb→expon,lastc);
tempb = tempb→link;
break;
return(c);
}
POLY *Pointer padd(POLY * a, POLY * b) /* return a polynomial which is the sum of a and
b */
{
POLY * c,*tempa, *tempb,*lastc;
int sum;
c= (POLY*)malloc(sizeof(POLY))
c->link=c
tempa=a->link;
tempb=b->link;
lastc=c;
while (tempa!=a && tempb!=b)
{
switch (COMPARE(tempa→expon, tempb→expon))
{
case -1: lastc=attach(tempb→coef, tempb→expon,lastc);
tempb = tempb→link;
break;
lastc->link=c
return(c);
}
temp→coef = c;
temp→expon = e;
temp->link =rear->link;
rear->link=temp;
rear=temp;
return(rear);
}
If m > 0 and n > 0, the while loop is entered. Each iteration of the loop requires O(1) time.At each
iteration, either a or b moves to the next term or both move to the next term. Since the iteration
terminates when either a or b reaches the end of the list, therefore, the number of iterations is bounded
by m + n - 1.
The time for the remaining two loops is bounded by O(n + m). The first loop can iterate m times and
the second can iterate n times. So, the asymptotic computing time of this algorithm is O(n +m).
In this section, we study a linked list representation for sparse matrices. Usually, linked lists
allow us to efficiently represent structures that vary in size, a benefit that also applies to
sparse matrices.
In our data representation, we represent each column of a sparse matrix as a circularly linked
list with a header NODE. We use a similar representation for each row of a sparse matrix.
Each NODE has a tag field, which we use to distinguish between header NODEs and entry
NODEs.
Each header NODE has three additional fields: down, right, and next.
down field links into a column list and the
right field links into a row list.
The next field links the header NODEs together.
The header NODE for row i is also the header NODE for column i, and the total number
of header NODEs is max {number of rows, number of columns}.
Each header NODE is in three lists: a list of rows, a list of columns, and a list of header
NODEs. The list of header NODEs also has a header NODE that has the same structure as an
entry NODE.
The row and col value of the header NODE consist of the dimension of the matrix
Example:
Consider the sparse matrix shown below.
Since there are two different types of NODEs a union is used to create the appropriate data structure.
The necessary C declarations are as follows: