0% found this document useful (0 votes)
13 views129 pages

Programming With Data Structure

The document outlines a course on programming with data structures, detailing three modules covering arrays, pointers, stacks, queues, linked lists, trees, sorting, and searching techniques. It defines key concepts such as data, information, entities, attributes, and various types of data structures, including primitive and non-primitive types. Additionally, it discusses algorithms, their efficiency, and complexity, emphasizing the importance of analyzing both time and space requirements for effective programming.

Uploaded by

Aman Verma
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
13 views129 pages

Programming With Data Structure

The document outlines a course on programming with data structures, detailing three modules covering arrays, pointers, stacks, queues, linked lists, trees, sorting, and searching techniques. It defines key concepts such as data, information, entities, attributes, and various types of data structures, including primitive and non-primitive types. Additionally, it discusses algorithms, their efficiency, and complexity, emphasizing the importance of analyzing both time and space requirements for effective programming.

Uploaded by

Aman Verma
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 129

Programming with Data Structure

Dr. Dharm Raj Singh


Assistant Professor, (HOD)
Department of Computer Application
JagatpurP. G. College, Varanasi
Mobile No. 9452070368, 7275887513
Email- [email protected]
Outline
1. MODULE 1
• Unit 1 : Array
• Unit 2 :pointer
• Unit 3 : Stacks and Queues
2. MODULE 2
• unit 1 : linked lists
• unit 2 : Trees
• unit 3 : B-Trees
3. MODULE 3
• Unit 1 : Sorting Techniques
• Unit 2 : Searching Techniques
Basic terminology
Data: data are simply values or sets of values. A data item refers to a single
unit of values. Data is a collection of facts and figures.
• The data items are then classified into sub-items, which is the group of items that
are not known as the simple primary form of the item.
• Let us consider an example where an employee name can be broken down into
three sub-items: First, Middle, and Last. However, an ID assigned to an employee
will generally be considered a single item.
• In the example data items are ID, Age, Gender, First, Middle, Last, Street,
Locality, etc., are elementary data items. In contrast, the Name and the Address
are group data items.
Basic terminology
Information: information is the manipulation of data which have meaningful
or processed data.
Entity : An entity is something that has certain attributes or properties which
may be assigned values. For example employee of a given organization,
students.
Attributes or Field: Name Age Sex Emp_ID
Rohit 35 M 101
Values or Records: Mohit 32 M 102
Ramesh 40 M 103
Entity Set: Entities with similar attributes form an entity set. e.g. all the
employees in an organization.
Field: A single elementary unit of information symbolizing the Attribute of an
Entity is known as Field.
Record: record is a collection of related information. A record is the collection
of field values of a given entity.
File: a file is the collection of related records of the entities in a given entity
set.
Database: database is a collection of related file.
Introduction to Data Structures
 A data type is a well-defined collection of data with a well-defined set of
operations on it.
 A data structure is an actual implementation of a particular abstract data
type.
 Data structure is the structural representation of logical relationships
between elements of data.
 Data structure is a representation of the logical relationship existing
between individual elements of data.
 Data Structure is a way of organizing all data items that considers not only
the elements stored but also their relationship to each other.
 We can also define data structure as a mathematical or logical model of
a particular organization of data items.
 The representation of particular data structure in the main memory of a
computer is called as storage structure.
 The storage structure representation in auxiliary memory is called as file
structure.
Data Structure mainly specifies the following four things

 Organization of Data
 Accessing methods
 Degree of associativity
 Processing alternatives for information
 Algorithm + Data Structure = Program
 Data structure study covers the following points
 Amount of memory require to store.
 Amount of time require to process.
 Representation of data in memory.
 Operations performed on that data.
Data organization
• Organization of data refers to classifying and organizing data to
make it more meaningful and usable.
• The collection of data you work with in a program have some kind
of structure or organization of data in Data Structures. No matter
how complex your data structures are they can be broken down into
two fundamental types.
1. Contiguous
2. Non-Contiguous
• In contiguous structures, terms of data are kept together in memory
(either RAM or in a file). An array is an example of a contiguous
structure.
• In contrast, items in a non-contiguous structure and scattered in
memory, but we linked to each other in some way. A linked list is
an example of a non-contiguous data structure.
Classification of Data Structure
Primitive Data Structure
• Primitive data structures are basic structures and are directly operated
upon by machine instructions.
• Primitive data structures have different representations on different
computers.
• The storage structure of these data structures may vary from one machine
to another.
• Integers, floats, character and pointers are examples of primitive data
structures.
Non primitive Data Type
1. Non-Primitive Data Structures are those data structures derived from
Primitive Data Structures.
2. These data structures can't be manipulated or operated directly by
machine-level instructions.
3. The focus of these data structures is on forming a set of data elements
that is either homogeneous or heterogeneous data types. Examples of
Array, File, strings, Unions, linked lists, stacks and queues etc. we can
divide these data structures into two sub-categories -
• Linear Data Structures
• Non-Linear Data Structures
Linear data structures
• A data structure is said to be linear if and only if there is a
adjacency relationship between the elements. or in sequence
memory locations.
• There are two ways to represent a linear data structure in
memory,
– Static memory allocation
– Dynamic memory allocation
• The possible operations on the linear data structure are:
Traversal, Insertion, Deletion, Searching, Sorting and
Merging.
• Examples of Linear data structure are arrays, linked list,
Stack and Queue etc.
Nonlinear data structures
• Nonlinear data structures are those data structure in which data
items are not arranged in a sequence.
• A data structure in which insertion and deletion is not possible in a
linear fashion and Elements are stored based on the hierarchical
relationship among the data.
• Examples of Non-linear Data Structure are Tree and Graph.
Tree: A tree can be defined as finite set of data items (nodes) in which
data items are arranged in branches and sub branches according
to requirement.
• Trees represent the hierarchical relationship between various
elements.
• Tree consist of nodes connected by edge, the node represented by
circle and edge represented by line.
Graph: Graph is a collection of nodes (Information) and connecting
edges (Logical relation) between nodes.
Operation on Data Structures
• Some of the common operations on Non-Primitive Data
Structure are:
1. Create: The create operation results in reserving memory for
program elements. This can be done by declaration statement.
Creation of data structure may take place either during
compile-time or run-time.
2. Destroy / delete: Destroy operation destroys memory space
allocated for specified data structure. free() function of
C language is used to destroy data structure.
• It is the process of removing an item from the structure.
3. Selection: Selection operation deals with accessing a
particular data within a data structure.
4. Updation: It updates or modifies the data in the data structure.
5. Traversal: Traversal is a process of visiting each and every
node of a list in systematic manner.
6. Searching: It is the process of finding the location of the
element with a given key value in a particular data structure
or finding the location of an element, which satisfies the
given condition.
7. Sorting: It is the process of arranging the elements of a
particular data structure in some form of logical order. The
order may be either ascending or descending or alphabetic
order depending on the data items present.
8. Merging: Merging is a process of combining the data items
of two different sorted list into a single sorted list.
9. Insertion: It is the process of adding a new element to the
structure. Most of the times this operation is performed by
identifying the position where the new element is to be
inserted.
10. Splitting: Splitting is a process of partitioning single list to
multiple list.
ALGORITHM
• A set of ordered steps or procedures necessary to solve a
problem.
• An algorithm is a sequence of unambiguous instructions for
solving a problem.
• An algorithm is a finite set of instructions that, it followed,
accomplishes a particular task. In additions, all algorithms
must satisfy the following criteria:
1. Input: Zero or more quantities are externally supplied.
2. Output: At least one quantities is produced.
3. Definiteness: Each instructions is clear and unambiguous.
4. Finiteness: if we trace out the instructions of an algorithm, then
for all cases, the algorithm terminates after a finite number of steps.
5. Effectiveness: Every instructions must be very basic so that it can
be carried out, in principle, by a person using only pencil and paper.
It is not enough that each operations be definite as in criterion 3; it
also must be feasible.
Basic Statements Used and Examples
 Algorithm always begins with the word ‘Start’ and ends with
the word ‘Stop’.
 Step wise solution is written in distinguished steps. This is as
shown in
example
Start
Step 1:
Step 2:
.
.
.
Step n:
End
 Input Statement: Algorithm takes one or more inputs to process.
The statements used to indicate the input is Read a or Input b. for
example
Let a , b be the names of the Input
Input a or Read a
Input b or Read b
Where a and b are variable names.
 Output Statements: Algorithm produces one or more outputs.
The statement used to show the output is output b or print b.
Syntax: Output variable name
Print variable name
For example output a or print a
output b or print b
where a and b are variable names.
 Assignment Statements:
Processing can be done using the assignment statement.
i.e. L.H.S = R.H.S
On the L.H.S is a variable.
While on the R.H.S is a variable or a constant or an expression.
• The value of the variable, constant or the expression on the R.H.S is
assigned in L.H.S.
 The L.H.S and R.H.S should be of the same type. Here ‘ = ’ is
