You are on page 1of 37

# UNIT III LINEAR DATA STRUCTURES LIST

lists Polynomial Manipulation All operation (Insertion, Deletion, Merge, Traversal)

INTRODUCTION-DATA STRUCTURES

A data structure is a way of organizing data that considers not only the items stored, but
also their relationship to each other. Advance knowledge about the relationship between data
items allows designing of efficient algorithms for the manipulation of data.

A data structure is a way of organizing data in a computer's memory or even disk storage
such that they can be retrieved easily and efficiently. An example of several common data
structures are arrays, linked lists, queues, stacks, binary trees, and hash tables.

Two types:
Linear Data Structure: Linked list stores data in an organized a linear fashion. They
store data in the form of a list. Eg: arrays, linked lists, queues, stacks etc.
Non-linear Data Structure: Every data item is attached to several other data items in a
way that is specific for reflecting relationships. The data items are not arranged in a
sequential structure. Eg: Trees, Graphs etc.

## 3.1- ABSTRACT DATA TYPES (ADTs)

An abstract data type (ADT) is a set of operations. Abstract data types are mathematical
abstractions; nowhere in an ADT's definition is there any mention of how the set of operations is
implemented. This can be viewed as an extension of modular design.

Objects such as lists, sets, and graphs, along with their operations, can be viewed as
abstract data types, just as integers, reals, and booleans are data types. Integers, reals, and
booleans have operations associated with them, and so do abstract data types. For the set ADT,
we might have such operations as union, intersection, size, and complement. Alternately, we

Page 1
might only want the two operations union and find, which would define a different ADT on the
set.

A list or sequence is an abstract data type that implements an ordered collection of values, where
the same value may occur more than once.
A list is a linear structure:
Each item except the first (front, head) has a unique predecessor
Each item except the last (end, tail) has a unique successor
First item has no predecessor, and last item has no successor
An item within a list is specified by its position in the list
List ADT is a sequential storage structure. General list of the form a1, a2, a3.., an and the size
of the list is 'n'.
Where,
a1->First element of the list
an -> last element of the list
Any element in the list at the position i is defined to be ai, ai+1 the successor of ai and ai-1 is the
predecessor of ai.

## Operations performed by List ADT:

Page 2
3.2-ARRAY BASED IMPLEMENTATION OF LIST ADT
An array is a list of a finite number n of homogeneous data elements (i.e., data elements
of the same type) such that:
The elements of the array are referenced respectively by an index consisting of
n consecutive numbers.
The elements of the array are stored respectively in successive memory
locations.

Insertion and Deletion are expensive. For example, inserting at position 0 (which
amounts to making a new first element) requires first pushing the entire array down one spot to
make room, whereas deleting the first element requires shifting all the elements in the list up one,
so the worst case of these operations is O(n). On average, half the list needs to be moved for
either operation, so linear time is still required.

Insertion: Insertion refers to the operation of adding another element to the list at the specified
position. If an element is inserted at the end of the array, if there is a space to add the element then
insertion can be done easily. If we want to insert an element in the middle of the array then half of
the elements must be moved downwards to new location to accommodate the new element and retain
the order of the element. If an element is inserted at the beginning of the array then the entire array
elements can be moved downward one step to make space for new element.

Deletion Deletion refers to the operation of removing an element from the array. Deleting the
element from the end of the array can be done easily. Deleting the first element of the array requires
shifting all elements in the list up one. Deleting the other elements requires half of the list needs to be
moved.

## Disadvantages of Array Implementation: Even if the array is dynamically allocated, an estimate of

the maximum size of the list is required. Usually this requires a high overestimate, which waste
considerable space.
Insertion and deletion operations are expensive, because insertion at the beginning of the
array requires pushing the entire array elements one step downwards. As like the deleting the first

Page 3
element of the array requires, shifting all elements up one position. So the worst case operation
requires the computation time O(n).

Because the running time for insertions and deletions is so slow and the list size must be
known in advance, simple arrays are generally not used to implement lists.

## Operations Running Times

PrintList O(N)
Find
Insert O(N) (on avarage half needs to be moved)
Delete
FindKth
Next O(1)
Previous

Drawbacks in Arrays:
Has a fixed size.
Data must be shifted during insertions and deletions.

In order to avoid the linear cost of insertion and deletion, we need to ensure that the list is
not stored contiguously, since otherwise entire parts of the list will need to be moved.
The linked list consists of a series of structures, which are not necessarily adjacent in
memory. Each structure contains the element and a pointer to a structure containing its successor.
We call this the next pointer.

