1 Basic Data Structure
1 Basic Data Structure
BCS301
What Is Data?
• Data Structures and Algorithms are two of the key aspects of Computer
Science.
• Data Structures allow us to organize and store data, whereas
Algorithms allow us to process that data meaningfully.
• Learning Data Structures and Algorithms will help us become better
Programmers.
• We will be able to write code that is more effective and reliable.
• We will also be able to solve problems more quickly and efficiently.
Classification of Data Structure
Classification of Data Structure
Characteristics of an Algorithm
• Input: An algorithm has some input values. We can pass 0 or some input value to an algorithm.
• Output: We will get 1 or more output at the end of an algorithm.
• Unambiguity: An algorithm should be unambiguous which means that the instructions in an algorithm should be
clear and simple.
• Finiteness: An algorithm should have finiteness. Here, finiteness means that the algorithm should contain a limited
number of instructions, i.e., the instructions should be countable.
• Effectiveness: An algorithm should be effective as each instruction in an algorithm affects the overall process.
• Language independent: An algorithm must be language-independent so that the instructions in an algorithm can be
implemented in any of the languages with the same output.
Algorithm Analysis
The algorithm can be analyzed in two levels, i.e., first is before creating the algorithm, and second is after creating the
algorithm. The following are the two analysis of an algorithm:
• Priori Analysis: Here, priori analysis is the theoretical analysis of an algorithm which is done before implementing
the algorithm. Various factors can be considered before implementing the algorithm like processor speed, which has
no effect on the implementation part.
When? Done before coding the algorithm.
How? Analyze the algorithm using mathematical calculations and logical reasoning.
Goal: Predict the algorithm's efficiency regardless of computers or programming languages.
Example: Say you design a sorting algorithm and, on paper, you determine that it uses two nested
loops—it will have a time complexity of O(n²).
• Posterior Analysis: Here, posterior analysis is a practical analysis of an algorithm. The practical analysis is achieved
by implementing the algorithm using any programming language. This analysis basically evaluate that how much
running time and space taken by the algorithm.
When? Done after implementing the algorithm in code.
How? Run the code on a real computer, measure actual run time and memory usage.
Goal: See how the algorithm performs in practice, considering hardware, compiler, and language
used.
Example: You write and run your sorting algorithm in Python, measure how many seconds it takes to
sort 1,000, 10,000, 100,000 items, and check how much RAM is used.
Algorithm Complexity
The performance of the algorithm can be measured in two factors:
Time complexity: The time complexity of an algorithm is the amount of time required to complete
the execution. The time complexity of an algorithm is denoted by the big O notation. Here, big O
notation is the asymptotic notation to represent the time complexity. The time complexity is
mainly calculated by counting the number of steps to finish the execution.
sum=0;
for i=1 to n
Space complexity: An algorithm's space complexity is the amount of sum=sum+i;
space required to solve a problem and produce an output. Similar to the return sum;
time complexity, space complexity is also expressed in big O notation.
The more accurate statement is: Big O, Omega, and Theta are notations
used to describe the upper, lower, and tight bounds of an algorithm's
performance in its best, average, or worst-case scenario.
Parameter Big O Notation O Omega Notation (Ω) Theta Notation (Θ)
Describes an upper bound on the time or space Describes a lower bound on the time or Describes both an upper and a lower
Definition
complexity of an algorithm. space complexity of an algorithm. bound on the time or space complexity.
Indicates the maximum rate of growth of the Indicates the minimum rate of growth of Indicates the exact rate of growth of the
Interpretation
algorithm's complexity. the algorithm's complexity. algorithm's complexity.
It is commonly used to analyze efficiency, Used to demonstrate the effectiveness Used to provide a precise analysis of
Usage in Algorithm Analysis
especially concerning worst-case performance. under optimal conditions. algorithm efficiency in typical scenarios.
A tradeoff is a situation where one thing increases and another thing decreases. It is a way to solve a problem in:
• Either in less time and by using more space, or
• In very little space by spending a long amount of time.
The best Algorithm is that which helps to solve a problem that requires less space in memory and also takes less time
to generate the output.
Abstract Data type (ADT) is a type (or class) for objects whose behavior is defined by a set of values and a set of
operations. The definition of ADT only mentions what operations are to be performed but not how these operations
will be implemented. It does not specify how data will be organized in memory and what algorithms will be used for
implementing the operations. It is called “abstract” because it gives an implementation-independent view.
Array in Data Structure
Arrays are defined as the collection of similar types of data items stored at contiguous memory
locations.
In C programming, they are the derived data types that can store the primitive type of data such
as int, char, double, float, etc.
Properties of array
There are some of the properties of an array that are listed as follows –
• Each element in an array is of the same data type and carries the same size that is 4 bytes.
• Elements in the array are stored at contiguous memory locations from which the first
element is stored at the smallest memory location.
• Elements of the array can be randomly accessed since we can calculate the address of each
element of the array with the given base address and the size of the data element.
Traversal operation
#include <stdio.h>
void main() {
int Arr[5] = {18, 30, 15, 70, 12};
int i;
printf("Elements of the array are:\n");
for(i = 0; i<5; i++) {
printf("Arr[%d] = %d, ", i, Arr[i]);
}
}
Insertion operation Deletion operation
#include <stdio.h> #include <stdio.h>
int main()
{ void main() {
int arr[] = {18, 30, 15, 70, 12};
int arr[20] = { 18, 30, 15, 70, 12 }; int k = 30, n = 5;
int i, x, pos, n = 5; int i, j;
printf("Array elements before insertion\n");
for (i = 0; i < n; i++) printf("Given array elements are :\n");
printf("%d ", arr[i]);
printf("\n"); for(i = 0; i<n; i++) {
printf("arr[%d] = %d, ", i, arr[i]);
}
x = 50; // element to be inserted
pos = 4; j = k;
n++;
while( j < n) {
for (i = n-1; i >= pos; i--) arr[j-1] = arr[ j];
arr[i] = arr[i - 1]; j = j + 1;
arr[pos - 1] = x; }
printf("Array elements after insertion\n"); n = n -1;
for (i = 0; i < n; i++)
printf("%d ", arr[i]); printf("\nElements of array after deletion:\n");
printf("\n");
return 0; for(i = 0; i<n; i++) {
} printf("arr[%d] = %d, ", i, arr[i]);
}
}
Search operation Update operation
#include <stdio.h> #include <stdio.h>
void main() {
int arr[5] = {18, 30, 15, 70, 12}; void main() {
int item = 70, i, j=0 ; int arr[5] = {18, 30, 15, 70, 12};
int item = 50, i, pos = 3;
printf("Given array elements are :\n");
printf("Given array elements are :\n");
for(i = 0; i<5; i++) {
printf("arr[%d] = %d, ", i, arr[i]); for(i = 0; i<5; i++) {
}
printf("\nElement to be searched = %d", item);
printf("arr[%d] = %d, ", i, arr[i]);
while( j < 5){ }
if( arr[j] == item ) {
break; arr[pos-1] = item;
} printf("\nArray elements after updation :\n");
Answer:
w = 2, b = 1000, i = 35
Address(A[i]) = b + w * (i - lb)
Address A[35] = 1000 + 2 * (35 - 0)
= 1000 + 2 * 35
= 1070
Q-2: Let the base address of the first element of an array be 400, and each
element of an array occupies 2 bytes in memory. Then find the address of the 4th
element in the array A[10].
Q-2: Let the base address of the first element of an array be 400, and each
element of an array occupies 2 bytes in memory. Then find the address of the 4th
element in the array A[10].
Solution:
i = 3, b= 400, lb = 0, w = 2
Address(A[3]) = 400 + 2 * [3 - 0]
= 400 + 6
= 406
Q-3: A[-25, +15] and Base address = 1000. Size of each element is 10,
and find the address of A[60].
Q-3: A[-25, +15] and Base address = 1000. Size of each element is 10,
and find the address of A[60].
Ans:
Address(A[i]) = b+ w * (i - lb)
Here i = 60, b= 1000, w = 10, lb = -25
Address(A[60]) = 1000 + 10 * [60 - (-25)]
= 1000 + 10 * [60 + 25]
= 1000 + 10 * 85
= 1850
• Q-4: Consider the linear array A[-5:30]. If the base address is 150 and
space required to store each element is 2 words, then calculate the
address of A[15].
Ans: ???
• Q-4: Consider the linear array A[-5:30]. If the base address is 150 and
space required to store each element is 2 words, then calculate the
address of A[15].
Ans: 190
• Q-5: Consider the linear array A[200:256]. If the base address is 200
and space required to store each element is 3 words of memory, then
the address of A[215], A[241], and A[266] is
Ans: ????
• Q-5: Consider the linear array A[200:256]. If the base address is 200
and space required to store each element is 3 words of memory, then
the address of A[215], A[241], and A[266] is
• Linear arrays are static structures, i.e., memory used by them cannot be
reduced or extended.
• Since the elements of these arrays are stored in consecutive locations, the
insertions and deletions in these arrays are time-consuming.
MULTI-DIMENSIONAL ARRAYS
An array can be of more than one dimension. There are
no restrictions to the number of dimensions that we
can have.
Syntax:
Datatype ArrayName [row-size][column-size];
Example:
int A[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
int a[][3] = {------------}; ✔
Int a[3][]= X
A11,A12,A13,A14,A15,A16,A21,A22,A23,A24,A25,A26,A31,…,A56
• Column-Major Representation
{a, e, i, b, f, j, c, g, k, d, h, l}
Q. Show how the matrix
would appear in memory
when stored in:
(a) Row-major order
(b) Column-major order
• Solution
Q . A 2D array with 2 rows and 3 columns stands in memory as: 853
726
Show the matrix form of 2 dimensional array
• Solution: Data may be stored in row-major or
column-major order. If the data is stored in row-major
order, then the memory mapping and the matrix form
would be as:
853
726
where i1 is the index of the element along the 1st dimension and i2 is the index along the 2nd dimension.
• Given the dimensions, d1=3 and d2=4 and the indices i1= 2 and i2=3 the index formula
becomes: Index = i_1 × d_2 + i_2
• Index = 2 × 4 + 3 = 11
• 3-D Array:
For a 3-dimensional array with dimensions d1,d2,d3
• Index = i_1 × (d_2 × d_3) + i_2 × d_3 + i_3
where i1 is the index of the element along the 1st dimension, i2 is the index along the 2nd dimension, and i3 is the index along the
3rd dimension.
• ADDRESS CALCULATION FOR 2D ARRAY
• Let us consider a two-dimensional array A of size m×n.
• Like a linear array system, the array keeps track of the address of the first
element only, i.e., the base address of the array (Base(A)). Using the base
address, the computer computes the address of the element in the ith row
and jth column, i.e., LOC(A[i][j]).
(a) Column-Major Order
LOC(A[i][j]) = Base(A) + w[(i - lower bound for column index) + m(j - lower bound for row index)]
Or in general
LOC(A[i][j]) = B+ w[(i-Lr)+m*(j-Lc)] in C/C++
(b) Row-Major Order
LOC(A[i][j]) = Base(A) + w[n(i - lower bound for row index) + (j - lower bound for column index)]
Or in general
LOC(A[i][j]) = B+ w[n(i-Lr)+(J-Lc)] in C/C++
w denotes the number of words per memory location for the array A or the number of bytes per storage location
for one element of the array.
B = Base Address
w = Storage size of an element
hr = Start row index of matrix / lower bound of row
hc = Start column index of matrix / lower bound of column
M = Number of rows in matrix
N = Number of columns in matrix
i = Row subscript of element whose address is to be found
j = Column subscript of the element whose address is to be found
• Q.
A[2][1] =?
Ans.
LOC(A[i][j]) = B+ w[n(i-Lr)+(J-Lc)]
• Here Base(A) = 104
w=2
N = 4, i = 2, j = 1
LOC(A[i][j]) = B+ w[n(i-Lr)+(J-Lc)]
Address of A[2][1] = 104 + 2[4(2 - 0) + (1 - 0)]
= 104 + 2[4 * 2 + 1]
= 104 + 2 * 9
= 104 + 18 = 122
• Q. Column Major order
• Solution:
Given:
Base Address (BA) = 1000
M × N = 20 × 5
w=2
i = 18, j = 4
• Row-major:
• Address of A[i][j] = Base(A) + w[N(i - hr) + (j - hc)]
• = 1000 + 2[5(10 - 0) + (4 - 0)]
• = 1000 + 2[5 * 10 + 4]
• = 1000 + 2 * 54
• = 1000 + 108
• A[10][4] = 1108
• Column-major:
Address of A[i][j] = Base(A) + w[(i - hr) + M * (j - hc)]
= 1000 + 2[(10 - 0) + 20(4 - 0)]
= 1000 + 2[10 + 80]
= 1000 + 2 * 90
A[10][4] = 1180
• Problem 4:
Consider a two-dimensional array A[10][8] which has a base address =
1000 and the number of bytes per element = 2. Compute the address
of element A[8][5] by row-major and column-major order.
• Answer:
Row = 1170
Column = 1116
• Problem 5:
Consider 2D array A[25...79, 55...124]
Base(A) = 1000
Size of each element w = 100
Find the location of A[55][75] by row-major and column-major.
Solution:
A[25...79, 55...124]
Number of rows (lr) = UB₁ - LB₁ + 1 = 79 - 25 + 1 = 55
Number of columns (lc) = UB₂ - LB₂ + 1 = 124 - 55 + 1 = 70