called assignment operator.
For example Let the variables be x, y. The product be z this can be
represented by as Read x, y
Z=x*y
 Order in which the steps of an algorithm are executed is divided in to
3 types namely
i) Sequential Order
ii) Conditional Order
iii) Iterative Order
 Sequential Order
Each step is performed in serial fashion i.e. in a step by step procedure
for example
Write an algorithm to add two numbers.
Step 1 : Start
Step 2 : Read a
Step 3 : Read b
Step 4 : Add a , b
Step 5 : Store in d
Step 6 : Print d
Step 7 : End
Conditional Order
Based on fact that the given condition is met or not the algorithm
selects the next step to do. If statements are used when decision has
to be made. Different format of if statements are available they are
a) Syntax : if (condition)
Then {set of statements S1}
• Here condition means Boolean expressions which is TRUE or
FALSE.
• If condition is TRUE then the statements S1 is evaluated.
• If FALSE S1 is not evaluated Programme skips that section.
• For example
Write an algorithm to check equality of numbers.
Step 1 : Start
Step 2 : Read a, b
Step 3 : if a = =b, print numbers are equal to each other
Step 4 : End
b) if else (condition) statement:
if (condition)
Then {set of statements S1}
else
Then {set of statements S2}
Here if condition evaluates to true then S1 is executed otherwise
else statements are executed. For example Write an algorithm to
print the grade.
Step 1 : Start
Step 2 : Read marks
Step 3 : if marks greater than 60 is TRUE
print ’GRADE A’
Step 4 : Other wise
print ’GRADE B’
Step 5 : End
iii) Iterative Order
Here algorithm repeats the finite number of steps over and
over till the condition is not meet. Iterative operation is also
called as looping operation. For example
Add ‘n’ natural numbers till the sum is 5.
Step 1 : Start
Step 2 : set count to 0 and i=1
Step 3 : add i to count
Step 4 : i=i+1
Step 5 : if count is less than 5, then repeat steps 3 & 4
Step 6 : otherwise print count
Step 7 : End
 The range of inputs for which an algorithm works has to be specified
carefully.
– The same algorithm can be represented in several different ways.
– Several algorithms for solving the same problem may exist.
– Algorithms for the same problem can be based on very different
ideas and can solve the problem with dramatically different speeds.
 Every problem as we understand can be solved using different
methods or techniques.
 Thus each method may be represented using an algorithm.
 The important question to answer is How to choose the best algorithm?
• Once we develop an algorithm, it is always better to check whether
the algorithm is efficient or not. The efficiency of an algorithm
depends on the following factors:
1. Accuracy of the output
2. Robustness of the algorithm
3. User friendliness of the algorithm
4. Time required to run the algorithm
5. Space required to run the algorithm
 The main aim of using a computer is to transform data from one
form to another. The algorithm describes the process of
transforming data
 Efficiency of algorithms depends upon the data structures that are
selected for data representation.
 The data structure has to be finally represented in the memory.
This is called as memory representation of data structures. While
selecting the memory representation of data structures it should
worth memory space and it should also be easy to access.
COMPLEXITY OF ALGORITHM
• Every algorithm we write should be analyzed before it is implemented
as a program.
• There are two main criteria's or reasons upon which we can judge an
algorithm. They are:
1. The correctness of the algorithm and
2. The simplicity of the algorithm
• The correctness of an algorithm can be analyzed by tracing the
algorithm with certain sample data and by trying to answer certain
questions such as.
1. Does the algorithm do what we want it to do?
2. Does it work correctly according to the original specifications of the task?
3. Does the algorithm work when the data structure used is full?
4. is there documentation that describes how to use it and how it works?
COMPLEXITY OF ALGORITHM
• In order to analyze this we will have to consider the time
requirements and the space requirements of the algorithm.
• These are the two parameters on which the efficiency of the
algorithms is measured.
• Space requirements are not a major problem today because
memory is very cheap. So time is the only criteria for
measuring efficiency of the algorithm as we have to maximize
the utilization of the CPU and response time to be minimized
to be faster.
Space complexity: The Space complexity of an algorithm
is the amount of main memory needed to run the program
till completion. Consider the following algorithms for
exchange two numbers:

Algo1_exchange (a, b) Algo2_exchange (a, b)


Step 1: tmp = a; Step 1: a = a + b;
Step 2: b = a - b;
Step 2: a = b;
Step 3: a = a - b;
Step 3: b = tmp;

• The first algorithm uses three variables a, b and tmp and the
second one take only two variables, so if we look from the
space complexity perspective the second algorithm is better
than the first one.
TIME COMPLEXITY
• The Time complexity of an algorithm is the amount of computer
time it needs to run the program till completion.
• To measure the time complexity in absolute time unit has the
following problems.
1. The time required for an algorithm depends on number of
instructions executed by the algorithm.
2. The execution time of an instruction depends on computer’s power.
Since, different computers take different amount of time for the
same instruction.
3. Different types of instructions take different amount of time on
same computer.
• Consider another algorithm for add n even number

Statement Per execution Frequency Total cost


Cost
Step 1. i = 2; 1 1 1
Step 2. sum = 0; 1 1 1
Step 3. while i <= 2*n 1 n+1 n+1
Step 4. sum = sum + i 1 n n
Step 5. i = i + 2; 1 n n
Step 6. end while; 0 1 0
Step 7. return sum; 1 1 1
Total cost 3n+4
• Consider another algorithm:

Statement Per execution Frequency Total cost


Cost
Step 1. sum(a, n) 0 - 0
Step 2. { 0 - 0
Step 3. s=0.0; 1 1 1
Step 4. for i=1 to n do 1 n+1 n+1
Step 5. s=s+a[i]; 1 n n
Step 6. return s; 1 1 1
Step 7. } 0 - 0
Total cost 2n+3
How to calculate f(n)?
• Calculating the value of f(n) for smaller programs is easy but for
bigger programs, it's not that easy. We can compare the data
structures by comparing their f(n) values. We will find the growth
rate of f(n) because there might be a possibility that one data
structure for a smaller input size is better than the other one but
not for the larger sizes.
• Now, how to find f(n).
• Let's look at a simple example.
• f(n) = 5n2 + 6n + 12
• where n is the number of instructions executed, and it depends on
the size of the input.
• When n=1
• % of running time due to 5n2 = * 100 = 21.74%
• % of running time due to 6n = * 100 = 26.09%
• % of running time due to 12 = * 100 = 52.17%
From the above calculation, it is observed that most of the time is taken by
12. But, we have to find the growth rate of f(n), we cannot say that the
maximum amount of time is taken by 12. Let's assume the different values of
n to find the growth rate of f(n).

