0% found this document useful (0 votes)
15 views178 pages

Ds 2

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 explains basic terminology related to data and information, introduces data structures and their classifications, and discusses operations on data structures, algorithms, and their complexities. Additionally, it emphasizes the importance of efficiency in algorithms and the impact of data structures on performance.

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)
15 views178 pages

Ds 2

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 explains basic terminology related to data and information, introduces data structures and their classifications, and discusses operations on data structures, algorithms, and their complexities. Additionally, it emphasizes the importance of efficiency in algorithms and the impact of data structures on performance.

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/ 178

Programming with Data Structure

Dr. Dharm Raj Singh


Assistant Professor, (HOD)

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 Frequenc Total
Cost y 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. The term n2 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 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 positive 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 positive constants c and no such that:
f(n)>=c.g(n) for all n≥no and c>0
This implies that g(n) does not
grow faster than f(n) , or
g(n) is an lower bound on the
function f(n).
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)) (read as “f of n is theta of g of n”) iff there exist positive
constant c1, c2, and n0 such that
c1.g(n)<=f(n)<=c2.g(n)
for all n, n>=n0.
 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
Factorial O(n!) force 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(logn)<O(n)<O(nlogn)<O(n2)<O(n3)<O(2n)
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 as li 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
• This means c 2 = 1/2 because li m 1/2 – 2/n = 1/2 (Big O notation)
n 
• 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(*ptr) = %lu\n", sizeof(*p), sizeof(*ptr));
return 0;
} Output: p = 000000000062FDF0, ptr = 000000000062FDF0
*p = 3, *ptr = 000000000062FDF0 *ptr[0]=3
sizeof(*p) = 4, sizeof(*ptr) = 20
#include <stdio.h>
int main()
{ int *p,i;
int x[5] = { 1, 2, 3, 4, 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("\n p=%u, ptr=%d\n", p, ptr);
}
Output:
p=6487536, ptr=6487536
p=6487540, ptr=6487556
#include <stdio.h>
int main()
{
int(*p)[5]; // Pointer to an array of five numbers
int b[5] = { 1, 2, 3, 4, 5 };
int i = 0;
p = &b; // Points to the whole array b
for (i = 0; i < 5; i++)
printf("%d\t", *(*p+ i));
return 0;
}
Output : 1 2 3 4 5
Two Dimensional Array: It can be defined as ‘an Array which holds
two subscript is known as two Dimensional Array. Generally 2-D
array is called as Matrix.
Declaration One 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.
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( );
}
Row Major ordering
• In row major ordering, all the rows of the 2D array are stored into the
memory contiguously. Considering the array shown in the image, its
memory allocation according to row major order is shown as follows.
• First, the 1st row of the array is stored into the memory completely, then
the 2nd row of the array is stored into the memory completely and so on till
the last row.
Calculating the Address of the random element of a 2D array
• By Row Major Order: If array is declared by a[m][n] where m is the
number of rows while n is the number of columns, then address of an
element a[i][j] of the array stored in row major order is calculated as,
Address(a[i][j]) = B. A. + ( n*( i-l1)+( j-l2) )* size
where, B. A. is the base address or the address of the first element of
the array a[0][0] ,
n=(u2 –l2+1), and l1 is lower bound of row, l2 is lower bound of column,
u1 is upper bound of row, u2 is upper bound of column.
Example : a[10...30, 55...75], base address of the array (BA) = 0, size of
an element = 4 bytes . Find the location of a[15][68].
l1=10, l2=55,
u1=30, u2=75, n=(75-55+1)=21
Address(a[15][68]) = 0 + ( 21(15 - 10) * + (68 - 55)) * 4
= (21*5 + 13) * 4
= 118 * 4
= 472 answer
Column Major ordering
• According to the column major ordering, all the columns of the 2D array are
stored into the memory contiguously. The memory allocation of the array
which is shown in the above image is given as follows.
• first, the 1st column of the array is stored into the memory completely, then
the 2d row of the array is stored into the memory completely and so on till
the last column of the array.
Calculating the Address of the random element of a 2D array
• By Column major order: If array is declared by a[m][n] where m is
the number of rows while n is the number of columns, then address
of an element a[i][j] of the array stored in row major order is
calculated as,

Address (a[i][j]) = B. A. + ( ( i-l1)+( j-l2)*m )* size

• where, B. A. is the base address or the address of the first element


of the array a[0][0] ,
• m=(u1 –l1+1), and l1 is lower bound of row, l2 is lower bound of
column, u1 is upper bound of row, u2 is upper bound of column.
Example :
• A [5 ... 20][20 ... 70], BA = 1020, Size of element = 8 bytes. Find
the location of a[0][30].
• l1=5, u1=20, l2=20, u2=70, m=(20-5+1)=16
• Address [A[0][30]) = ((0-5) + (30-20)*16)*8) + 1020
= (-5+160)* 8 + 1020
= 2260 bytes
#include<stdio.h>
main ( )
{ int a[2] [3], i,j;
int *p;
printf ("Enter elements of 2D array \n");
for (i=0; i<2; i++)
{
for (j=0; j<3; j++)
{ scanf ("%d", &a[i] [j]);
}
}
p = &a[0] [0];
printf ("elements of 2d array are \n");
for (i=0; i<2; i++)
{
for (j=0; j<3; j++)
{ printf ("%d \t", *(p+i*3+j));
}
printf ("\n");
}
}
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, i.e. 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 2-D array 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.
• 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.
• We can say that 2-D dimensional arrays that are placed one after another.
So here arr is an 2-Darray of 3 rows where each row 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


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