Page 4

In this type of Linked List two successive nodes are linked together in linear fashion.
Each Node contain address of the next node to be followed. In Singly Linked List only Linear or
Forward Sequential movement is possible in this type. Elements are accessed sequentially, no
direct access is allowed.

Characteristics:
Each Node has its successor and predecessor.
First Node does not have predecessor while last node does not have any successor.
Last Node have successor reference as NULL.
Each node of the list contains
the data item (an object pointer in our ADT)
a pointer to the next node
Real-Time Example:
Think of it like a train. The programmer always stores the first node of the list. This
would be the engine of the train. The pointer is the connector between cars of the train. Every
time the train adds a car, it uses the connectors to add a new car. This is like a programmer using
the keyword new to create a pointer to a new struct or class.

Page 5
Operations Performed:
Procedure to placing a new node to the list:
Obtain space for new node.
Assign data to the data field of the new node.
Set the next field of the new node to the beginning of the list.
Change the reference pointer of the LL to point to the new node.

## typedef struct node *node_ptr;

struct node
{
element_type element;
node_ptr next;
};
typedef node_ptr LIST;
typedef node_ptr position;

## int is_empty( LIST L )

{
return( L->next == NULL );
}

## int is_last( position p, LIST L )

{
return( p->next == NULL ); }

Page 6
//Routine- Insertion routine for linked lists

## void insert( element_type x, LIST L, position p )

{
position tmp_cell;
tmp_cell = (position) malloc( sizeof (struct node) );
if( tmp_cell == NULL )
fatal_error("Out of space!!!");
else
{
tmp_cell->element = x;
tmp_cell->next = p->next;
p->next = tmp_cell;
}
}

## //Routine -Find_previous--the find routine for use with delete

/* of returned value is NULL */
position
find_previous( element_type x, LIST L )
{
position p;
p = L;
while( (p->next != NULL) && (p->next->element != x) )
p = p->next;
return p;
}

Page 7
INSERT(O4,2,L): Insert an element 04 after the location 2 in the list L.

## void delete( element_type x, LIST L )

{
position p, tmp_cell;
p = find_previous( x, L );
if( p->next != NULL ) /* Implicit assumption of header use */
{ /* x is found: delete it */
tmp_cell = p->next;
p->next = tmp_cell->next; /* bypass the cell to be deleted */
free( tmp_cell );
}
}
DELETE(03,L): Delete the element 03 from the list L

## Figure: Deletion in SLL

Page 8
The next routine we will write is find. Find, shown in Figure 3.10, returns the position
in the list of some element. Line 2 takes advantage of the fact that the and (&&) operation is
short-circuited: if the first half of the and is false, the result is automatically false and the second
half is not executed.

//Routine-Find routine
/* Return position of x in L; NULL if not found */
position find ( element_type x, LIST L )
{
position p;
p = L->next;
while( (p != NULL) && (p->element != x) )
p = p->next;
return p;
}

DELETE(03,P,NODE)

involved.

Page 9

## 1) Nodes can only be accessed sequentially.

2) Because of the above disadvantage, binary search algorithm cannot be implemented on the

## 3) Only forward traversal is possible.

In DLL, each node has two link fields, one linking in the forward direction and another in
the backward direction and one data field.

Page 10
//Creation of a node in DLL//

struct node

int data;

## struct node *prev;

};

Operations Performed:

Insertion:

## temp=(struct node *)malloc(sizeof(node));

if(temp!=NULL)

temp->data=num;

temp->next=p->next;

temp->next->prev=temp;

p->next=temp;

temp->prev=p; } }

Page 11
Before Insertion:

After Insertion:

## Figure: Insertion in DLL

Deletion Operation:

## void delete(int num, List L)

position p;

p=Find(X, L);