• As we can observe in the above table that with the increase in the
value of n, the running time of 5n2 increases while the running time
of 6n and 12 also decreases. Therefore, it is observed that for
larger values of n, the squared term consumes almost 99% of the
time. As the n2 term is contributing most of the time, so we can
eliminate the rest two terms.
• Therefore,
• f(n) = 5n2
• Here, we are getting the approximate time complexity whose
result is very close to the actual result. And this approximate
measure of time complexity is known as an Asymptotic complexity.
Here, we are not calculating the exact running time, we are
eliminating the unnecessary terms, and we are just considering the
term which is taking most of the time.
• In mathematical analysis, asymptotic analysis of algorithm is a
method of defining the mathematical boundation of its run-time
performance. Using the asymptotic analysis, we can easily
conclude the average-case, best-case and worst-case scenario of an
algorithm.
• Order of growth: Order of growth is how the time of execution
depends on the length of the input. In the above example, we can
clearly see that the time of execution is linearly depends on the
length of the array.
• Order of growth will help us to compute the running time with ease.
We will ignore the lower order terms, since the lower order terms
are relatively insignificant for large input. We use different notation
to describe limiting behavior of a function.
Worst Case Analysis
• In the worst case analysis, we calculate upper bound on running time
of an algorithm.
• In that causes maximum number of operations to be executed.
• It defines the input for which the algorithm takes a huge time.
• For Linear Search, the worst case happens when the element to be
searched is not present in the array. When x is not present, the search
() functions compares it with all the elements of array [] one by one.
Therefore, the worst case time complexity of linear search would be.
.
Average Case Analysis
• In average case analysis, we take all possible inputs and
calculate computing time for all of the inputs. Sum all the
calculated values and divide the sum by total number of inputs.
• It takes average time for the program execution.
Best Case Analysis
• In the best case analysis, we calculate lower bound on running
time of an algorithm. We must know the case that causes
minimum number of operations to be executed.
• It defines the input for which the algorithm takes the lowest time
• In the linear search problem, the best case occurs when x is
present at the first location. The number of operations in worst
case is constant (not dependent on n). So time complexity in
the best case would be.
Asymptotic Analysis(O, Ω, ϴ) :
• When we calculate the complexity of an algorithm we often get
a complex polynomial. For simplify this complex polynomial we
use some notation to represent the complexity of an algorithm
call Asymptotic Notation. The function f and g are non
negative functions.
– Big oh Notation (O)
– Omega Notation (Ω)
– Theta Notation (θ)
Big oh Notation (O):
This notation provides an upper bound on a function which ensures that
the function never grows faster than the upper bound. So, it gives the
least upper bound on a function so that the function never grows faster than
this upper bound.
If f(n) and g(n) are the two functions defined for positive integers,
then f(n) = O(g(n)) as f(n) is big oh of g(n) or f(n) is on the order of g(n)) if
there exists constants c and no such that:
f(n)≤c.g(n) for all n≥no
This implies that f(n) does not grow faster than g(n), or g(n) is an upper
bound on the function f(n). In this case, we are calculating the growth rate
of the function which eventually calculates the worst time complexity
of a function, i.e., how worst an algorithm can perform.
Omega Notation (Ω)
1.It basically describes the best-case scenario which is
opposite to the big o notation.
2.It is the formal way to represent the lower bound of an
algorithm's running time. It measures the best amount of time
an algorithm can possibly take to complete or the best-case
time complexity.
3.It determines what is the fastest time that an algorithm can
run.
If f(n) and g(n) are the two functions defined for positive
integers,
then f(n) = Ω (g(n)) as f(n) is Omega of g(n) or f(n) is on the
order of g(n)) if there exists constants c and no such that:
f(n)>=c.g(n) for all n≥no and c>0
Theta Notation (θ)
• The theta notation mainly describes the average case scenarios.
• It represents the realistic time complexity of an algorithm. Every time,
an algorithm does not perform worst or best, in real-world problems,
algorithms mainly fluctuate between the worst-case and best-case,
and this gives us the average case of the algorithm.
• Let f(n) and g(n) be the functions of n where n is the steps required to
execute the program then:
f(n)= θg(n)
The above condition is satisfied only if when
c1.g(n)<=f(n)<=c2.g(n)
 The common name of few order notations is listed below:
Name Notation Example Algorithms
Logarithmic O(log n) Binary Search

Linear O(n) Linear Search

Superlinear O(n log n) Heap Sort, Merge Sort

Polynomial O(n^c) Bubble Sort, Selection Sort, Insertion Sort,


Bucket Sort

Exponential O(c^n) Tower of Hanoi

Determinant Expansion by Minors, Brute force


Factorial O(n!) Search algorithm for Traveling Salesman
Problem
 A Comparison of typical running time of different order notations for
different input size listed below:

The growth patterns of order notations have been listed below:


O(1) < O(log(n)) < O(n) < O(n log(n)) < O(n2 ) < O(n3 ) …
Example 1 Show that 4n 2 = O(n 3 ).
• Solution By definition, we have
0 ≤ f(n) ≤ cg(n)
• Substituting 4n2 as f(n) and n 3 as g(n), we get
0 ≤ 4n2 ≤ cn3
Dividing by n 3
0/n3 ≤ 4n2/n3 ≤ cn3/n3
0 ≤ 4/n ≤ c
Now to determine the value of c, we see that 4/n is maximum when
n=1. Therefore, c=4.
To determine the value of n 0 ,
0 ≤ 4/n0 ≤ 4
0 ≤ 4/4 ≤ n0
0 ≤ 1 ≤ n0
This means n 0 =1. Therefore, 0 ≤ 4n2 ≤ 4n 3 , n ≥ n0 =1.
Example 2 Show that 400n3 + 20n2 = O(n3).
• Solution By definition, we have
0 ≤ f(n) ≤ cg(n)
Substituting 400n 3 + 20n 2 as f(n) and n 3 as g(n), we get
0 ≤ 400n3 + 20n2 ≤ cn3 Dividing by n 3
0/n3 ≤ 400n3/n3 + 20n2/n3 ≤ cn3/n3
0 ≤ 400 + 20/n ≤ c
Note that 20/n → 0 as n → ∞, and 20/n is maximum when n = 1.
Therefore, 0 ≤ 400 + 20/1 ≤ c
This means, c = 420
To determine the value of n 0 ,
0 ≤ 400 + 20/n0 ≤ 420
–400 ≤ 400 + 20/n0 – 400 ≤ 420 – 400
–400 ≤ 20/n0 ≤ 20
–20 ≤ 1/n0 ≤ 1
–20 n0 ≤ 1 ≤ n0 . This implies n0 = 1.
Hence, 0 ≤ 400n 3 + 20n 2 ≤ 420n 3 n ≥ n0 =1.
• Example 3 Show that n = O(nlogn).
• Solution By definition, we have
0 ≤ f(n) ≤ cg(n)
• Substituting n as f(n) and nlogn as g(n), we get
0 ≤ n ≤ c n log n
Dividing by nlogn, we get
0/n log n ≤ n/n log n ≤ c n log n/ n log n
0 ≤ 1/log n ≤ c
We know that 1/log n → 0 as n → ∞
To determine the value of c, it is clearly evident that 1/log n is greatest
when n=2. Therefore,
0 ≤ 1/log 2 ≤ c = 1. Hence c = 1.
To determine the value of n 0, we can write
0 ≤ 1/log n0 ≤ 1
0 ≤ 1≤ log n0
Now, log n0 = 1, when n 0 = 2.
Hence, 0 ≤ n ≤ cn log n when c= 1 and n ≥ n0 =2.
• Example 4 Show that 10n 3 + 20n ≠ O(n2 ).
• Solution By deinition, we have
0 ≤ f(n) ≤ cg(n)
Substituting 10n 3 + 20n as f(n) and n 2 as g(n), we get
0 ≤ 10n3 + 20n ≤ cn2
Dividing by n 2
0/n2 ≤ 10n3/n2 + 20n/n2 ≤ cn2/n2
0 ≤ 10n + 20/n ≤ c
0 ≤ (10n2 + 20)/n ≤ c
Hence, 10n3 + 20n ≠ O2(n2)
Example 5 Show that 5n 2 + 10n = Ω(n 2 ).
• Solution By the definition, we can write
• 0 ≤ cg(n) ≤ f(n)
• 0 ≤ cn2 ≤ 5n2 + 10n
• Dividing by n 2
• 0/n2 ≤ cn2/n2 ≤ 5n2/n2 + 10n/n2
• 0 ≤ c ≤ 5 + 10/n
• Now, li m 5 +10/n = 5.
n 

• Therefore, 0 ≤ c ≤ 5. Hence, c = 5
• Now to determine the value of n 0
• 0 ≤ 5 ≤ 5 + 10/n0
• –5 ≤ 5 – 5 ≤ 5 + 10/n0 – 5
• –5 ≤ 0 ≤ 10/n0
• So n 0 = 1 asli m 1/n = 0
n 

• Hence, 5n2 + 10n = Ω(n2) for c=5 and n ≥ n0 =1.


• Example 6 Show that n 2 /2 – 2n = Θ(n 2 ).
• Solution By the definition, we can write
• c1 g(n) ≤ f(n) ≤ c2 g(n)
• c1 n 2 ≤ n2/2 – 2n ≤ c2 n 2
• Dividing by n 2 , we get
• c1 n 2/n2 ≤ n2/2n2 – 2n/n2 ≤ c2 n 2/n2
• c1 ≤ 1/2 – 2/n ≤ c2 li m
• This means c 2 = 1/2 becausen 
1/2 – 2/n = 1/2 (Big O notation)
• To determine c 1 using Ω notation, we can write
• 0 < c1 ≤ 1/2 – 2/n
• We see that 0 < c 1 is minimum when n = 5. Therefore,
• 0 < c1 ≤ 1/2 – 2/5
• Hence, c 1 = 1/10
• Now let us determine the value of n 0
• 1/10 ≤ 1/2 – 2/n0 ≤ 1/2
• 2/n0 ≤ 1/2 – 1/10 ≤ 1/2
• 2/n0 ≤ 2/5 ≤ 1/2
• n0 ≥ 5
• You may verify this by substituting the values as shown below.
• c1 n 2 ≤ n2/2 – 2n ≤ c2 n 2
• c1 = 1/10, c2 = 1/2 and n0 = 5 1/10(25) ≤ 25/2 – 20/2 ≤ 25/2
• 5/2 ≤ 5/2 ≤ 25/2
• Thus, in general, we can write, 1/10n 2 ≤ n2/2 – 2n ≤ 1/2n2 for n ≥ 5.
Pointer
 A pointer is a derived data type in ‘C’. It is built from any one of the
primary data type available in ‘C’ programming language.
 Pointer is a variable that holds the Address of another variable.
 Pointer is used to points the address of the value stored anywhere in