*(*(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
#include <stdio.h>
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 ( "S[%d][%d]=%d ", i, j,*( *( s + i ) + j ) ) ;
}}
Output:
Address of 0 th row one D array=6487536 6487536
S[0][0]=12 S[0][1]=56
Address of 1 th row one D array=6487544 6487544
S[1][0]=12 S[1][1]=33
Address of 2 th row one D array=6487552 6487552
S[2][0]=14 S[2][1]=80
Address of 3 th row one D array=6487560 6487560
S[3][0]=13 S[3][1]=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
• Write a program to read and display a 3
* 3 matrix.
#include <stdio.h>
void display(int (*)[3]);
int main() void display(int (*mat)[3])
{ {
int i, j, mat[2][3]; int i, j;
printf("\n The elements of the matrixare ");
printf("\n Enter the elements of the matrix"); for(i = 0; i < 2; i++)
for(i=0;i<2;i++) {
{ printf("\n");
for(j=0;j<3;j++)
for(j = 0; j < 3; j++)
printf("\t %d",*(*(mat + i)+j));
{ }
scanf("%d", &mat[i][j]); }
}
}
display(mat);
return 0;
}
Array with more than two dimensions
• 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]
MULTI-DIMENSIONAL ARRAYS
• A multi-dimensional array in simple terms is an array of arrays. As we have
one index in a one dimensional array, two indices in a two-dimensional
array, in the same way, we have n indices in an n-dimensional array or
multi-dimensional array.
• An n-dimensional m1* m2* m3 *…* mn array is a collection of m1*m2* m3*…*
mn elements.
• In a multi-dimensional array, a particular element is specified by using n
subscripts as A[I1 ][I2 ][I3 ]...[In ], where I1 <=M1, I2<=M2, I3<=M3, ... In<=Mn.
• For example a three-dimensional array has three pages, four rows, and two
columns.
#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]); }
}
}
}
• To find the address of any element in 3-Dimensional arrays there are the
following two ways-
– Row Major Order
– Column Major Order
Row Major Order:
• Assuming 3 dimensions: depth, rows, and columns. The following diagram show
s the memory layout of a 3D array with , in row-major:
• Data type Array[depth][rows-size][columns-size];
• To find the address of the element using row-major order, use the following formula:
Address of A[i][j][k] = B + W *(M* N * (i-x) + N*(j-y) + (k-z))
• Here: B = Base Address (start address)
W = Weight (storage size of one element stored in the array)
M = Row (total number of rows)
N = Column (total number of columns)
P = Width (total number of cells depth-wise)
x = Lower Bound of Row
y = Lower Bound of Column
z = Lower Bound of Width
• Example: Given an array, arr[1:9, -4:1, 5:10] with a base value of 400 and the size of each
element is 2 Bytes in memory find the address of element arr[5][-1][8] with the help of row-
major order?
• Solution:
Block Subset of an element whose address to be found I = 5
Row Subset of an element whose address to be found J = -1
Column Subset of an element whose address to be found K = 8
Base address B = 400
Storage size of one element store in any array(in Byte) W = 2
Lower Limit of blocks in matrix x = 1
Lower Limit of row/start row index of matrix y = -4
Lower Limit of column/start column index of matrix z = 5
M (row) = Upper Bound – Lower Bound + 1 = 1 – (-4) + 1=> M = 6
N (Column)= Upper Bound – Lower Bound + 1 = 10 – 5 + 1 => N = 6
• Formula used: Address of[I][J][K] =B + W (M * N(i-x) + N *(j-y) + (k-z))
Address of arr[5][-1][8] = 400 + 2 * {[6 * 6 * (5 – 1)] + 6 * [(-1 + 4)]} + [8 – 5]
= 400 + 2 * (6*6*4)+(6*3)+3 = 730
To find the address of the element using column-major order, use the following formula:
Address of A[i][j][k]=B+W×(N×M×(k−z)+M×(j−y)+(i−x))
• Here: B = Base Address (start address)
W = Weight (storage size of one element stored in the array)
M = Row (total number of rows)
N = Column (total number of columns)
P = Width (total number of cells depth-wise)
x = Lower Bound of block (first subscipt)
y = Lower Bound of Row
z = Lower Bound of Column
Example: Given an array arr[1:8, -5:5, -10:5] with a base value of 400 and the size of each
element is 4 Bytes in memory find the address of element arr[3][3][3] with the help of colum
n-major order?
• Solution:
Row Subset of an element whose address to be found I = 3
Column Subset of an element whose address to be found J = 3
Block Subset of an element whose address to be found K = 3
Base address B = 400
Storage size of one element store in any array(in Byte) W = 4
Lower Limit of blocks in matrix x = 1
Lower Limit of row/start row index of matrix y = -5
Lower Limit of column/start column index of matrix z = -10
M (row)= Upper Bound – Lower Bound + 1 = 8 – 1 + 1=> M = 8
N (column)= Upper Bound – Lower Bound + 1 = 5 – (-5 ) + 1=> N = 11
• Formula used: Address of A[i][j][k]=B+W×(N×M×(k−z)+M×(j−y)+(i−x))
Address of arr[3][3][3] = 400 + 4 * ((11*8*(3-(-10)+ 8*(3-(-5)+ (3-1))
= 400 + 4 * ((88 * 13+ 8 * 8 + 2) = 5240
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");
} 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.
 Insert operation is possible only when 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
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
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.
Recursive implementation of binary search
binary_search(A, ITEM ,low,high):
if (low > high)
return False
else
mid = (low + high)/2
if (A[mid] == ITEM)
return True
elseif (A[mid] < ITEM)
return binary_search(A, ITEM ,mid+1,high)
else
return binary_search(A, ITEM ,low,mid-1)
Time Complexity of Binary Search Algorithm:
• Best case is when the element is at the middle index of the array. It takes only one
comparison to find the target element. So the best case complexity is O(1).
Average Case Time Complexity of Binary Search:
• Case1: Element is present in the array
• Case2: Element is not present in the array.
 The average case arises when the target element is present in some location other
than the central index
• The time complexity depends on the number of comparisons to find the desired element.
• In the following iterations, the size of the subarray is reduced using the result of the
previous comparison.
– Initial length of array =n
– Iteration 1 – Length of array =n/2
– Iteration 2 – Length of array =(n/2)/2=n/22
– Iteration k – Length of array =n/2k
• After k iterations, the size of the array becomes 1 (narrowed down to the first element
or last element only).
• Length of array =n/2k=1 => n=2k
Applying log function on both sides:
=> log2(n)=log2(2k)
=> log2(n)=k log22=k
=> k=log2(n)
• Therefore, the overall Average Case Time Complexity of Binary Search is O(logn).
Worst Case Time Complexity of Binary Search
The worst-case scenario of Binary Search occurs when the target element is
the smallest element or the largest element of the sorted array.
 Since the target element is present in the first or last index, there are logn
comparisons in total.
Therefore, the Worst Case Time Complexity of Binary Search is O(logn).
Case Time Complexity

Best Case O(1)


Average Case O(logn)
Worst Case O(logn)

Space Complexity of Binary Search


 In the case of the iterative approach, no extra space is used. Hence, the
space complexity is O(1).
 In the worst case, logn recursive calls are stacked in the memory.
• i comparisons require i recursive calls to be stacked in memory.
• Since average time complexity analysis has logn comparisons, the average
memory will be O(logn).
Thus, in recursive implementation the overall space complexity will
be 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 two floating point number arrays. Merge the two arrays and
display the resultant array in reverse order.
2. Write a program in C to calculate determinant of a 3 x 3 matrix.
3. Write a program in C to generate a random permutation of array elements.
4. Write a program that interchanges the odd and even components of an array.
5. Find equilibrium index of an array.
6. Shuffle a given array of elements.
7. Find majority element in an array (Boyer–Moore majority vote algorithm).
8. Find Longest Bitonic Subarray in an array.
9. Find maximum difference between two elements in the array.
10. Find the length of smallest subarray whose sum of elements is greater than the
given number.
11. Trapping Rain Water within given set of bars.
12. Find minimum platforms needed in the station so to avoid any delay in arrival of any
train.
13. Given a list of tasks with deadlines and total profit earned on completing a task, find
the maximum profit earned by executing the tasks within the specified deadlines.
Assume that each task takes one unit of time to complete, and a task can’t execute
beyond its deadline. Also, only a single task will be executed at a time.
Linked list
• Linked list is a linear data structure that includes a series of connected nodes in
which the elements are not stored at contiguous memory locations.
• Linked list can be defined as the nodes that are randomly stored in the memory.
• A node in the linked list contains two parts, i.e., first is the data part and second is
the address part. The last node of the list contains a pointer to the null.
Representation of a Linked list
Why use linked list over array?
• Linked list is a data structure that overcomes the limitations of arrays. Let's first see
some of the limitations of arrays -
• The size of the array must be known in advance before using it in the program.
• Increasing the size of the array is a time taking process. It is almost impossible to
expand the size of the array at run time.
• All the elements in the array need to be contiguously stored in the
memory. Inserting an element in the array needs shifting of all its predecessors.
• A linked list does not allow random access of data. Nodes in a linked list can be
accessed only in a sequential manner.
• Another advantage of a linked list over an array is that we can add any number of
elements in the list.
types of Linked Lists:
1. Singly linked list
2. Circular linked list
3. Doubly linked list
SINGLY LINKED LIST: A linked list in its simplest form is a
collection of nodes that together form a linear ordering.
 Each node usually consists of a structure that includes information
fields and a link fields. HEAD(start) is a pointer, which stores the
address of the first node in the linked list. Link field of the last node
contains the NULL, which indicates it does not hold any address.
SELF-REFERENTIAL STRUCTURES
• Self-referential structures are those structures that contain a reference
to the data of its same type.
• Self Referential structures are those structures that have one or more
pointers which point to the same type of structure, as their member.
For example,
struct node {
int val;
struct node *next;
};
• Here, the structure node will contain two types of data: an integer
val and a pointer next.
• Self-referential structure is the foundation of other data structures.
Definition of a NODE of a Linked list in C
Struct Node
{
Data type information;
Struct Node *Link;
};

1. Once the structure of a node is defined we may want to allocate memory


space for the nodes of the linked list. Memory space is always allocated
with the help of a declaration statement.
2. A structure called Node which has two fields, Information and Link.
3. information will store the information part and Link will store the
address of the next node in sequence.
4. Every node contains a pointer to another node which is of the same
type, it is also called a self-referential data type.
For example If we want to create a linked list that contains three nodes
called Node1, Node2 and Node3 the declaration may be as follows.
struct Node * Node1, *Node2, *Node3;
DIFFERENT OPERATIONS POSSIBLE ON A LINKED LIST
1. Creating a linked list
2. Traversing a linked list.
3. Inserting an item into a linked list.
4. Deleting an item from the linked list.
5. Searching an item in a linked list.
Creating a Linked List
 To create a linked list, which contains nodes, where we do not know
how many elements are to be created in a linked list.
 To create a list components are dynamically created as they are
needed using pointers and dynamic memory allocation function
such as malloc( ).
 We start accessing the list with a pointer variable that holds the
address of the first node in the list.
Example create and allocate memory for 3 nodes
struct node
{ int data;
struct node *next;
};
struct node *head,*middle,*last; //declaring nodes
//allocating memory for each node
head = (node*)malloc(sizeof(struct node));
middle = (node*)malloc(sizeof(struct node));
last = (node*) malloc(sizeof(struct node));
head->data = 10; head->next=middle;
middle->data = 20; middle->next=last;
last->data = 30; last->next= NULL;
1. Stack memory stores all the local variables and function calls
(static memory).
2. Heap memory stores all the dynamically allocated variables.
Example: int *ptr = malloc(sizeof(int)); Here, memory will be allocated
in the heap section. And the ptr resides in the stack section and
receives the heap section memory address on successful memory
allocation.
3. Address of the dynamic memory which will be assigned to the
corresponding variable.
Difference Between Stack and Heap
Feature Stack Heap
Automatically managed by the CPU. Memory must be manually managed.
Memory
Management
Memory is allocated and deallocated as Programmers allocate and free
functions are called and finishes execution. memory as needed.
Allocation Slower because it involves finding a
Fast because it involves moving the stack
and free block of memory of sufficient
Deallocation pointer.
size.
The size of the stack is determined at the The heap can dynamically grow and
start of the program and can be limited, If shrink at runtime, heap provides a
Size
too many function calls exceed the stack’s larger memory space compared to the
capacity, it results in a stack overflow error. stack
Used for dynamic memory allocation.
Used for static memory allocation. Ideal for
Ideal for objects or data structures
temporary variables or data that is not
Usage whose size may change at runtime or
required to exist outside the scope of a
whose lifetime must extend beyond
function call.
the scope in which they were created.
Since memory is managed by the system, it Slower than stack memory due
Access Time is fast and efficient because of its LIFO to manual allocation and garbage
(Last In, First Out) nature. collection
#include<stdio.h> while(choice)
#include<malloc.h> {
last=(NODE *)malloc(sizeof(NODE));
int main() printf("Enter the next data item\n");
{ scanf("%d",&last->num);
struct node{ last->link=NULL;
temp->link=last;
int num; temp=last;
struct node *link; printf("Do you want to continue(type 0 or 1)?\n");
}; scanf("%d",&choice);
}
typedef struct node NODE; temp->link=NULL;
NODE *last, *first, *temp; temp=first;
int count=0; printf("Status of the linked list is\n");
while(temp!=NULL)
int choice=1; {
first= (NODE *)malloc(sizeof(NODE)); printf("%d->",temp->num);
//first=new(NODE); in C++ count++;
temp=temp->link;
printf("input the value of first node1"); }
scanf("%d",&first->num); printf("NULL");
first->link=NULL; printf("\n NO of nodes in the list =%d",count);
}
temp=first;
Traversing a Linked List
• Traversing a linked list means accessing the nodes of the list in order
to perform some processing on them. Remember a linked list always
contains a pointer variable START which stores the address of the
first node of the list. End of the list is marked by storing NULL or –1
in the NEXT field of the last node.

Step 1: [INITIALIZE] SET PTR = START


Step 2: Repeat Steps 3 and 4 while PTR != NULL
Step 3: Apply Process to PTR-> DATA
Step 4: SET PTR = PTR-> NEXT
[END OF LOOP]
Step 5: EXIT
Traversing a Linked List
#include<stdlib.h> temp=first;
struct node for(i=1;i<n; i++)
{ {
int data; last =(node *)malloc(sizeof(node));
node *link; scanf("%d",&last->data);
}; last->link=NULL;
int main() temp->link=last;
temp=last;
{
}
struct node *first, *temp,*last;
temp=first;
int n, i;
while(temp!=NULL)
printf("input how many nodes to create in {
list=");
printf("%d->",temp->data);
scanf("%d", &n); temp=temp->link;
first=(node *)malloc(sizeof(node)); }
printf("input data value of node1"); }
scanf("%d", &first->data);
first->link=NULL;
Searching for a Value in a Linked List
• Searching a linked list means to find a particular element in
the linked list. searching means finding whether a given
value is present in the information part of the node or not. If
it is present, the algorithm returns the address of the node
that contains the value.
Step 1: SET PTR = START
Step 2: Repeat Step 3 while PTR != NULL
Step 3: IF PTR-> DATA == ITEM
SET POS = PTR Go To Step 5
ELSE
SET PTR = PTR ->NEXT
[END OF IF]
[END OF LOOP]
Step 4: SET POS = NULL
Step 5: EXIT
#include<stdio.h>
#include<stdlib.h> printf("input serch item“);
struct node scanf(“%d”, &item);
{ int data; temp=first;
node *link; int f=0;
}; i=1;
int main() while(temp!=NULL)
{ struct node *first, *temp,*last; {
int n, i, item; if(temp->data==item)
printf("input how many nodes to create ="); { printf("find item %d", i);
scanf(“%d”,&n); f++;
first=(node *)malloc(sizeof(node)); break;
printf("input data value of node1“); }
scanf(“%d”, &first->data); temp=temp->link;
first->link=NULL; i++;
temp=first; }
for(i=1;i<n; i++) if(f==0)
{ { printf( "not find“);
last=(node *)malloc(sizeof(node)); } }
scanf(“%d”, &last->data);
last->link=NULL;
temp->link=last;
temp=last;
}
Inserting a New Node in a Linked List
• We will take four cases and then see how insertion is done in
each case.
Case 1: The new node is inserted at the beginning.
Case 2: The new node is inserted at the end.
Case 3: The new node is inserted after a given node.
Case 4: The new node is inserted before a given node.
Inserting a Node at the Beginning of a Linked List

Step 1: IF AVAIL = NULL


Write OVERFLOW Go to Step 7
[END OF IF]
Step 2: SET NEW_NODE = AVAIL
Step 3: SET AVAIL = AVAIL-> NEXT
Step 4: SET NEW_NODE-> DATA = VAL
Step 5: SET NEW_NODE ->NEXT = START
Step 6: SET START = NEW_NODE
Step 7: EXIT
#include<iostream> for(i=1;i<n; i++)
#include<stdlib.h> {
using namespace std; last= (node*)malloc(sizeof(node));
scanf("%d", &last->data);
struct node last-> next =NULL;
{ int data; temp-> next =last;
node * next; temp=last;
}; }
int main()
printf(" input new node value");
{ scanf(“%d”,&item);
struct node *first, *temp,*last, *newnode; newnode= (node*)malloc(sizeof(node));
int n, i, item; newnode->data=item;
printf("input how many nodes in list="); newnode-> next =first;
scanf("%d", &n); first=newnode;
temp=first;
first=(node *)malloc(sizeof(node)); while(temp!=NULL)
printf(" input data value of node1"); {
scanf("%d", &first->data); printf(" %d ->", temp->data);
first-> next =NULL; temp=temp-> next;
temp=first; }
}
Inserting a Node at the End of a Linked List
Step 1: IF AVAIL = NULL
Write OVERFLOW Go to Step 10
[END OF IF]
Step 2: SET NEW_NODE = AVAIL
Step 3: SET AVAIL = AVAIL-> NEXT
Step 4: SET NEW_NODE->DATA = VAL
Step 5: SET NEW_NODE->NEXT = NULL
Step 6: SET PTR = START
Step 7: Repeat Step 8 while PTR ->NEXT != NULL
Step 8: SET PTR = PTR-> NEXT
[END OF LOOP]
Step 9: SET PTR ->NEXT = NEW_NODE
Step 10: EXIT
#include<stdio.h> for(i=1;i<n; i++)
#include<stdlib.h> { last= (node *)malloc(sizeof(node));
scanf("%d", &last->data);
struct node
last-> next =NULL;
{ int data; temp-> next =last;
node * next; temp=last;
}; }
printf(" input new node value at end");
int main() scanf("%d",&item);
{ newnode= (node *)malloc(sizeof(node));
struct node *first, *temp,*last, *newnode; newnode->data=item;
int n, i, item; newnode-> next =NULL;
temp=first;
printf("input how many nodes in list="); while(temp->next!=NULL)
scanf("%d", &n); {
First=(node *)malloc(sizeof(node)); temp=temp->next;
}
// First=new node; in C++
temp->next=newnode;
printf(" input data value of node1"); temp=first;
scanf("%d", &first->data); while(temp!=NULL)
first-> next =NULL; {
printf(" %d ->", temp->data);
temp=first;
temp=temp-> next;
}
}
Algorithm to insert a new node after a node that has value NUM
Step 1: IF AVAIL = NULL
Write OVERFLOW Go to Step 12
[END OF IF]
Step 2: SET NEW_NODE = AVAIL
Step 3: SET AVAIL = AVAIL ->NEXT
Step 4: SET NEW_NODE ->DATA = VAL
Step 5: SET PTR = START
Step 6: SET PREPTR = PTR
Step 7: Repeat Steps 8 and 9 while PREPTR->DATA != NUM
Step 8: SET PREPTR = PTR
Step 9: SET PTR = PTR ->NEXT
[END OF LOOP]
Step 10 : PREPTR ->NEXT = NEW_NODE
Step 11: SET NEW_NODE-> NEXT = PTR
Step 12: EXIT
struct node printf(" input insert new node value ");
{ int data; scanf("%d",&item);
node * next; printf(" \n Enter the value before which
}; new node has to be inserted :");
int main() scanf(" %d" , &val);
{ struct node *first, *temp,*last, *newnode, newnode= (node *)malloc(sizeof(node));
*preptr; newnode->data=item;
int n, i, item, val;
printf("input how many nodes in list="); temp=first;
scanf("%d", &n); while(temp->data!=val)
first=(node *)malloc(sizeof(node)); {
printf(" input data value of node1"); preptr=temp;
scanf("%d", &first->data); temp=temp-> next;
first-> next =NULL; }
temp=first; preptr -> next = newnode;
for(i=1;i<n; i++) newnode -> next = temp;
{ temp=first;
last=(node *)malloc(sizeof(node)); while(temp!=NULL)
scanf("%d", &last->data); {
last-> next =NULL; printf(" %d ->", temp->data);
temp-> next =last; temp=temp-> next;
temp=last; }
} }
Inserting a Node Before a Given Node in a Linked List
Step 1: IF AVAIL == NULL
Write OVERFLOW Go to Step 12
[END OF IF]
Step 2: SET NEW_NODE = AVAIL
Step 3: SET AVAIL = AVAIL-> NEXT
Step 4: SET NEW_NODE ->DATA = VAL
Step 5: SET PTR = START
Step 6: SET PREPTR = PTR
Step 7: Repeat Steps 8 and 9 while PTR-> DATA != NUM
Step 8: SET PREPTR = PTR
Step 9: SET PTR = PTR-> NEXT
[END OF LOOP]
Step 10: PREPTR-> NEXT = NEW_NODE
Step 11: SET NEW_NODE ->NEXT = PTR
Step 12: EXIT
Algorithm to delete the first node

Step 1: IF START = NULL


Write UNDERFLOW Go to Step 5
[END OF IF]
Step 2: SET PTR = START
Step 3: SET START = START ->NEXT
Step 4: FREE PTR
Step 5: EXIT
struct node for(i=1;i<n; i++)
{ int data; {
node * next; last =(node*)malloc(sizeof(node));
}; scanf("%d", &last->data);
int main() last-> next =NULL;
{ temp-> next =last;
struct node *first, *temp,*last, *temp1; temp=last;
int n, i; }
printf("input how many nodes in list="); temp=first;
scanf("%d", &n); first=first->next;
first=(node *)malloc(sizeof(node)); free (temp);
printf(" input data value of node1"); temp1=first;
scanf("%d", &first->data); while(temp1!=NULL)
first-> next =NULL; {
temp=first; printf(" %d ->", temp1->data);
temp1=temp1-> next;
}
}
Algorithm to delete the last node

Step 1: IF START = NULL


Write UNDERFLOW Go to Step 8
[END OF IF]
Step 2: SET PTR = START
Step 3: Repeat Steps 4 and 5 while PTR-> NEXT != NULL
Step 4: SET PREPTR = PTR
Step 5: SET PTR = PTR ->NEXT
[END OF LOOP]
Step 6: SET PREPTR ->NEXT = NULL
Step 7: FREE PTR
Step 8: EXIT
struct node temp=first;
{ int data; while(temp -> next != NULL)
node *next; {
}; preptr = temp;
int main() temp= temp ->next;
{ struct node *first, *temp,*last, *temp1, }
*preptr; preptr ->next =NULL;
int n, i; free(temp);
printf("input how many nodes in list="); temp1=first;
scanf("%d", &n); while(temp1!=NULL)
first=(node *)malloc(sizeof(node)); { printf(" %d ->", temp1->data);
printf(" input data value of nodes"); temp1=temp1-> next;
scanf("%d", &first->data); }}
first-> next =NULL;
temp=first;
for(i=1;i<n; i++)
{ last =(node *)malloc(sizeof(node));
scanf("%d", &last->data);
last->next =NULL;
temp->next =last;
temp=last;
}
Algorithm to delete the node after a given node

Step 1: IF START = NULL


Write UNDERFLOW Go to Step 10
[END OF IF]
Step 2: SET PTR = START
Step 3: SET PREPTR = PTR
Step 4: Repeat Steps 5 and 6 while PREPTR ->DATA != NUM
Step 5: SET PREPTR = PTR
Step 6: SET PTR = PTR ->NEXT
[END OF LOOP]
Step 7: SET TEMP = PTR
Step 8: SET PREPTR ->NEXT = PTR ->NEXT
Step 9: FREE TEMP
Step 1 0: EXIT
struct node printf("\n Enter the value after which
{ int data; the node has to deleted : ");
node *next; scanf("%d", &val);
}; temp=first;
int main() preptr = temp;
{ struct node *first, *temp,*last, *temp1, while(preptr -> data != val)
*preptr; {
int n, i, val; preptr = temp;
printf("input how many nodes in list="); temp= temp ->next;
scanf("%d", &n); }
first=(node *)malloc(sizeof(node)); preptr ->next =temp -> next;
printf(" input data value of nodes"); free(temp);
scanf("%d", &first->data); temp1=first;
first-> next =NULL; while(temp1!=NULL)
temp=first; {
for(i=1;i<n; i++) printf(" %d ->", temp1->data);
{ last =(node *)malloc(sizeof(node)); temp1=temp1-> next;
scanf("%d", &last->data); }
last->next =NULL; }
temp->next =last;
temp=last;
}
APPLICATIONS OF LINKED LISTS
• Polynomial Representation
• Let us see how a polynomial is represented in the memory using a linked
list. Consider a polynomial 6x3 + 9x2 + 7x + 1. Every individual term in a
polynomial consists of two parts, a coefficient and a power.
• Here, 6, 9, 7, and 1 are the coefficients of the terms that have 3, 2, 1, and 0
as their powers respectively.

Linked representation of a polynomial


• Implementation of Stacks and Queues: Stacks and Queues, as the most
fundamental data structures, are usually implemented as singly linked lists.
• Graph Representation: In graph theory, singly linked lists are the representations
of adjacency lists, an important part also to search algorithms like BFS and DFS.
• Sparse Matrix Representation: Singly linked lists store non-zero elements of a
sparse matrix, saving memory by avoiding the storage of unnecessary zero values.
• Database Management Systems: In databases, singly linked lists are used to
manage dynamic collections of data, such as tables or records, which can grow or
shrink as needed.
Applications of linked list in the real world:
• Undo Functionality: Singly Linked Lists are used in applications that require
undo functionality, such as text editors or drawing programs. Each action
performed by the user can be stored as a node in the list, allowing the user to
undo previous actions by traversing the list.
• Queue Implementation: Singly Linked Lists are used to implement queues,
particularly in applications where dynamic resizing is required. In a queue, each
node represents an element in the queue, with the next pointer pointing to the
next element in the queue.
• Music Playlist: Singly Linked Lists can be used to implement music playlists in
music player applications. Each node in the list represents a song, with the next
pointer pointing to the next song in the playlist.
• Navigation Systems: Singly Linked Lists are used in navigation systems to
represent routes or paths. Each node in the list represents a waypoint or
destination, with the next pointer pointing to the next waypoint in the route.
• GPS navigation systems- Linked lists can be used to store and manage a list of
locations and routes, allowing users to easily navigate to their desired destination.
• Task Scheduling- Operating systems use linked lists to manage task scheduling,
where each process waiting to be executed is represented as a node in the list.
• Image Processing- Linked lists can be used to represent images, where each
pixel is represented as a node in the list.
Advantages of Singly Linked Lists
• Singly linked lists in data structures can grow and shrink during runtime
as needed without a predefined size.
• They only allocate memory for nodes that are actually in use, reducing
memory waste compared to pre-allocated data structures like arrays.
• Adding or removing nodes doesn't require shifting elements, which can
be a costly operation in arrays. This is particularly beneficial at the
beginning of the list.
• Unlike arrays, linked lists don’t reserve memory in advance, which can
be more efficient for certain types of applications where the size of the
data structure fluctuates.
Disadvantages of Singly Linked Lists
• Accessing an element in a singly linked list requires traversal from the
head to the point of interest, which can be time-consuming.
• Each node in a singly linked list requires additional memory for the pointer
alongside the actual data.
• Implementing a singly linked list is more complex than using an array,
particularly when it comes to handling pointers.
CIRCULAR LINKED LIST
• In a circular linked list, the last node contains a pointer to the first
node of the list. so the link part of the last node holds the first node's
address.
• The circular linked list has no starting and ending node. We can
traverse in any direction, i.e., either backward or forward.
• Circular linked lists are widely used in operating systems for task
maintenance.
#include<stdio.h> for(i=1;i<n; i++)
#include<stdlib.h> {
struct node last =(node *)malloc(sizeof(node));
{ int data; scanf("%d", &last->data);
node *link; last->link=first;
}; temp->link=last;
int main() temp=last;
}
{
struct node *first, *temp,*last, *temp1;
temp1=first;
int n, i; while(temp1->link!=first)
printf("input how many nodes in list="); {
scanf("%d", &n); printf(" %d -> %d->", temp1->data, temp1->link);
First=(node *)malloc(sizeof(node)); temp1=temp1->link;
printf(" input data value of nodes"); }
scanf("%d", &first->data); printf(" %d -> %d->", temp1->data, temp1->link);
first->link=first; }
temp=first;
Inserting a Node at the Beginning of a Circular Linked List

Step 1: IF AVAIL = NULL


Write OVERFLOW Go to Step 11
[END OF IF]
Step 2: SET NEW_NODE = AVAIL
Step 3: SET AVAIL = AVAIL-> NEXT
Step 4: SET NEW_NODE-> DATA = VAL
Step 5: SET PTR = START
Step 6: Repeat Step 7 while PTR ->NEXT != START
Step 7: PTR = PTR-> NEXT
[END OF LOOP]
Step 8: SET NEW_NODE-> NEXT = START
Step 9: SET PTR-> NEXT = NEW_NODE
Step 10 : SET START = NEW_NODE
Step 11: EXIT
struct node temp->link=last;
{ int data; temp=last;
node *link; }
}; printf("input new node at begining");
int main() scanf("%d",&val);
{ newnode =(node *)malloc(sizeof(node));
struct node *first, *temp,*last, *temp1, newnode->data=val;
*newnode; temp=first;
int n, i, val; while(temp->link!=first)
printf("input how many nodes in list="); {temp= temp->link;
scanf("%d", &n); }
first=(node *)malloc(sizeof(node)); temp->link=newnode;
printf(" input data value of nodes"); newnode->link=first;
scanf("%d", &first->data); first=newnode;
first->link=first; temp1=first;
temp=first; while(temp1->link!=first)
for(i=1;i<n; i++) { printf(" %d ->", temp1->data);
{ last=new node; temp1=temp1->link;
}
scanf("%d", &last->data);
printf(" %d ->", temp1->data);
last->link=first; }
Inserting a Node at the End of a Circular Linked List

Step 1: IF AVAIL = NULL


Write OVERFLOW Go to Step 10
[END OF IF]
Step 2: SET New_node = AVAIL
Step 3: SET AVAIL = AVAIL-> NEXT
Step 4: SET New_node->DATA = VAL
Step 5: SET New_node-> NEXT = START
Step 6: SET PTR = START
Step 7: Repeat Step 8 while PTR ->NEXT != START
Step 8: SET PTR = PTR ->NEXT
[END OF LOOP]
Step 9: SET PTR ->NEXT = New_node
Step 10 : EXIT
struct node temp->link=last;
{ int data; temp=last;
node *link; }
}; printf("input new node at end");
int main() scanf("%d",&val);
{ newnode =(node *)malloc(sizeof(node));
struct node *first, *temp,*last, *temp1, newnode->data=val;
*newnode; temp=first;
int n, i, val; while(temp->link!=first)
printf("input how many nodes in list="); { temp= temp->link;
scanf("%d", &n); }
first=(node *)malloc(sizeof(node)); temp->link=newnode;
printf(" input data value of nodes"); newnode->link=first;
scanf("%d", &first->data); temp1=first;
first->link=first; while(temp1->link!=first)
temp=first; {
for(i=1;i<n; i++) printf(" %d ->", temp1->data);
{ last=(node *)malloc(sizeof(node)); temp1=temp1->link;
scanf("%d", &last->data); }
last->link=first; printf(" %d ->", temp1->data);
}
Deleting the First Node from a Circular Linked List

Step 1: IF START = NULL


Write UNDERFLOW Go to Step 8
[END OF IF]
Step 2: SET PTR = START
Step 3: Repeat Step 4 while PTR ->NEXT != START
Step 4: SET PTR = PTR-> NEXT
[END OF LOOP]
Step 5: SET PTR-> NEXT = START ->NEXT
Step 6: FREE START
Step 7: SET START = PTR- >NEXT
Step 8: EXIT
struct node temp->link=last;
{ int data; temp=last;
node *link; }
}; printf("delet first node");
int main() temp=first;
{ while(temp->link!=first)
struct node *first, *temp,*last, *temp1; {temp= temp->link;
int n, i; }
printf("input how many nodes in list="); temp->link=first->link;
scanf("%d", &n); free(first);
first=(node *)malloc(sizeof(node)); first=temp->link;
printf(" input data value of nodes"); temp1=first;
scanf("%d", &first->data); while(temp1->link!=first)
first->link=first; {
temp=first; printf(" %d ->", temp1->data);
for(i=1;i<n; i++) temp1=temp1->link;
{ }
last= (node *)malloc(sizeof(node)); printf(" %d ->", temp1->data);
scanf("%d", &last->data); }
last->link=first;
Deleting the Last Node from a Circular Linked List

Step 1: IF START = NULL


Write UNDERFLOW Go to Step 8
[END OF IF]
Step 2: SET PTR = START
Step 3: Repeat Steps 4 and 5 while PTR-> NEXT != START
Step 4: SET PREPTR = PTR
Step 5: SET PTR = PTR ->NEXT
[END OF LOOP]
Step 6: SET PREPTR ->NEXT = START
Step 7: FREE PTR
Step 8: EXIT
struct node temp->link=last;
{ int data; temp=last;
node *link; }
};
int main() printf("delet last node");
{ temp=first;
struct node *first, *temp,*last, *temp1, *pr while(temp->link!=first)
eptr; { preptr=temp;
int n, i; temp= temp->link;
printf("input how many nodes in list="); }
scanf("%d", &n); preptr -> link = temp->link;
first=new node; free(temp);
//(node *)malloc(sizeof(node)); temp1=first;
printf(" input data value of nodes"); while(temp1->link!=first)
scanf("%d", &first->data); {
first->link=first; printf(" %d ->", temp1->data);
temp=first; temp1=temp1->link;
for(i=1;i<n; i++) }
{ printf(" %d ->", temp1->data);
last= (node *)malloc(sizeof(node)); }
scanf("%d", &last->data);
last->link=first;
Application of Circular Linked Lists
• Music or Media Player: Circular linked lists can be used to create a
playlist for a music or media player. The playlist can be represented as a
circular linked list, where each node contains information about a song or
media item, and the next node points to the next song in the playlist. This
allows for continuous playback of the playlist.
• Hash table implementation: Circular linked lists can be used to implement
a hash table, where each index in the table is a circular linked list. This is a
form of collision resolution, where when two keys hash to the same index,
the nodes are added to the circular linked list at that index.
• Navigation systems: Circular linked lists can be used to model the movem
ents of vehicles on a circular route, such as buses, trains or planes that
travel in a loop or circular route. Each node in the list represents the
location of the vehicle on the route, with the next node pointing to the next
location on the route.
• It is used for time-sharing among different users, typically through a Round
-Robin scheduling mechanism.

You might also like