if(isLast(P.L)) {

Page 12
temp=p;

p->prev->next=NULL;

free(temp);

else

temp=p;

p->prev->next=p->next;

p->next->prev=p->prev;

free(temp);

## Figure: Deletion in DLL

1.We can traverse in both directions i.e. from starting to end and as well as from end to starting.

## 2. It is easy to reverse the linked list.

Page 13

1.It requires more space per space per node because one extra field is required for pointer to
previous node.

2. Insertion and deletion take more time than linear linked list because more pointer operations
are required than linear linked list.

In a circularly-linked list the first and last nodes are linked together. This works for both
singly and doubly-linked lists. In a singly-circularly-linked list the last node points to the first
node. In a doubly-circularly-linked list both the last and first nodes point to each other.

In this, the last node does not contain NULL pointer. Instead the last node contains a
pointer that has the address of first node and thus points back to the first node.

1. If we are at a node, then we can go to any node. But in linear linked list it is not possible to go
to previous node.
2. It saves time when we have to go to the first node from the last node. It can be done in single
step because there is no need to traverse the in between nodes. But in double linked list, we will
have to go through in between nodes.

## 1. It is not easy to reverse the linked list.

2. If proper care is not taken, then the problem of infinite loop can occur.
3. If we at a node and go back to the previous node, then we can not do it in single step.

Instead we have to complete the entire circle by going through the in between nodes and
then we will reach the required node

Page 14

## Figure: Doubly Circular Linked List

3.4-APPLICATION OF LISTS:
Multi-list.

We can define an abstract data type for single-variable polynomials (with nonnegative
exponents) by using a list. Let ( ) . If most of the coefficients ai are non-zero, we
can use a simple array to store the coefficients. An example of a single variable polynomial:

4x6 + 10x4 - 5x + 3

## - degree of polynomial = the largest exponent in a polynomial.

Page 15
p( x) a1 x e1 ... an x en

20 5
Polynomials A(X)=3X +2X +4,
4 3 2
B(X)=X +10X +3X +1
How to implement this?

## Array (not recommended)

Array Impementation:

## p3(x) = 16x21 - 3x5 + 2x + 6

Page 16
Ignoring the time to initialize the output polynomials to zero, the running time of the
multiplication routine is proportional to the product of the degree of the two input polynomials.

typedef struct
{
int coeff_array[ MAX_DEGREE+1 ];
unsigned int high_power;
} *POLYNOMIAL;

## Routine-Type declarations for array implementation of the polynomial ADT

An alternative is to use a singly linked list. Each term in the polynomial is contained in
one cell, and the cells are sorted in decreasing order of exponents. For instance, the linked lists in
foll Figure:a represent p1(x) and p2(x). We could then use the declarations in Figure 3.23.

void
zero_polynomial( POLYNOMIAL poly )
{
unsigned int i;
for( i=0; i<=MAX_DEGREE; i++ )
poly->coeff_array[i] = 0;
poly->high_power = 0;
}

## Figure: a Procedure to initialize a polynomial to zero

Page 17
Polynomial Add(poly1, poly2) ::= return the polynomial
poly1 +poly2
Polynomial Mult(poly1, poly2) ::= return the polynomial
poly1 poly2

void
add_polynomial( POLYNOMIAL poly1, POLYNOMIAL poly2, POLYNOMIAL poly_sum)
{
int i;
zero_polynomial( poly_sum );
poly_sum->high_power = max( poly1->high_power, poly2->high_power);
for( i=poly_sum->high_power; i>=0; i-- )
poly_sum->coeff_array[i] = poly1->coeff_array[i] + poly2->coeff_array[i];
}

## Figure b Procedure to add two polynomials

void
mult_polynomial(POLYNOMIAL poly1, POLYNOMIAL poly2, POLYNOMIAL poly_prod )
{
unsigned int i, j;
zero_polynomial( poly_prod );
poly_prod->high_power = poly1->high_power + poly2->high_power;
if( poly_prod->high_power > MAX_DEGREE )
error("Exceeded array size");
else
for( i=0; i<=poly->high_power; i++ )
for( j=0; j<=poly2->high_power; j++ )
poly_prod->coeff_array[i+j] += poly1->coeff_array[i] * poly2->coeff_array[j];
}

Page 18

## only good for non-sparse polynomials.

ease of storage and retrieval.

## have to allocate array size ahead of time.

huge array size required for sparse polynomials. Waste of space and runtime.

## p2(x) = 4x6 + 10x4 + 12x + 8

Node Structure:

Page 19
Adding polynomials using a Linked list representation: (storing the result in p3)

## Case 3: exponent of p1 = exponent of p2

Create a new node in p3 with the same exponent and with the sum of the
coefficients of p1 and p2.

Page 20
Page 21
typedef struct node *node_ptr;

struct node
{
int coefficient;
int exponent;
node_ptr next;
};
typedef node_ptr POLYNOMIAL; /* keep nodes sorted by exponent */

Figure e Type declaration for linked list implementation of the Polynomial ADT

## //Creation of the polynomial//

{
POLYNOMIAL *p;
{
}
else
{
while(p->next!=NULL)
p=p->next;
p->next=new;
}
}

Page 22
{
POLYNOMIAL *p1, *p2, *new1;
p1=list 1;
p2=list2;
while(p1!=NULL && p2!=NULL)
{
new1=malloc(sizeof(struct POLYNOMIAL));
}
if(p1->exp==p2->exp)
{
new1->coef=p1->coef+p2->coef;
new1->exp=p1->exp;
new1->next=NULL;
list3=create(list3, new1);
}
else if(p1->exp>p2->exp)
{
new1->coef=p1->coef;
new1->exp=p1->exp;
new1->next=NULL;
list3=create(list3, new1);
p1=p1->next;
}
else
{
new1->coef=p2->coef;
new1->exp=p2->exp;
new1->next=NULL;
list3=create(list 3, new1);

Page 23
p2=p2->next;
}
}

The operations would then be straightforward to implement. The only potential difficulty
is that when two polynomials are multiplied, the resultant polynomial will have to have like
terms combined.

save space (dont have to worry about sparse polynomials) and easy to maintain.
dont need to allocate list size and can declare nodes (terms) only as needed

## cant go backwards through the list.

Easy implementation

## Disadvantage: waste space when sparse

sometimes known as card sort, because it was used, until the advent of modern computers, to
sort old-style punch cards.

## If we have n integers in the range 1 to m (or 0 to m - 1) 9, we can use this information to

obtain a fast sort known as bucket sort. We keep an array called count, of size m, which is
initialized to zero. Thus, count has m cells (or buckets), which are initially empty. When ai is

Page 24
read, increment (by one) count[ai]. After all the input is read, scan the count array, printing out a
representation of the sorted list.

Pass-1

10 15

## 80 174 25 256 187 8

------------------------------------------------------------------------------------------------------------

0 1 2 3 4 5 6 7 8 9

Pass-II

## i/p: 80 10 174 25 15 256 187 8

15 187

08 10 25 256 174 80

0 1 2 3 4 5 6 7 8 9

Page 25
Pass-III

080

025

015

010 187

## 008 174 256

0 1 2 3 4 5 6 7 8 9

## After Pass-III: 8 10 15 25 25 80 174 187 256

3.4.3-MULTILIST

In a general multi-linked list each node can have any number of pointers to other nodes,
and there may or may not be inverses for each pointer. The standard use of multi-linked lists is to
organize a collection of elements in two different ways. For example, suppose my elements
include the name of a person and his/her age. e.g.

## (FRED,19) (MARY,16) (JACK,21) (JILL,18)

I might want to order these elements alphabetically and also order them by age. I would
have two pointers - NEXT-alphabetically, NEXT-age - and the list header would have two
pointers, one based on name, the other on age.

Page 26
A list can have two pointers without having a backward pointer. For instance, we may
want to keep a set of data ordered on more than one "key". A key is a unique data item included
in a record which distinguishes one record from all other records included in the list. Suppose
we want to be able to access customer accounts in order by account number (integer) and by
customer name (string). We can in fact have one list that is ordered both ways. We need two
pointer fields. Each node of the list will have the form:

Page 27
Insertion and deletion require about twice the work since two sets of pointers must be
adjusted: one for the name and one for the account number. Essentially, you perform the same
adjustments as in a singly linked list but you do it twice.

## 3.5.1/*Merging of linked lists with sorted data*/

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>

## typedef struct node

{ int data;
struct node *next;
}node;
node *merge(node *l1,node *l2);
node *create_normal();
node *create_sorted();
void main()
clrscr();

Page 28
printf("\nFinal List:");
getch();
}
node *merge(node *l1,node *l2)
{ node *l,*p;
l=NULL;
while(l1!=NULL && l2!=NULL)
{ if(l1->data < l2->data)
{ if(l==NULL)
{ l=p=l1;
l1=l1->next;
}
else
{ p->next=l1;
l1=l1->next;
p=p->next;
}
}
else
{ if(l==NULL)
{ l=p=l2;
l2=l2->next;
}
else
{ p->next=l2;
l2=l2->next;
p=p->next;
}
}
}
if(l1!=NULL)
{ if(l==NULL)
l=l1;
else
p->next=l1;
}
if(l2!=NULL)
{ if(l==NULL)
l=l2;
else
p->next=l2;

Page 29
}
return(l);
}
node *create_normal()
int n,x,i;
printf("\nNumber of nodes:");
scanf("%d",&n);
printf("\nEnter data:");
for(i=1;i<=n;i++)
{ scanf("%d",&x);
p->next=NULL;
}
else
{p->next=(node*)malloc(sizeof(node));
p=p->next;
p->next=NULL;
}
p->data=x;
}
}
node *create_sorted()
int n,x,i;
printf("\nNumber of nodes:");
scanf("%d",&n);
printf("\nEnter data:");
for(i=1;i<=n;i++)
{ scanf("%d",&x);
p=(node*)malloc(sizeof(node));
p->data=x;
p->next=NULL;
}
else
while(q->next !=NULL && x>q->next->data)
q=q->next;
p->next=q->next;
q->next=p;
}