the computer memory. To obtain the value stored at the location is
known as dereferencing the pointer.
Declaring Pointer Variable:- Pointer declaration is similar to other
type of variable except asterisk (*) character before pointer variable
name. it is also called dereference operator.
“Value at Address”(*) Operator
The * Operator is also known as Value at address operator.
syntax to declare a pointer:- data_type *variable_name;
int *p;
char *ch;
float *pf;
Example
#include<stdio.h>
int main()
{
int*p;
int v=10;
p=&v; /* Assigning the address of variable v to the pointer p*/
printf("Value of variable v is: %d",v);
printf("\n Value of variable v is: %d",*p);
printf("\n Address of variable v is:%p",&v);
printf("\n Address of variable v is: %p", p);
printf("\nAddress of pointer p is: %p",&p);
}
Note: Pointers can be outputted using %p, since, most of the computers
store the address value in hexadecimal form using %p gives the value
in that form. But for simplicity and understanding we can also use %u
to get the value in Unsigned int form.
BENIFITS OF POINTER:-
1. Pointers reduce the length and complexity of a program.
2. Execution time with pointers is faster because data are manipulated
with the address, that is, direct access to memory location.
3. A pointer enables us to access a variable that is defined outside the
function.
4. Pointers are more efficient in handling the data tables.
5. The use of a pointer array of character strings results in saving of data
storage space in memory.
6. We can return multiple values from a function using the pointer.
7. Pointers save memory space.
8. Pointers are used to allocate memory dynamically.
%x -> Hexadecimal value represented with lowercase characters (unsigned integer type)
%X -> Hexadecimal value represented with uppercase characters (unsigned integer type)
%p -> Displays a memory address (pointer type) hexadecimal system are depending by
our system bit.
%u which is format specifier for printing an unsigned integer.

#include <stdio.h>
int main( )
{
int a = 5;
int *b;
b = &a;
printf ("value of a = %d\n", a);
printf ("value of a = %d\n", *(&a));
printf ("value of a = %d\n", *b); OUTPUT:
printf ("address of a = %u\n", &a); value of a = 5
printf ("address of a = %p\n", b); value of a = 5
printf ("value of b = address of a = %x\n", value of a = 5
b); address of a = 6487580
address of a = 000000000062FE1C
printf ("address of b = %X", &b);
value of b = address of a = 62fe1c
return 0; address of b = 62FE10
}
INITIALIZATION OF POINTER VARIABLE:-
 The process of assigning the address of a variable to a pointer variable
is known as initialization. Once a pointer variable has been declare we
can use the assignment operator to initialize the variable. EXAMPLE:

int quantity;
int *p;
#include<stdio.h>
int main() p= &quantity;
{ int a;
int *ptr;
a = 10;
ptr = &a;
printf(“Value of ptr:%u”, ptr);
return (0);
}
Dereferencing Pointer:
• Dereferencing is an operation performed to access and manipulates data
contained in the memory location pointed to by a pointer.
• The operator * is used to dereference pointers. A pointer variable is
dereference when the unary operator *, in this case called the indirection
operator, is used as a prefix to the pointer variable.
#include<stdio.h>
int main()
{
int *p, v1, v2;
p=&v1;
*p=25;
*p+=10;
printf(" value of v1= %d\n", v1);
v2=*p; output
printf("value of v2= %d\n", v2); value of v1= 35
p=&v2; value of v2= 35
*p+=20; now the value of v2=55
printf(" now the value of v2=%d \n", v2);
}
Accessing the Address of a Variable through its Pointer:-
• Once a pointer has been assigned the address of variable, the question is how to
access a value of a variable through its pointer? This is done by using another
unary operator *(asterisk),Consider the following statements.
int ds, *p, n;
ds = 133;
p = &ds;
n = *p;

• Here we can seen that ds and n declare as integer and p pointer variable that point
to an integer. When the operator * is placed before the pointer variable in an
expression, the pointer returns the values of variable of which the pointer value is
the address. In this case, *p returns the value of variable ds. Thus the value of n
would be 133. The two statements
p =&ds;
n = *p; are equivalent to
n = *&ds; which is turn is equivalent to n = ds;
int main()
{ int *p, q;
q = 19;
p = &q; /* assign p the address of q */
printf(" Vlaue of q=%d\n",q);
printf("Contents of p=%d\n ", *p);
printf("Address of q stored in p=%d ",p);
return 0;
}
OUTPUT:
Vlaue of q=19
Contents of p=19
Address of q stored in p=6487572
Pointer Arithmetic
• The size of data type which the pointer variable points to is the
number of bytes accessed in memory.
• The size of the pointer variable is dependent on the data type of the
variable pointed by the pointer.
• Some arithmetic operations can be performed with pointers.
• C language supports the flowing arithmetic operators which can be
performed with pointers .They are
1. Pointer increment(++)
2. Pointer decrement(- -)
3. addition (+)
4. subtraction (-)
5. Subtracting two pointers of the same type
6. Comparison of pointers
Pointer increment and decrement:-
• Integer, float, char, double data type pointers can be incremented and
decremented. For all these data types both prefix and post fix
increment or decrement is allowed.
• Integer pointers are incremented or decremented in the multiples of
two. Similarly character by one, float by four and double pointers by
eight etc For 32-bit machine.
• Note that pointer arithmetic cannot be performed on void pointers,
since they have no data type associated with them.
• Let int *x;
x++ /*valid*/
++x /*valid*/
x-- /*valid*/
--x /*valid*/
• The Rule to increment the pointer is given as
new_address= current_address + i * size_of(data type)
• Where i is the number by which the pointer get increased.
• For 32-bit int variable, it will be incremented by 2 bytes.
• For 64-bit int variable, it will be incremented by 4 bytes.
• The Rule to decrement the pointer is given as
new_address= current_address - i * size_of(data type)
Note: If we have more than one pointer pointing to the same location,
then the change made by one pointer will be the same as another
pointer.
void main()
{
int *p1,x;
float *f1,f;
char *c1,c;
p1=&x;
f1=&f;
c1=&c;
printf("Memory address before increment:\n int=%p\n,float=%p\n, char=%p\n",p1,f1
,c1);
p1++;
f1++;
c1++;
printf("Memory address after increment:\n int=%p\n, float=%p\n,char=%p\n",p1,f1,
c1);
}
C Pointer Addition
• We can add a value to the pointer variable. The formula of adding
value to pointer is given
new_address= current_address + (number * size_of(data type))
#include<stdio.h>
int main(){
int number=50;
int *p; //pointer to int
p=&number; //stores the address of number variable
printf("Address of p variable is %u \n", p);
p=p+3; //adding 3 to pointer variable
printf("After adding 3: Address of p variable is %u \n", p);
return 0;
Output }

Address of p variable is 3214864300


