Académique Documents
Professionnel Documents
Culture Documents
2.1 Overview
2.2 Concept of Data Structures
2.3 Design of a Suitable Algorithm
2.4 Algorithm Analysis
2.1 OVERVIEW
It may be noted that elements of list and the procedure represent the
data and program of the problem, respectively.
Now, the efficiency of the program would primarily depend upon the
organization of data. When the data is poorly organized, then the
program cannot efficiently access it. For instance, the time taken to open
the lock of your house depends upon where you have kept the key to it:
in your hand, in front pocket, in the ticket pocket of your pant or the
inner pocket of your briefcase, etc. There may be a variety of motives for
selecting one or the other of these places to keep the key. Key in the hand
or in the front pocket would be quickly accessible as compared to other
places whereas the key placed in the inner pocket of briefcase is
comparatively much secured. For similar reasons, it is also necessary to
Choice I: The various data items related to a student are: name, roll
number, marks, percentage, and grade. The total number of students is
60. Therefore, the simplest choice would be to have as many parallel lists
as there are data items to be represented. The arrangement is
shown Figure 2.4.
roll[i]=roll[j];
roll[j]=temp;
temp=marks[i];
marks[i]=marks[j];
marks[j]=temp;
fTemp=percent[i];
percent[i]=percent[j];
percent[j]=fTemp;
chTemp=grade[i];
grade[i]=grade[j];
grade[j]=chTemp;
Though the above code may work, but it is not only a clumsy way of
representing the data but would require a lot of typing effort also. In fact,
as many as fifteen statements are required to exchange the data of ith
student with that of jth student.
Choice II: From the built-in data structures, the struct can be
selected to represent the data of a student as shown below:
structstudent{
charname[15];
introll;
intmarks;
floatpercent;
chargrade;
};
Similarly, from built-in data structures, an array called studList can
be selected to represent a list. However, in this case each location has to
be of type student which itself is a structure. The required declaration is
given below:
structstudentstudList[60];
It may be noted that the above given array of structures is a user-defined
data structure constructed from two built-in data
structures: struct and array. Now in this case, exchange between data
of ith andjth student would require the following operations:
inti,j;
structstudenttemp;
temp=studList[i];
studList[i]=studList[j];
studList[j]=temp;
Thus, only three statements are required to exchange the data of ith
student with that of jth student.
A comparison of the two choices discussed above establishes that Choice
II is definitely better thanChoice I as far as the selection of data
structures for the given problem is concerned. The number of lines of
code of Choice II is definitely less than the Choice I. Moreover, the code
of Choice II is comparatively easy and elegant.
From the above discussion, it can be concluded that choice of right data
structures is of paramount importance from the point of view of
representing the data belonging to a problem.
2.2.2 Types of Data Structures
A large number of data structure are available to programmers that can
be usefully employed in a program. The data structures can be broadly
classified into two categories: linear and non-linear.
(1) Linear data structures: These data structures represent a
sequence of items. The elements follow a linear ordering. For instance,
one-dimensional arrays and linked lists are linear data structures. These
can be used to model objects like queues, stacks, chains (linked lists),
etc., as shown in Figure 2.5.
For example, in the list of Figure 2.3, the 2nd element (1) is followed by 3rd
element (9) and so on.
Thus, we can say that the algorithm tells the computer when to read
data, compute on it, and write the answers.
While solving problems with the help of computers, the following facts
should be kept in mind:
A location in the main memory has the property: Writing-in is
destructive and Reading-out is non-destructive. In simple words, we
can say that if a value is assigned to a memory location, then its previous
contents will be lost. However, if we use the value of a memory location
then the contents of the memory do not change, i.e., it remains intact.
For example, in the following statement, the value of variables B and C
are being used and their sum is stored in variable A
A=B+C
where, the symbol = is an assignment operator.
If previous values of A, B, C were 15, 45, 20, respectively then after
execution of the above statement, the new contents of A, B, C would be
65, 45, and 20, respectively.
Consider the following statement:
Total = Total + 100;
The abnormal looking statement is very much normal as far as computer
memory is concerned. The statement reveals the following fact:
Old value of variable Total is being added to an integer 100 and the
result is being stored as new value in the variable Total, i.e., replacing
its old contents with the new contents.
After the execution of the statement with old contents of Total (say 24),
the new contents of Total will be 124.
List of numbers
Size of list
Type of numbers to be stored in the list
In which order to be sorted
Output specifications
1. In what order and format the outputs values will be produced?
2. What types of values to be produced with what spacing i.e., decimal spacing,
significant digits, etc.
3. What main headings and column headings to be printed on the output page.
The problem at hand is How to print the table. The first version of the
algorithm is given below:
Algorithm Print_TableVer1.
{
Step1.Printtable
}
When we look at the table, we find that the table is nothing but a
collection of rows and we have to print only 10 rows. So, the problem has
been reduced to printing a row 10 times. The second refined version of
the algorithm is given below:
Algorithm Print_TableVer2.
{
Step
1.Row=1
2.Printtherow
3.Row=Row+1
4.IfRow<=10repeatsteps2and3
5.Stop
}
Now our focus is on how to print a row. A closer look at the problem
suggests that a row is nothing but a collection of columns and we have to
print only 10 columns for each row. The third refined version of the
algorithm is given below:
Algorithm Print_TableVer3.
{
Step
1.Row=1
2.Col=1
2.1Printthecol.
2.2Col=Col+1
2.3IfCol<=10repeatsteps2.1and2.2
2.4Gotoanewline.
3.Row=Row+1
4.IfRow<=10repeatsteps2and3
5.Stop.
}
Now our concern is how to print a column. We find that it is very
simple, i.e., we get the value to be printed by multiplying the values
contained in the variables Row and Col The final version of the refined
algorithm is given below:
Algorithm Print_TableVer4.
{
Step
1.Row=1
2.Col=1
2.1ColVal=Row*Col
2.2PrinttheColVal.
2.3Col=Col+1
2.4IfCol<=10repeatsteps2.1to2.3
2.5Gotoanewline.
3.Row=Row+1
4.IfRow<=10repeatsteps2and3
5.Stop.
}
The programmer stops at this stage where he finds that the step(s) is
trivial and can be easily implemented.
Solution:
Input: Three numbers: Num1,Num2, and Num3
Type of numbers: integer.
Output: Display the biggest number and a message in this regard.
Algorithm Biggest()
{
Step
1.ReadNum1,Num2,Num3;
2.If(Num1>Num2)
2.1If(Num1>Num3)
PrintNum1isthelargest
Else
PrintNum3isthelargest
Else
2.2If(Num2>Num3)
PrintNum2isthelargest
Else
PrintNum3isthelargest
3.Stop
}
(3) Iteration: The iteration structure is used to repeatedly execute a
statement or a block of statements. The loop is repeatedly executed until
a certain specified condition is satisfied.
Example 5: Write an algorithm that finds the largest number from a
given list of numbers.
Solution:
Input: List of numbers, size of list, prompt for input.
Type of numbers: integer.
Output: Display the largest number and a message in this regard.
The most basic solution to this problem is that if there is only one
number in the list then the number is the largest. Therefore, the first
number of the list would be taken as largest. The largest would then be
compared with the rest of the numbers in the list. If a number is found
larger than the current largest, then it is stored in the largest. This
process is repeated till the end of the list. For iteration, For loop can be
employed.
The concerned algorithm is given below:
Algorithm Largest
{
Step
1.PromptEnterthesizeofthelist;
2.ReadN;
3.PromptEnteraNumber;
4.ReadNum;
5.Largest=Num;/*Thefirstnumberisthe
largest*/
6.For(I=2toN)
{
6.1PromptEnteraNumber
6.2ReadNum
6.3If(Num>Largest)Largest=Num
}
7.PromptThelargestNumber=
8.PrintLargest;
9.Stop
}
It may be noted here that if a loop terminates after a number of
iterations, then the loop is called afinite loop. On the other hand if a
loop does not terminate at all and keeps on executing endlessly, then it is
called an infinite loop.
(4) Use of accumulators and counters: Accumulator is a variable
that is generally used to compute sum or product of a series. For
example, the sum of the following list of numbers can be computed by
initializing a variable (say Total) to zero.
The 1st number of the list is added to Total and then the 2nd, 3rd and so
on till the end of the list. Finally, the variable Total would get the
accumulated sum of the list given above.
Example 6: Write an algorithm that reads a list of 50 integer values and
prints the total of the list.
Solution: Let us assume that a variable called sum would be used as an
accumulator. A variable called Num would be used to read a number
from the input list one at time. For loop will be employed to do the
iteration.
The Algorithm is given below:
Algorithm SumList
{
Step
1.Sum=0;
2.For(I=1to50)
{
2.1ReadNum;
2.2Sum=Sum+Num;/*Theaccumulationofthe
list*/
}
3.PromptThesumofthelist=;
4.PrintSum;
5.Stop
}
It may be noted that for product of a series, the accumulator is initialized
to 1.
Counter is a variable used to count number of operations/actions
performed in a loop. It may also be used to count number of members
present in a list or a set of items.
The counter variable is generally initialized by 0. On the occurrence of an
event/operation, the variable is incremented by 1. At the end of the
counting process, the variable contains the required count.
Example 7: Write an algorithm that finds the number of zeros present
in a given list of N numbers.
Solution: A counter variable called Num_of_Zeros would be used to
count the number of zeros present in a given list of numbers. A variable
called Num would be used to read a number from the input list one at
time. For loop will be employed to do the iteration.
The Algorithm is given below:
Algorithm Count_zeros()
{
Step
1.Num_of_zeros=0;
2.For(I=1toN)
{
2.1ReadNum;
2.2If(Num==0)
Num_of_zeros=Num_of_zeros+1;
}
3.PromptThenumberofzeroelements=;
4.PrintNum_of_zeros;
5.Stop
}
Example 8: Write a program that computes the sum of first N multiples
of an integer called K, i.e.
sumSeries = 1*K + 2*K + 3*K + N*K
Solution: An accumulator called sumSeries would be used to
compute the required sum of the series. As the number of steps are
known (i.e., N), For loop is the most appropriate for the required
computation. The index of the loop will act as the counter.
Input: N, K
Output: sumSeries
/*Thisprogramcomputesthesumofaseries*/
#include<stdio.h>
voidmain()
{
intsumSeries,i;
intN;/*Numberofterms*/
intK;/*Theintegermultiple*/
printf(\nEnterNumberoftermsandInteger
Multiple);
scanf(%d%d,&N,&K);
sumSeries=0;/*Accumulatorinitialized*/
For(i=1;i<=N;i++)
{
sumSeries=sumSeries+i*K;
}
printf(\nThesumoffirst%dterms=%d,N,
sumSeries);
}
In fact, it can be concluded that irrespective of the programming
paradigms, a general algorithm is designed based on following
constructs:
1. Sequence structure: Statement after statements are written in sequence
in a program.
A critical look at the above discussion indicates that the data structures
and algorithms are related to each other and have to be studied together.
For a given problem, an algorithm is developed to solve it but the
algorithm needs to operate on data. Unless the data is stored in a
suitable data structure, the design of algorithm remains incomplete. So,
both the data structures and algorithm are important for program
development.
In fact, an algorithm requires following two resources:
1. Memory space: Space occupied by program code and the associated data
structures.
2. CPU time: Time spent by the algorithm to solve the problem.
where c>0.
(2.1)
From above relation, we can say that for a large value of n, the function
g provides an upper bound on the growth rate T.
Let us now consider the various constructs used by a programmer to
write an algorithm.
(1) Simple statement: Let us assume that a statement takes a unit
time to execute, i.e., 1. Thus, T(n) = 1 for a simple statement. To satisfy
the Big-Oh condition, the above relation can be rewritten as shown
below:
T(n) <= 1*1
{
Step
1.Readbase,height;
2.Area=0.5*base*height;
3.PrintArea;
4.Stop
}
The above algorithm takes four steps to complete.
Thus, T(n) = 4.
To satisfy the relation 2.1, the above relation can be rewritten as:
T(n) <= 4*1
where c = 4 and n0 = 0.
= 4 (Steps 1, 3, 4, 5)
=1
= 3 (1 comparison, 1 addition, 1
assignment)
where c = 4, n0 >= 4
Hence, the given algorithm has time complexity of the order of N, i.e.,
O(N). This indicates that the term 4 has negligible contribution in the
expression: 3*N + 4.
Note: In case of nested loops, the time complexity depends upon the
counters of both outer and inner loops. Consider the nested loops given
below. This program segment contains S, a sequence of statements
within nested loops I and J.
For(I=1;I<=N;I++)
{
For(J=1;J<=N;J++)
{
S;
}
}
It may be noted that for each iteration of I loop, the J loop executes N
times. Therefore, for N iterations of I loop, the J loop would execute N*N
= N2 times. Accordingly, the statement S would also execute N2times.
Thus, T(n) = N2
To satisfy the relation 2.1, the above relation can be rewritten as shown
below:
T(n) <= 1 * N2
Comparing the above relation with relation 2.1, we get g(n) = N2.
Therefore, the above relation can be expressed as:
T(n) = O(N2)
Hence, the given nested loop has time complexity of the order of N2, i.e.,
O(N2).
Example 9: Compute the time complexity of the following nested loop:
For(I=1;I<=N;I++)
{
For(J=1;J<=I;J++)
{
S;
}
}
Hence, the given algorithm has time complexity of the order of N2, i.e.,
O(N2). This indicates that the term N/2 has negligible contribution in the
expression N2/2 + N/2.
(4) If-then-else structure: In the if-then-else structure, the then and
else parts are considered separately. Consider the if-then-else structure
given in Figure 2.8.
}
Else
{
For(i=1;i<=N,i++)
{
x=x+i;
}
}
Solution: It may be noted that in the above algorithm, the time
complexity of then and else part are O(1) and O(N), respectively. The
maximum of the two is O(N). Therefore, the time complexity of the
above algorithm is O(N).
Example 11: compute the time complexity of the following relations:
1.
2.
3.
4.
T(n) = 2527
T(n) = 8*n + 17
T(n) = 15*N2 + 6
T(n) = 5*N3 + N2 = 2*N
Solution:
1. T(n) = 2527 <= 2527*1, where c = 2527 and n0 = 0.
= O(1)
Ans. The time complexity = O(1)
Note: All the relations, given in example 10 were polynomials. From the
answers, we can say that any polynomial has the time complexity of BigOh of its leading term with coefficient of 1.
It is also understandable that the Big-Oh does not provide the exact
execution time. Rather, it gives only an asymptotic upper bound of the
execution time of an algorithm.
For different types of functions, the growth rates for different values of
input size n have been tabulated in Table 2.1.
It can be observed from Table 2.1 that for a given input, the growth rate
O(lg n) is faster than O(n lg n). For the same input size, the growth rate
O(N2) is the slowest.
Later in the book, for various algorithms, timing estimates will be
included using Big-Oh notation.
Table 2.1 Growth rates of functions
EXERCISES
1.
2.
3.
4.
5.
6.
7.
8.
i.
ii.
iii.
iv.
v.
Data element
Primitive data types
Data object
Constant
Variable
2.
3.
4.
5.
i.
ii.
iii.
iv.
T(n) = 410
T(n) = 4*n -12
T(n) = 13*N2 -7
T(n) = 3*N3 + N214*N
2.
3.
i.
ii.
iii.
iv.
for(inti=0;i<n;i++)
{
for(intj=0;j<n;j++)
{
statement;
}
}
for(inti=0;i<n;i++)
{
for(intj=i+1;j<n;j++)
{
statement;
}
}
for(inti=0;i<n;i++)
{
for(intj=n;j>i;j)
{
statement;
}
}
for(inti=0;i<n;i++)
{
for(intj=0;j<m;j++)
{
statement1;
}
statement2;
}
2.
if(a==b)
statement1;
elseif(a>b)
statement2;
else
statement3;