Page 30
}
}
{ printf("\n");
}
}
{ int i,j,n,temp;
node *p;
/*counting number of nodes*/
n++;
for(i=1;i<n;i++)
for(j=0;j<n-i;j++)
{if(p->data > p->next->data)
{ temp=p->data;
p->data=p->next->data;
p->next->data=temp;
}
p=p->next;
}
}
}
/*
OUTPUT:-

Number of nodes:2

Enter data:42 12

Number of nodes:3

Enter data:12 68 41

42 12

Page 31
12 42
12 41 68
Final List:
12 12 41 42 68

## #include < stdio.h >

#include < conio.h >
#include < alloc.h >
#define newnode (struct node*) malloc(sizeof(struct node))
struct node
{
int data;
struct node *next;
struct node *prev;
};
struct node *create_list();
struct node *join_list(struct node *f1, struct node *f2);
void main()
{
struct node *f1,*f2,*f3;
f1 = f2 = NULL;
clrscr();
printf("\nEnter first list\n");
f1 = create_list();
printf("\nEnter second list\n");
f2 = create_list();
printf("\n First list is\n");

Page 32
print_list(f1);
printf("\n Second list is\n");
print_list(f2);
f3 = join_list(f1,f2);
printf("\nThe resultant list is \n");
print_list(f3);
} // main

## struct node *create_list()

{
struct node *f,*c,*p;
int tdata;
f = NULL;
printf("\n Enter data ( use 0 to exit ) : ");
scanf("%d",&tdata);
while( tdata != 0 )
{
c = newnode;
if( c == NULL)
{
printf("\n Insuf. mem. ");
exit(0);
}
c->data = tdata;
c->next = NULL;
c->prev = NULL;
if( f== NULL)
f = c;
else
{
p->next = c;

Page 33
c->prev = p;
}
p = c;
printf("\n Enter data ( use 0 to exit ) : ");
scanf("%d",&tdata);
} //while
f->prev = c;
c->next= f;
return(f);
} // create list

## print_list( struct node *f)

{
struct node *t;

if( f == NULL)
{
printf("List is empty");
return;
}
printf("%4d",f->data);
t = f->next;
while ( t != f)
{
printf("%4d",t->data);
t = t->next;
}
return;
}

Page 34
struct node *join_list(struct node *f1, struct node *f2)
{
struct node *t1,*t2;

## if( f1 == NULL && f2 == NULL)

return(NULL);
else
if( f1 != NULL && f2 == NULL)
return(f1);
else
if( f1 == NULL && f2 != NULL)
return(f2);
else
{
t1 = f1->prev;
t2 = f2->prev;
t1->next = f2;
f2->prev = t1;
f1->prev = t2;
t2->next = f1;
return(f1);
}
}

Page 35
Program Input

Program Output

REFERENCE:
Mark Allen Weiss, Data Structures and Algorithm Analysis in C, 2nd Edition, Pearson
Education, 1997.

Page 36
EXPECTED ANNA UNIVERSITY PART-B QUESTIONS

1.What is a linked list? Explain with suitable program segments any four
operations of a linked list. (12)
2.Explain polynomial manipulation using linked lists with an example

## 4.Explain the following operations in a doubly linked list.

(i) Insert an element (6)
(ii) Delete an element (5)
(iii) Reverse the list. (5)
5.Explain the following operations in a singly linked list.
(i) Insert an element (6)
(ii) Delete an element (5)
(iii) Reverse the list. (5)
6.Explain the operations performed in List ADT with routines.
7.Explain polynomial manipulation using arrays with an example

## 9.Write a C program to implement singly linked list.

10.Write a C program to implement doubly linked list.
11.Write a C program to merge 2 linked lists.
12.Write a C program to add and multiply two polynomials using linked list.

Page 37