After adding 3: Address of p variable is 3214864312
Address of p variable is 3214864300 After subtracting 3: Address of p variable is 3214864288
C Pointer Subtraction
• Subtracting any number from a pointer will give an address. The
formula of subtracting value from the pointer variable is given as:
new_address= current_address - (number * size_of(data type))
#include<stdio.h>
int main()
{
int number=50;
int *p; //pointer to int
p=&number; //stores the address of number variable
printf("Address of p variable is %u \n", p);
p=p-3; //subtracting 3 from pointer variable
printf("After subtracting 3: Address of p variable is %u \n", p);
return 0;
}
Output
• Address of p variable is 3214864300
• After subtracting 3: Address of p variable is 3214864288
Subtraction of one pointer from another:-
The subtraction of two pointers is possible only when they have the same data type.
The result is generated by calculating the difference between the addresses of the
two pointers and calculating how many bytes of data it is according to the pointer
data type. The subtraction of two pointers gives the increments between the two
pointers. This operation is useful for calculating the distance or offset between
two pointers.
Example: Two integer pointers say ptr1(address:1000) and ptr2(address:1004) are
subtracted. The difference between addresses is 4 bytes. Since the size of int is 4
bytes, therefore the increment between ptr1 and ptr2 is given by (4/4) = 1.
#include <stdio.h>
main()
{ int x[] = {10, 20, 30, 45, 67, 56, 74} ;
int *i, *j ;
i = &x[1] ;
j = &x[5] ;
printf("i=%d and j=%d\n",i,j);
printf ( "%d %d", j - i, *j - *i ) ;
}
Output:
i=6487540 and j=6487556
4 36
#include <stdio.h>
main()
{
int x = 5, y = 7;
int *p = &y;
int *q = &x;
printf("p is %d\n q is %d\np - q is %d", p, q, (p - q));
}
Output
p is 6487560
q is 6487564
p - q is -1
Comparison of Pointers
We can compare pointers using operators like >, >=, <, <=, ==, and !=. The
se operators return true for valid conditions and false for unsatisfied
conditions.
#include <stdio.h>
int main()
{
int arr[5];
int *ptr2 = &arr[0];
int *ptr1 =arr;
if (ptr1 == ptr2)
{
printf("Pointer to Array Name and First Element are Equal.");
}
else
{
printf("Pointer to Array Name and First Element are not Equal.");
}
return 0;
}
Null Pointers
• A pointer variable is a pointer to a variable of some data type. However, in
some cases, we may prefer to have a null pointer which is a special pointer
value and does not point to any value.
• This means that a null pointer does not point to any valid memory address.
• This is done at the time of variable declaration. A pointer that is assigned
NULL is called a null pointer.
• The NULL pointer is a constant with a value of zero defined in several
standard libraries.
#include<stdio.h>
int main ()
{
int *ptr=NULL;
printf("The value of ptr is : %x\n",&ptr);
printf("The value of ptr is :%d\n",ptr);
return 0;
}
Output
The value of ptr is : 62fe18
The value of ptr is :0
Pointers does not allow the flowing operation
(a) Addition of two pointer
(b) Multiplication of a pointer with a constant
(c) Division of a pointer with a constant
There are various operations which can not be performed on pointers.
Address + Address = illegal
Address * Address = illegal
Address % Address = illegal
Address / Address = illegal
Address & Address = illegal
Address ^ Address = illegal
Address | Address = illegal
~Address = illegal
void Pointer
void Pointer: A generic pointer is a pointer variable that has void as its
data type.
• The void pointer, or the generic pointer, is a special type of pointer
that can point to variables of any data type.
• For example if we have a pointer to int, then it would be incorrect to
assign the address of a float variable to it. But an exception to this
rule is a pointer to void.
• Syntax of declaration of a void type:
<void> *<variable name>;
• A void pointer cannot be dereferences simple by using indirection
operator. Before dereferencing, it should be type cast to appropriate
pointer data type.
• Pointer arithmetic cannot be performed on void pointers without
typecasting.
int main ()
{
int a=3;
float b=3.4, *fp=&b;
void *vp;
vp=&a;
printf ("value of a= %d\n", *(int *)vp);
*(int *)vp=12;
printf ("value of a= %d\n", *(int *)vp);
vp = fp;
printf ("value of b= %f\n", *(float *)vp);
}
Output:
value of a= 3
value of a= 12
value of b=3.400000
Precedence of dereferencing Operator and Increment /decrement Operators

• The precedence level of * operator and increment/ decrement operators is


same and their associativity is from right to left.
• Suppose ptr is an integer and x in an integer variable.
 X=*ptr++;
• The expression *ptr++ is equivalent to *(ptr++), since these operators
associate from right to left. The increment operator is postfix, so first the value
of ptr will be used in the expression and then it will be incremented.
 X=*++ptr;
• The expression *++ptr is equivalent to *(++ptr), since these operators
associate from right to left. The increment operator is preefix, so first ptr
will be incremented
 X=++*ptr;
• The expression ++*ptr is equivalent to ++(*ptr), since these operators
associate from right to left.
 X=(*ptr)++;
• Here increment operator is applied over (*ptr), since it is postfix increment
hence first the value of *ptr will be assigned to x and then it will be
incremented.
#include <stdio.h>
int main()
{ int nums[] = {10, 20, 30, 40, 50};
int *p = nums; //pointer storing the address of nums array
int var;
var = ++*p; //value at index 0 incremented by 1
printf(" *p = %d, var = %d \n", *p, var);
var = *p++; //value of index 0 stored in var and then pointer get inc.
printf(" *p = %d, var = %d \n", *p, var);
var = *++p; //pointer address get inc. and then value is stored
printf(" *p = %d, var = %d \n", *p, var);
return 0;
}
Output
*p = 11, var = 11
*p = 20, var = 11
*p = 30, var = 30
Pointer to pointer
• It is possible to make a pointer to point to another pointer, (this is also
known as Pointer to pointer and Double pointer), thus creating a chain of
pointer as shown.

• Here, the pointer variable p1 contains the address of the pointer variable p2.
This is known as multiple indirections.
• A variable that is a pointer to a pointer must be declared using additional
indirection operator symbols in front of the name.
• The general syntax for declaring a pointer to pointer is:
<data type> **< pointer to pointer variable name>.
Example: int **p1;
int main ()
{
intvar;
int *ptr;
int **pptr;
var = 3000;
ptr = &var; /* take the address of var */
pptr = &ptr;/* take the address of ptr using address of operator &*/
printf("Value of var = %d\n", var );
printf("Value available at *ptr = %d\n", *ptr );
printf("Value available at **pptr = %d\n", **pptr); /* take the value using pptr */
}
OUTPUT:-
Value of var = 3000
Value available at *ptr = 3000
Value available at **pptr = 3000
4000 3000 2000
3000 2000 5

ppa pa a

Value of a a *pa **ppa 5


Address of a &a pa *ppa 2000
Value of pa &a pa *ppa 2000
Address of pa &pa ppa 3000
Value of ppa &pa ppa 3000
Address of ppa &ppa 4000
Use of pointers to pointers
• Double pointers are often used in situations where we need to
allocate memory for a two-dimensional array dynamically or when
we need to pass a pointer to a pointer to a function to modify the
original pointer value.
• Note that if we used a single pointer to hold the address of the row
pointer array, we would not be able to allocate memory for the
columns of the array dynamically, since the single pointer would
only hold the address of the first row pointer, and we would not be
able to access the other rows of the array.
• If we used a single pointer in the modify Pointer function, we would
only be able to modify the copy of the original pointer value that was
passed to the function, not the original pointer value itself. Therefore
, using a double pointer is necessary to modify the original pointer
value directly.
#include <stdio.h>
#include <stdlib.h> // Print the array
int main() { for (int i = 0; i < m; i++)
{
int m,n;
for (int j = 0; j < n; j++)
printf("input number of row and column\n"); {
scanf("%d \n %d",&m, &n); printf("%d ", arr[i][j]);
int** arr; // Allocate memory for rows }
arr = (int**)malloc(m * sizeof(int*)); printf("\n");
}
for (int i = 0; i < m; i++)
arr[i] = (int*)malloc(n * sizeof(int)); // Free allocated memory
printf("input element in matrix \n"); for (int i = 0; i < m; i++)
for (int i = 0; i < m; i++) {
{ for (int j = 0; j < n; j++) free(arr[i]);
}
{ scanf("%d",&arr[i][j]);
free(arr);
} return 0;
} }
#include <stdio.h>
// Function that takes array of strings as argument
void print(char** arr, int n) {
for (int i = 0; i < n; i++)
printf("%s\n", *(arr + i));
}

int main()
{
char* arr[10] = {"Geek", "Geeks ", "Geekfor"};
print(arr, 3);
return 0;
}
C Array
• An array is defined as the collection of similar type of data items
stored at contiguous memory locations.
• Arrays are the derived data type in C programming language
which can store the primitive type of data such as int, char, double,
float, etc.
• It also has the capability to store the collection of derived data
types, such as pointers, structure, etc.
• The array is the simplest data structure where each data element
can be randomly accessed by using its index number. example
Declaration One Dimensional Array: arrays must be declared
explicitly before they are used. The general form of declaration is:
Data_type Array_Name[Array_Size];
int marks[5];
• Here, int is the data_type, marks are the array_name, and 5 is
the array_size.
Initialization of One Dimensional Array
• Once an array is declared, it must be initialized. Otherwise array
will contain the garbage values. There are two different ways in
which we can initialize the static array
1. Compile time
2. Run time
• Compile Time Initialization
1. Initializing Arrays during Declaration
data-type array-name[size] = { list of values separated by comma };
For example:
int marks[5]={90, 82, 78, 95, 88};
• Note that if the number of values provided is less than the number of
elements in the array, the un-assigned elements are filled with zeros.

initialize an array is by using the index of each element: We can initialize


each element of the array by using the index.
marks[0]=80;//initialization of array
marks[1]=60;
marks[2]=70;
marks[3]=85;
marks[4]=75;
Run Time Initialization
• An array can initialized at run time by the program or by taking the
input from the keyboard. Generally, the large arrays are declared at
run time in the program itself. Such as –
int i, marks[10];
printf(“Enter any ten marks: ”);
for(i=0;i<10;i++)
scanf(“%d”, &marks[i]);
Accessing array elements: An element is accessed by indexing the
array name.
Array_name[index];
for example marks[0];
marks[1];
main() main( )
{ {
int i; int val[10], i, total=0;
int x[10]; printf(“Enter any ten numbers: ”);
for (i=0; i<10; i++) for(i=0;i<10;i++)
{ scanf(“%d”, &val[i]);
x[i] = i + 1;
for(i=0;i<10;i++)
printf( “x=%d.\n", x[i]);
total = total + val[i];
}
printf(“\nTotal is: %d”, total);
}
}
Write a program to find the mean of n numbers using arrays.
#include <stdio.h>
#include <conio.h>
int main()
{
int i, n, arr[20], sum =0;
float mean = 0.0;
printf("\n Enter the number of elements in the array : ");
scanf("%d", &n);
for(i=0;i<n;i++)
{
printf("\n arr[%d] = ", i);
scanf("%d",&arr[i]);
}
for(i=0;i<n;i++)
sum += arr[i];
mean = (float)sum/n;
printf("\n The sum of the array elements = %d", sum);
printf("\n The mean of the array elements = %.2f", mean);
return 0;
}
Calculating the Address of Array Elements
• When we use the array name, we are actually referring to the first
byte of the array. Since an array stores all its data elements in
consecutive memory locations, storing just the base address, that is
the address of the first element in the array, is sufficient.
• The address of other data elements can simply be calculated using the
base address.
Address of data element, A[k] = BA(A) + w(k – lower_bound)
• For Example Given an array int marks[]={99,67,78,56,88,90,34,85},
calculate the address of marks[4] if the base address = 1000.

• We know that storing an integer value requires 2 bytes, therefore, its


size is 2 bytes. marks[4] = 1000 + 2(4 – 0)
= 1000 + 2(4) = 1008
Calculating the Length of an Array
• The length of an array is given by the number of elements stored
in it. The general formula to calculate the length of an array is
Length = upper_bound – lower_bound + 1
• where upper_bound is the index of the last element and
lower_bound is the index of the first element in the array.
• Example Let Age[5] be an array of integers such that Age[0] = 2,
Age[1] = 5, Age[2] = 3, Age[3] = 1, Age[4] = 7 Show the memory
representation of the array and calculate its length.

Length = upper_bound – lower_bound + 1


• Here, lower_bound = 0, upper_bound = 4
• Therefore, length = 4 – 0 + 1 = 5
Pointers and one dimensional Arrays:-
• The elements of an array are store in contiguous memory location. When an array
is declared, compiler allocates sufficient amount of memory to contain all the
elements of the array. Base address i.e address of the first element of the array is
also allocated by the compiler.
Suppose we declare an array x,
int x[5] = { 1, 2, 3, 4, 5 };
Assuming that the base address of x is 1000 and each integer requires two bytes, the
five elements will be stored as follows:

Element x[0] x[1] x[2] x[3] x[4]


Address 1000 1002 1004 1006 1008
• Here variable x will give the base address, which is a constant pointer pointing to
the first element of the array, x[0]. Hence x contains the address of x [0] i.e. 1000.
We can also declare a pointer of type int to point to the array x.
int *p; p = x; // or,
p = &x[0]; //both the statements are equivalent.
 Now we can access every element of the array x using p++ to move
from one element to another.
 When using pointers, an expression like x[i] is equivalent to writing
*(x+i).
NOTE: You cannot decrement a pointer once incremented. p--
Won’t work.
 Many beginners get confused by thinking of array name as a pointer.
 For example, while we can write ptr = x; // ptr = &x[0]
 we cannot write x = ptr;
 This is because while x is a variable, x is a constant. the location at
which the first element of x will be stored cannot be changed once
x[] has been declared. Therefore, an array name is often known to be
a constant pointer.
 Note: x[i], i[x], *(x+i), *(i+x) gives the same value of ith element
of array x.
#include<stdio.h> #include<stdio.h>
int main() int main()
{ {
int a[]={1,2,3,4,5,6};
int a[]={1,2,3,4,5,6}; int *b=a;
int *b=a; b=a+1;
b=a++; //error printf("%d\n",*b);
printf("%d\n",*b); }
}
Arrays Of Pointers
• An array of pointers can be declared as int *ptr[10];
• The above statement declares an array of 10 pointers where each of the
pointer points to an integer variable.

#include <stdio.h>
int main()
{ int arr1[]={1,2,3,4,5};
int arr2[]={0,2,4,6,8};
int arr3[]={1,3,5,7,9};
int *parr[3] = {arr1, arr2, arr3};
int i;
for(i = 0;i<3;i++)
printf(" %d", *parr[i]);
return 0;
} Output 1 0 1

• parr[0] stores the base address of arr1 (or, &arr1[0]). So writing *parr[0]
will print the value stored at &arr1[0]. Same is the case with *parr[1] and
*parr[2]
Pointer to an Array:
• We have seen that a pointer that pointed to the first element of array. We
can also declare a pointer that can point to the whole array.
• For example int (*ptr)[10]; here ptr is point to an array of 10 integer.
• Note that it is necessary to enclose the pointer name inside parentheses.
• We know that the pointer arithmetic is performed relative to the base size,
so if we write ptr++, then the pointer ptr will be shifted forward by 20 bytes.
#include <stdio.h>
int main()
{
int arr[] = { 3, 5, 6, 7, 9 };
int *p = arr;
int (*ptr)[5] = &arr;
printf("p = %p, ptr = %p\n", p, ptr);
printf("*p = %d, *ptr = %p *ptr[0]=%d\n", *p, *ptr, *ptr[0]);
printf("sizeof(p) = %lu, sizeof(*p) = %lu\n", sizeof(p), sizeof(*p));
return 0;
} Output: p = 000000000062FDF0, ptr = 000000000062FDF0
*p = 3, *ptr = 000000000062FDF0 *ptr[0]=3
sizeof(p) = 8, sizeof(*p) = 4
#include <conio.h>
int main()
{ int *p;
int x[5];
int (*ptr)[5];
p=x; // Points to 0th element of the x.
ptr=&x; // Points to the whole array of x.
printf(" p=%u, ptr=%d\n", p, ptr);
p++;
ptr++;
printf(" p=%u, ptr=%d\n", p, ptr);
}
Output:
P=3000, pa=3000
P=3002, pa=3010
int main()
{
int(*a)[5]; // Pointer to an array of five numbers
int b[5] = { 1, 2, 3, 4, 5 };
int i = 0;
a = &b; // Points to the whole array b
for (i = 0; i < 5; i++)
printf("%d\n", *(*a + i));
return 0;
}
Output
1
2
3
4
5
Multi Dimensional Array: It can be defined as ‘an Array which holds
more than one subscript is known as Multi Dimensional Array.
Generally 2-D array is called as Matrix. It is more suitable for the
processing of table and matrix manipulations. C language allow to
programmers to use arrays with more than two dimensions. On
behalf of this it can be divided into two sub section:
Two Dimensional Array
N-Dimensional Array
Data_Type Array_Name[row size][column size];
For Example: int x[3][4];
Where int is the type of the array, x is the array name and row size is the
number of rows and column size the number of column. To find the
total number of element of an array, multiply the total number of row
with the total number of column.
For Example: int a[3][4];

Thus, every element in array a is identified by an element name of


the form a[ i ][ j ], where a of the array, and i and j are the subscripts
(index) that uniquely identify each element in a.
It can be seen that a rectangular picture of a two-dimensional array,
in the memory, these elements actually will be stored sequentially.
There are two ways of storing a two-dimensional array in the
memory.
The First way is the row major order and the second is the column
major order.
row major order
• In a row major order the elements of the first row are stored before
the elements of the second and third rows. That is, the elements of
the array are stored row by row where n elements of the first row will
occupy the first n locations.

• The computer stores the base address, and the address of the other
elements is calculated using the following formula.
• if the array elements are stored in row major order,

Address(A[I][J]) = Base_Address + w{N ( I – 1) + (J – 1)}

• where w is the number of bytes required to store one element, N is


the number of columns, and I and J are the subscripts of the array
element.
column major order
• In a column major order, the elements of the first column are stored
before the elements of the second and third column. That is, the
elements of the array are stored column by column where m elements
of the first column will occupy the first m locations.

• The computer stores the base address, and the address of the other
elements is calculated using the following formula.
• If the array elements are stored in column major order,
Address(A[I][J]) = Base_Address + w{(I – 1) + M ( J – 1) }
• where w is the number of bytes required to store one element, M is
the number of rows, and I and J are the subscripts of the array
element.
• Example Consider a 20 * 5 two-dimensional array marks which has
its base address = 1000 and the size of an element = 2. Now
compute the address of the element, marks[18][ 4] assuming that the
elements are stored in row major order.
• Solution
Address(A[I][J]) = Base_Address + w{N (I – 1) + (J – 1)}
Address(marks[18][4]) = 1000 + 2 {5(18 – 1) + (4 – 1)}
= 1000 + 2 {5(17) + 3}
= 1000 + 2 (88)
= 1000 + 176
= 1176
Initializing Two-Dimensional Arrays:
 Multidimensional arrays may be initialized by specifying
bracketed values for each row. Following is an array with
3 rows and each row has 4 columns.

Accessing Two-Dimensional Array Elements:


An element in 2-dimensional array is accessed by using the subscripts, by
row index and column index of the array i.e.
Array_name[row index][column index];.
For example: int val = a[2][3];
The above statement will take 4th element from the 3rd row of the array.
Example

#include <stdio.h>
int main ()
{
int a[5][2] = { {0,0}, {1,2}, {2,4}, {3,6},{4,8}}; /* an array with 5 rows and 2 columns*/
int i, j;
/* output each array element's value */
for ( i = 0; i < 5; i++ )
{
for ( j = 0; j < 2; j++ )
{
printf("a[%d][%d] = %d\n", i, j, a[i][j] );
}
}
return 0;
}
Write a program to print a matrix of order m * n where
void main( )
{ clrscr( );
int mat[50][50] i, j, m, n;
printf(“Enter the number of Rows”);
scanf(“%d”,&m);
printf(“Enter the number of Columns”);
scanf(“%d”,&n);
printf(“Enter the element for the Matrix”);
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
scanf(“%d”, &mat[i][j]);
}
}
printf(“The Matrix is:”);
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
printf(“\t%d”,mat[i][j]);
}
printf(“\n”);
}
getch( );
}
Array with more than two dimentions
• Three-D array as 2-D arrays. For example
int x[2][3][4];
This array consist of two 2-D arrays and each of those 2-D array has 3
rows and 4 columns.

[0] [1]
#include<stdio.h> printf("print the values in array: \n");
int i,j,k; //variables for nested for loops for(i=1;i<=2;i++)
int main() {
{ for(j=1;j<=3;j++)
int arr[2][3][4]; //array declaration {
printf("enter the values in the array: \n"); for(k=1;k<=4;k++)
for(i=1;i<=2;i++) //represents block {
{ printf("%d ",arr[i][j][k]);
for(j=1;j<=3;j++) //represents rows }
{ printf("\n");
for(k=1;k<=4;k++) //represents columns }
{ printf("\n");
printf("the value at arr[%d][%d][%d]: ", i, j, k }
); return 0;
scanf("%d", &arr[i][j][k]); }
}
}
}
Pointer to Two dimensional Array:
• In two dimensional arrays, we can access each element by using two
subscripts, where first subscript represents row number and second
subscript represents the column number.
• A two dimensional array is of form, x[i][j]. Lets see how we can make
a pointer point to such an array. As we know, name of the array gives
its base address.
• In x[i][j], x will give the base address of this array, that is the address
of x[0][0] element.
• In the case of 2-D arrays, first element is a 1-D array, so the name of
2-D array represents a pointer to 1-D array. x[i] or (x+i) or *(x+i)
point to ith row of 1-D array of the base address where x is two
dimension array.
• Individual elements of the array mat can be accessed using either:
• x[i][j] or *(*(x + i) + j) or *(x[i]+j);
• Since memory in a computer is organized linearly it is not possible to store
the 2-D array in rows and columns. The concept of rows and columns is
only theoretical, actually, a 2-D array is stored in row-major order i.e rows
are placed next to each other. The following figure shows how the above
2-D array will be stored in memory.

• Each row can be considered as a 1-D array, so a two-dimensional array


can be considered as a collection of one-dimensional arrays that are placed
one after another. In other words, we can say that 2-D dimensional arrays
that are placed one after another. So here arr is an array of 3 elements
where each element is a 1-D array of 4 integers.
• We know that the name of an array is a constant pointer that points to
0th 1-D array and contains address 5000. Since arr is a ‘pointer to an array
of 4 integers’, according to pointer arithmetic the expression arr + 1 will
represent the address 5016 and expression arr + 2 will represent address
5032.
• So we can say that arr points to the 0th 1-D array, arr + 1 points to the
1st 1-D array and arr + 2 points to the 2nd 1-D array.

• arr + i Points to ith element of arr - Points to ith 1-D array


• Thus the expression *(arr + i) gives us the base address of ith 1-D array.
• The pointer expression *(arr + i) is equivalent to the subscript expression
arr[i]. So *(arr + i) which is same as arr[i] gives us the base address of
ith 1-D array.
• To access an individual element of our 2-D array, we should be able to
access any jth element of ith 1-D array.
• Since the base type of *(arr + i) is int and it contains the address of
0th element of ith 1-D array, we can get the addresses of subsequent
elements in the ith 1-D array by adding integer values to *(arr + i).
• For example *(arr + i) + 1 will represent the address of 2nd element of ith 1-D
array and *(arr+i)+2 will represent the address of 3rd element of ith 1-D array
.
• Similarly *(arr + i) + j will represent the address of jth element of ith1-D array.

*(*(arr+2)+3)

*(arr+2) *(arr+2)+3
#include<stdio.h>
int main()
{
int arr[3][4] = {{10, 11, 12, 13}, {20, 21, 22, 23}, {30, 31, 32, 33} };
int (*ptr)[4];
ptr = arr;
printf("%p %p %p\n", ptr, ptr + 1, ptr + 2);
printf("%p %p %p\n", *ptr, *(ptr + 1), *(ptr + 2));
printf("%d %d %d\n", **ptr, *(*(ptr + 1) + 2), *(*(ptr + 2) + 3));
printf("%d %d %d\n", ptr[0][0], ptr[1][2], ptr[2][3]);
return 0;
}

Output:
0x7ffead967560 0x7ffead967570 0x7ffead967580
0x7ffead967560 0x7ffead967570 0x7ffead967580
10 22 33
10 22 33
main( )
{
int s[4][2] = {{ 12, 56 }, { 12, 33 }, { 14, 80 }, { 13, 78 }} ;
int i, j ;
for ( i = 0 ; i <= 3 ; i++ )
{
printf("\n Address of %d th row one D array=%u %u\n", i, s[i], *(s+i));
printf ( "\n" ) ;
for ( j = 0 ; j <= 1 ; j++ )
printf ( "%d ", *( *( s + i ) + j ) ) ;
}}
Output:
Address of 0th row one D array=2293400 229340012 56
Address of 1th row one D array=2293408 229340812 33
Address of 2th row one D array=2293416 229341614 80
Address of 3th row one D array=2293424 229342413 78
• The golden rule to access an element of a two-dimensional array can
be given as arr[i][j] = (*(arr+i))[j] = *((*arr+i))+j) = *(arr[i]+j)
• Therefore, arr[0][0] = *(arr)[0] = *((*arr)+0) = *(arr[0]+0)

If we declare an array of pointers If we declare a pointer to an array


using, using,
data_type *array_name[SIZE]; data_type (*array_name)[SIZE];
Here SIZE represents the number of Here SIZE represents the number of
rows and the space for columns that columns and the space for rows that
can be dynamically allocated may be dynamically allocated
Pointers and Three Dimensional Arrays
• In a three dimensional array we can access each element by using three subscripts.
int arr[2][3][2] = { {{5, 10}, {6, 11}, {7, 12}}, {{20, 30}, {21, 31}, {22, 32}} };
• We can consider a three dimensional array to be an array of 2-D array i.e. each
element of a 3-D array is considered to be a 2-D array. The 3-D array arr can be
considered as an array consisting of two elements where each element is a 2-D
array. The name of the array arr is a pointer to the 0th 2-D array.

• Thus the pointer expression *(*(*(arr + i ) + j ) + k) is equivalent to the subscript


expression arr[i][j][k].
#include<stdio.h>
int main()
{ int arr[2][3][2] = { { {5, 10}, {6, 11}, {7, 12}, },
{ {20, 30}, {21, 31}, {22, 32}, } };
int i, j, k;
for (i = 0; i < 2; i++)
{
for (j = 0; j < 3; j++)
{
for (k = 0; k < 2; k++)
printf("%d\t", *(*(*(arr + i) + j) +k));
printf("\n");
}
}
How the 3-D array used in the above program is stored in memory
return 0;
}
OPERATIONS ON ARRAYS
• There are a number of operations that can be preformed on arrays.
These operations include:
 Traversing an array
 Inserting an element in an array
 Searching an element in an array
 Deleting an element from an array
 Merging two arrays
 Sorting an array in ascending or descending order
Traversing an Array
Traversing an array means accessing each and every element
of the array for a specific purpose.
Traversing the data elements of an array A can include printing
every element, counting the total number of elements, or
performing any process on these elements.

Step 1 SET I= lower_bound


Step 2: Repeat Steps 3 to 4 while I<= upper_bound
Step 3: Apply Process to A[I]
Step 4: SET I=I+1
[END OF LOOP]
Step 5: EXIT
Write a program to read and display n numbers using an array.
#include<stdio.h>
int main()
{
int i, n, A[20];
printf("\n Enter the number of elements in the array : ");
scanf("%d", &n);
for(i=0;i<n;i++)
scanf("%d", &A[i]);
printf("the Array elements are=");
for(i=0;i<n; i++)
printf("%d \t", A[i]);
}
Inserting an Element in an Array
Insert operation is to insert one or more data elements into an
array. Based on the requirement, a new element can be added at
the beginning, end, or any given index of array. Here, we assume
that the memory space allocated for the array is still available.

Step 1: SET I=N


Step 2: Repeat Steps 3 and 4 while I>= POS
Step 3: SET A[I + 1] = A[I]
Step 4: SET I=I–1
[END OF LOOP]
Step 5: SET A[POS] = NUM
Step 6: SET N=N+1
Step 7: EXIT
Inserting an Element in an Array
#include<stdio.h>
int main()
{ int i, n, num, pos, arr[10];
printf("\n Enter the number of elements in the array : ");
scanf("%d", &n);
for(i=0;i<n;i++)
scanf("%d", &arr[i]);
printf("\n Enter the number to be inserted : ");
scanf("%d", &num);
printf("\n Enter the position at which the number has to be added :");
scanf("%d", &pos);
for(i=n-1;i>=pos;i--)
arr[i+1] = arr[i];
arr[pos] = num;
n = n+1;
printf("\n The array after insertion of %d is : ", num);
for(i=0;i<n;i++)
printf("%d \t", arr[i]);
}
Deleting an Element in an Array
Deleting an element from an array means removing a data
element from an already existing array and re-organizing all
elements of an array.

• Consider LA is a linear array with N elements and K is a positive


integer such that K<=N.
1. Start NUM=LA[K]
2. Set J = K
3. Repeat steps 4 and 5 while J < N
4. Set LA[J] = LA[J + 1]
5. Set J = J+1
6. Set N = N-1
7. Stop
Write a program to delete a number from a given location in an array
#include<stdio.h>
int main()
{ int i, n, pos, arr[10],num;
printf("\n Enter the number of elements in the array : ");
scanf("%d", &n);
printf("\n Enter the elements in the array : ");
for(i=0;i<n;i++)
scanf("%d", &arr[i]);
printf("\nEnter the position from which the number has to be deleted : ");
scanf("%d", &pos);
num=arr[pos];
for(i=pos; i<n-1;i++)
arr[i] = arr[i+1];
n=n-1;
printf("\n The array after deletion is : ");
for(i=0;i<n; i++)
printf("\n arr[%d] = %d", i, arr[i]);
}
Search Operation
It is the process of finding the location of the element with a
given key value in a particular data structure or finding the
location of an element, which satisfies the given condition. There
are mainly two techniques available to search the data in an
array:
1. Linear search
2. Binary search
Linear search, also called as sequential search, is a very
simple method used for searching an array for a particular value.
 It works by comparing the value to be searched with every
element of the array one by one in a sequence until a match is
found. if the match is found, then it returns the index of the
element else it returns element not found. This algorithm can be
implemented on the unsorted list.
Linear Search Operation
• Consider A is a linear array with N elements and K is a positive
integer such that K<=N. Following is the algorithm to find an
element with a value of ITEM using sequential search.
1. Start
2. Set J = 0
3. Repeat steps 4 and 5 while J < N
4. IF A[J] ==ITEM
THEN GOTO STEP 6
5. Set J = J +1
6. PRINT J, ITEM
7. Stop
Time Complexity

Operation Average Case Worst Case


Access O(1) O(1)
Search O(n) O(n)
Insertion O(n) O(n)
Deletion O(n) O(n)
Example of linear search
#include<stdio.h>
int main()
{ int i,j, n, item, A[10];
printf("\n Enter the number of elements in the array : ");
scanf("%d", &n);
printf("\n Enter the elements in the array : ");
for(i=0;i<n;i++)
scanf("%d", &A[i]);
printf("\n Enter the item in the array whose search the position : ");
scanf("%d",&item);
j=0;
while( j < n)
{
if( A[j] == item )
{ break;
}
j = j + 1;
}
printf("Found element %d at position %d\n", item, j+1);
}
Binary Search
• A Binary algorithm is the simplest algorithm that searches the element very quickly.
• It is used to search the element from the sorted list. The elements must be stored in
sequential order or the sorted manner to implement the binary algorithm.
• Binary search cannot be implemented if the elements are stored in a random manner
.
BINARY_SEARCH(A, lower_bound, upper_bound, ITEM)
Step 1: SET BEG = lower_bound ; END = upper_bound, POS=-1
Step 2: Repeat Steps 3 and 4 while BEG <= END
Step 3: SET MID = (BEG + END)/2
Step 4: IF A[MID] == ITEM
SET POS = MID
PRINT POS Go to Step 6
ELSE IF A[MID] > ITEM
SET END = MID-1
ELSE
SET BEG = MID+1
[END OF IF]
[END OF LOOP]
Step 5: IF POS=-1
PRINT “VALUE IS NOT PRESENT IN THE ARRAY”
Step 6: end
• Let the element to search is, k = 56 i.e. ITEM=k
• We have to use the below formula to calculate the mid of the array

• beg = 0
• end = 8
• mid = (0 + 8)/2 = 4. So, 4 is the mid of the array.
Binary Search complexity

Case Time Complexity


Best Case O(1)

Average Case O(logn)

Worst Case O(logn)


Merging Two Arrays
• Merging two arrays in a third array means first copying the contents
of the first array into the third array and then copying the contents of
the second array into the third array. Hence, the merged array contains
the contents of the first array followed by the contents of the second
array.
• If the arrays are unsorted, then merging the arrays is very simple, as
one just needs to copy the contents of one array into another. But
merging is not a trivial task when the two arrays are sorted and the
merged array also needs to be sorted.
• If we have two sorted arrays and the resultant merged array also needs
to be a sorted one, then the task of merging the arrays becomes a little
difficult.
Merging Two Arrays
void mergeArrays(int arr1[], int arr2[], int n1, int n2, int arr3[])
{
int i = 0, j = 0, k = 0;
while (i < n1 && j < n2)
{
if (arr1[i] < arr2[j])
arr3[k++] = arr1[i++];
else
arr3[k++] = arr2[j++];
}
while (i < n1)
arr3[k++] = arr1[i++];
while (j < n2)
arr3[k++] = arr2[j++];
}
Write a program to merge two unsorted arrays.
int main()
{int arr1[10], arr2[10], arr3[20];
int i, n1, n2, m, index=0;
printf("\n Enter the number of elements in array1 : ");
scanf("%d", &n1);
printf("\n\n Enter the elements of the first array");
for(i=0;i<n1;i++)
scanf("%d", &arr1[i]);
printf("\n Enter the number of elements in array2 : ");
scanf("%d", &n2);
printf("\n\n Enter the elements of the second array");
for(i=0;i<n2;i++)
scanf("%d", &arr2[i]);
m = n1+n2;
for(i=0;i<n1;i++)
{ arr3[index] = arr1[i];
index++;}
for(i=0;i<n2;i++)
{arr3[index] = arr2[i];
index++;}
printf("\n\n The merged array is");
for(i=0; i<m; i++)
printf("\n arr[%d] = %d", i, arr3[i]);
}
Write a program to merge two sorted arrays .
#include<stdio.h>
int main() index++;
{ int arr1[10], arr2[10], arr3[20]; }
int i, n1, n2, m, index=0; int index_first = 0, if(index_first == n1)
index_second = 0; {
printf("\n Enter the number of elements in array1 : "); while(index_second<n2)
scanf("%d", &n1); {
printf("\n\n Enter the elements of the first array"); arr3[index] = arr2[index_second];
for(i=0;i<n1;i++) index_second++;
scanf("%d", &arr1[i]); index++;
printf("\n Enter the number of elements in array2 : "); }}
scanf("%d", &n2); else if(index_second == n2)
printf("\n\n Enter the elements of the second array"); {
for(i=0;i<n2;i++) while(index_first <n1)
scanf("%d", &arr2[i]); { arr3[index] = arr1[index_first];
m = n1+n2; index_first++;
while(index_first < n1 && index_second < n2) index++;
{ }}
if(arr1[index_first]< arr2[index_second]) printf("\n\n The merged array is");
{arr3[index] = arr1[index_first]; for(i=0;i<m;i++)
index_first++; printf("\n arr[%d] = %d", i, arr3[i]);
} }
else
{ arr3[index] = arr2[index_second];
index_second++;
}
Exercise
1. Write a program to read an array of n numbers and then find the
smallest number.
2. Write a program to interchange the largest and the smallest
number in an array.
3. Write a program to transpose a 3*3 matrix.
4. Write a program to input two m *n matrices and then calculate
the sum of their corresponding elements and store it in a third
m * n matrix.
5. Write a program to multiply two m * n matrices.
6. Write a program to read a 2D array marks which stores the marks
of five students in three subjects. Write a program to display the
highest marks in each subject.

You might also like