0% found this document useful (0 votes)
31 views25 pages

Datastructure Unit 1

The document provides an introduction to data structures and their organization. It defines key terms like data, data items, entities, fields, records, files, and keys. It also classifies data structures as primitive (basic data types) and non-primitive, with non-primitive structures further divided into linear structures (arrays, queues, stacks, linked lists) and non-linear structures (trees, graphs). Common data structure operations like traversing, searching, inserting, and deleting are outlined. Algorithms are described as procedures for searching, sorting, inserting, updating, and deleting items in a data structure.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
0% found this document useful (0 votes)
31 views25 pages

Datastructure Unit 1

The document provides an introduction to data structures and their organization. It defines key terms like data, data items, entities, fields, records, files, and keys. It also classifies data structures as primitive (basic data types) and non-primitive, with non-primitive structures further divided into linear structures (arrays, queues, stacks, linked lists) and non-linear structures (trees, graphs). Common data structure operations like traversing, searching, inserting, and deleting are outlined. Algorithms are described as procedures for searching, sorting, inserting, updating, and deleting items in a data structure.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 25

UNIT 1: INTRODUCTION

DATA STRUCTURES
Data may be organized in many different ways. The logical or mathematical model of a
particular organization of data is called a data structure.
The choice of a particular data model depends on the two considerations
1. It must be rich enough in structure to mirror the actual relationships of the data in the real
world.
2. The structure should be simple enough that one can effectively process the data whenever
necessary.
Basic Terminology: Elementary Data Organization:
Data: Data are simply values or sets of values.
Data items: Data items refers to a single unit of values.
Data items that are divided into sub-items are called Group items. Ex: An Employee Name may be
divided into three subitems- first name, middle name, and last name.
Data items that are not able to divide into sub-items are called Elementary items.
Ex: SSN
Entity: An entity is something that has certain attributes or properties which may be assigned values.
The values may be either numeric or non-numeric.
Ex: Attributes- Names, Age, Sex, SSN
Values- Rohland Gail, 34, F, 134-34-5533
Entities with similar attributes form an entity set. Each attribute of an entity set has a range of
values, the set of all possible values that could be assigned to the particular attribute.
The term “information” is sometimes used for data with given attributes, of, in other words
meaningful or processed data.
Field is a single elementary unit of information representing an attribute of an entity.
Record is the collection of field values of a given entity.
File is the collection of records of the entities in a given entity set.
Each record in a file may contain many field items but the value in a certain field may
uniquely determine the record in the file. Such a field K is called a primary key and the values k1,
k2, ….. in such a field are called keys or key values.
Records may also be classified according to length.
A file can have fixed-length records or variable-length records.
 In fixed-length records, all the records contain the same data items with the same amount of
space assigned to each data item.
 In variable-length records file records may contain different lengths.
Example: Student records have variable lengths, since different students take different numbers of
courses. Variable-length records have a minimum and a maximum length.
The above organization of data into fields, records and files may not be complex enough to maintain
and efficiently process certain collections of data. For this reason, data are also organized into more
complex types of structures.

1
The study of complex data structures includes the following three steps:
1. Logical or mathematical description of the structure
2. Implementation of the structure on a computer
3. Quantitative analysis of the structure, which includes determining the amount of memory
needed to store the structure and the time required to process the structure.
CLASSIFICATION OF DATA STRUCTURES
Data structures are generally classified into
 Primitive data Structures
 Non-primitive data Structures
1. Primitive data Structures: Primitive data structures are the fundamental data types which are
supported by a programming language. Basic data types such as integer, real, character and Boolean
are known as Primitive data Structures. These data types consists of characters that cannot be divided
and hence they also called simple data types.
2. Non- Primitive data Structures: Non-primitive data structures are those data structures which
are created using primitive data structures. Examples of non-primitive data structures is the
processing of complex numbers, linked lists, stacks, trees, and graphs.
Based on the structure and arrangement of data, non-primitive data structures is further classified
into
1. Linear Data Structure
2. Non-linear Data Structure
1. Linear Data Structure:
A data structure is said to be linear if its elements form a sequence or a linear list. There are
basically two ways of representing such linear structure in memory.
1. One way is to have the linear relationships between the elements represented by means of
sequential memory location. These linear structures are called arrays.
2. The other way is to have the linear relationship between the elements represented by means
of pointers or links. These linear structures are called linked lists.
The common examples of linear data structure are Arrays, Queues, Stacks, Linked lists
2. Non-linear Data Structure:
A data structure is said to be non-linear if the data are not arranged in sequence or a linear.
The insertion and deletion of data is not possible in linear fashion. This structure is mainly used to
represent data containing a hierarchical relationship between elements. Trees and graphs are the
examples of non-linear data structure.
Arrays:
The simplest type of data structure is a linear (or one dimensional) array. A list of a finite
number n of similar data referenced respectively by a set of n consecutive numbers, usually 1, 2, 3 . .
. . . . . n. if A is chosen the name for the array, then the elements of A are denoted by subscript
notation a1, a2, a3….. an
or
by the parenthesis notation A (1), A (2), A (3) . . . . . . A (n)
or
2
by the bracket notation A [1], A [2], A [3] . . . . . . A [n]
Linear arrays are called one-dimensional arrays because each element in such an array is
referenced by one subscript. A two-dimensional array is a collection of similar data elements where
each element is referenced by two subscripts.
Example A chain of 28 stores, each store having 4 departments, may list its weekly sales as in below
fig. Such data can be stored in the computer using a two-dimensional array in which the first
subscript denotes the store and the second subscript the department. If SALES is the name given to
the array, then
SALES [1, 1] = 2872, SALES [1, 2] - 805, SALES [1, 3] = 3211,…., SALES [28, 4] = 982
Trees
Data frequently contain a hierarchical relationship between various elements. The data
structure which reflects this relationship is called a rooted tree graph or a tree.
Some of the basic properties of tree are explained by means of examples
Example 1: Record Structure
Although a file may be maintained by means of one or more arrays a record, where one indicates
both the group items and the elementary items, can best be described by means of a tree structure.
For example, an employee personnel record may contain the following data items:
Social Security Number, Name, Address, Age, Salary, Dependents
However, Name may be a group item with the sub-items Last, First and MI (middle initial).
Also Address may be a group item with the subitems Street address and Area address, where Area
itself may be a group item having subitems City, State and ZIP code number.
This hierarchical structure:
Some of the data structures are briefly described below.
1. Stack: A stack, also called a fast-in first-out (LIFO) system, is a linear list in which insertions and
deletions can take place only at one end, called the top. This structure is similar in its operation to a
stack of dishes on a spring system as shown in fig.
Note that new 4 dishes are inserted only at the top of the stack and dishes can be deleted only from
the top of the Stack.
2. Queue: A queue, also called a first-in first-out (FIFO) system, is a linear list in which deletions
can take place only at one end of the list, the "from'' of the list, and insertions can take place only at
the other end of the list, the “rear” of the list.
This structure operates in much the same way as a line of people waiting at a bus stop, as pictured in
Fig. the first person in line is the first person to board the bus. Another analogy is with automobiles
waiting to pass through an intersection the first car in line is the first car through.
3. Graph: Data sometimes contain a relationship between pairs of elements which is not necessarily
hierarchical in nature. For example, suppose an airline flies only between the cities connected by
lines in Fig. The data structure which reflects this type of relationship is called a graph.
DATA STRUCTURES OPERATIONS
The data appearing in data structures are processed by means of certain operations.
The following four operations play a major role in this text:
1. Traversing: accessing each record/node exactly once so that certain items in the record may be
processed. (This accessing and processing is sometimes called “visiting” the record.)
3
2. Searching: Finding the location of the desired node with a given key value, or finding the
locations of all such nodes which satisfy one or more conditions.
3. Inserting: Adding a new node/record to the structure.
4. Deleting: Removing a node/record from the structure.
The following two operations, which are used in special situations:
1. Sorting: Arranging the records in some logical order (e.g., alphabetically according to some
NAME key, or in numerical order according to some NUMBER key, such as social security number
or account number)
2. Merging: Combining the records in two different sorted files into a single sorted file.
Algorithm
From the data structure point of view, following are some important categories of algorithms −
 Search − Algorithm to search an item in a data structure.
 Sort − Algorithm to sort items in a certain order.
 Insert − Algorithm to insert item in a data structure.
 Update − Algorithm to update an existing item in a data structure.
 Delete − Algorithm to delete an existing item from a data structure.
Characteristics of an Algorithm
Not all procedures can be called an algorithm. An algorithm should have the following
characteristics −
 Unambiguous − Algorithm should be clear and unambiguous. Each of its steps (or phases),
and their inputs/outputs should be clear and must lead to only one meaning.
 Input − An algorithm should have 0 or more well-defined inputs.
 Output − An algorithm should have 1 or more well-defined outputs, and should match the
desired output.
 Finiteness − Algorithms must terminate after a finite number of steps.
 Feasibility − Should be feasible with the available resources.
 Independent − An algorithm should have step-by-step directions, which should be
independent of any programming code.
How to Write an Algorithm?
There are no well-defined standards for writing algorithms. Rather, it is problem and resource
dependent. Algorithms are never written to support a particular programming code.
As we know that all programming languages share basic code constructs like loops (do, for,
while), flow-control (if-else), etc. These common constructs can be used to write an algorithm.
We write algorithms in a step-by-step manner, but it is not always the case. Algorithm
writing is a process and is executed after the problem domain is well-defined. That is, we should
know the problem domain, for which we are designing a solution.
Example
Let's try to learn algorithm-writing by using an example.
Problem − Design an algorithm to add two numbers and display the result.
Step 1 − START
4
Step 2 − declare three integers a, b & c
Step 3 − define values of a & b
Step 4 − add values of a & b
Step 5 − store output of step 4 to c
Step 6 − print c
Step 7 − STOP
Algorithms tell the programmers how to code the program. Alternatively, the algorithm can be
written as −
Step 1 − START ADD
Step 2 − get values of a & b
Step 3 − c ← a + b
Step 4 − display c
Step 5 − STOP
In design and analysis of algorithms, usually the second method is used to describe an
algorithm. It makes it easy for the analyst to analyze the algorithm ignoring all unwanted definitions.
He can observe what operations are being used and how the process is flowing.
Writing step numbers, is optional.
We design an algorithm to get a solution of a given problem. A problem can be solved in
more than one ways.

Hence, many solution algorithms can be derived for a given problem. The next step is to
analyze those proposed solution algorithms and implement the best suitable solution.
Algorithm Analysis
Efficiency of an algorithm can be analyzed at two different stages, before implementation and after
implementation. They are the following −
 A Priori Analysis − This is a theoretical analysis of an algorithm. Efficiency of an algorithm
is measured by assuming that all other factors, for example, processor speed, are constant and
have no effect on the implementation.

5
 A Posterior Analysis − This is an empirical analysis of an algorithm. The selected algorithm
is implemented using programming language. This is then executed on target computer
machine. In this analysis, actual statistics like running time and space required, are collected.
We shall learn about a priori algorithm analysis. Algorithm analysis deals with the execution or
running time of various operations involved. The running time of an operation can be defined as the
number of computer instructions executed per operation.
Algorithm Complexity
Suppose X is an algorithm and n is the size of input data, the time and space used by the algorithm X
are the two main factors, which decide the efficiency of X.
 Time Factor − Time is measured by counting the number of key operations such as
comparisons in the sorting algorithm.
 Space Factor − Space is measured by counting the maximum memory space required by the
algorithm.
The complexity of an algorithm f(n) gives the running time and/or the storage space required by
the algorithm in terms of n as the size of input data.
Space Complexity
Space complexity of an algorithm represents the amount of memory space required by the algorithm
in its life cycle. The space required by an algorithm is equal to the sum of the following two
components −
 A fixed part that is a space required to store certain data and variables, that are independent of
the size of the problem. For example, simple variables and constants used, program size, etc.
 A variable part is a space required by variables, whose size depends on the size of the
problem. For example, dynamic memory allocation, recursion stack space, etc.
Space complexity S(P) of any algorithm P is S(P) = C + SP(I), where C is the fixed part and S(I)
is the variable part of the algorithm, which depends on instance characteristic I. Following is a
simple example that tries to explain the concept −
Algorithm: SUM(A, B)
Step 1 - START
Step 2 - C ← A + B + 10
Step 3 - Stop
Here we have three variables A, B, and C and one constant. Hence S(P) = 1 + 3. Now, space
depends on data types of given variables and constant types and it will be multiplied accordingly.
Time Complexity
Time complexity of an algorithm represents the amount of time required by the algorithm to
run to completion. Time requirements can be defined as a numerical function T(n), where T(n) can
be measured as the number of steps, provided each step consumes constant time.
For example, addition of two n-bit integers takes n steps. Consequently, the total
computational time is T(n) = c ∗ n, where c is the time taken for the addition of two bits. Here, we
observe that T(n) grows linearly as the input size increases.
Asymptotic Analysis:
The efficiency of an algorithm depends on the amount of time, storage and other resources required
to execute the algorithm. The efficiency is measured with the help of asymptotic notations.

6
An algorithm may not have the same performance for different types of inputs. With the increase in
the input size, the performance will change.
The study of change in performance of the algorithm with the change in the order of the input size is
defined as asymptotic analysis.
Asymptotic Notations
Asymptotic notations are the mathematical notations used to describe the running time of an
algorithm when the input tends towards a particular value or a limiting value.
For example: In bubble sort, when the input array is already sorted, the time taken by the algorithm is
linear i.e. the best case.
But, when the input array is in reverse condition, the algorithm takes the maximum time (quadratic)
to sort the elements i.e. the worst case.
When the input array is neither sorted nor in reverse order, then it takes average time. These
durations are denoted using asymptotic notations.
There are mainly three asymptotic notations:
 Big-O notation
 Omega notation
 Theta notation
Big-O Notation (O-notation)
Big-O notation represents the upper bound of the running time of an algorithm. Thus, it gives the
worst-case complexity of an algorithm.

Big-O gives the upper bound of a function


O(g(n)) = { f(n): there exist positive constants c and n0
such that 0 ≤ f(n) ≤ cg(n) for all n ≥ n0 }
The above expression can be described as a function f(n) belongs to the set O(g(n)) if there exists a
positive constant c such that it lies between 0 and cg(n), for sufficiently large n.
For any value of n, the running time of an algorithm does not cross the time provided by O(g(n)).

7
Since it gives the worst-case running time of an algorithm, it is widely used to analyze an algorithm
as we are always interested in the worst-case scenario.
Time-Space Trade-Off in Algorithms
A tradeoff is a situation where one thing increases and another thing decreases. It is a way to
solve a problem in:
 Either in less time and by using more space, or
 In very little space by spending a long amount of time.
The best Algorithm is that which helps to solve a problem that requires less space in memory
and also takes less time to generate the output. But in general, it is not always possible to achieve
both of these conditions at the same time. The most common condition is an algorithm using
a lookup table. This means that the answers to some questions for every possible value can be
written down. One way of solving this problem is to write down the entire lookup table, which
will let you find answers very quickly but will use a lot of space. Another way is to calculate the
answers without writing down anything, which uses very little space, but might take a long time.
Therefore, the more time-efficient algorithms you have, that would be less space-efficient.
Types of Space-Time Trade-off
 Compressed or Uncompressed data
 Re Rendering or Stored images
 Smaller code or loop unrolling
 Lookup tables or Recalculation
Compressed or Uncompressed data: A space-time trade-off can be applied to the problem
of data storage. If data stored is uncompressed, it takes more space but less time. But if the data is
stored compressed, it takes less space but more time to run the decompression algorithm. There are
many instances where it is possible to directly work with compressed data. In that case of
compressed bitmap indices, where it is faster to work with compression than without compression.
Re-Rendering or Stored images: In this case, storing only the source and rendering it as an image
would take more space but less time i.e., storing an image in the cache is faster than re-rendering
but requires more space in memory.
Smaller code or Loop Unrolling: Smaller code occupies less space in memory but it requires high
computation time that is required for jumping back to the beginning of the loop at the end of each
iteration. Loop unrolling can optimize execution speed at the cost of increased binary size. It
occupies more space in memory but requires less computation time.
Lookup tables or Recalculation: In a lookup table, an implementation can include the entire table
which reduces computing time but increases the amount of memory needed. It can recalculate i.e.,
compute table entries as needed, increasing computing time but reducing memory requirements.
For Example: In mathematical terms, the sequence Fn of the Fibonacci Numbers is defined by the
recurrence relation:
Fn = Fn – 1 + Fn – 2,
where, F0 = 0 and F1 = 1.
A simple solution to find the Nth Fibonacci term using recursion from the above recurrence
relation.
Arrays

8
An array is a collection of elements of the same type placed in contiguous memory locations that can
be individually referenced by using an index to a unique identifier.
Five values of type int can be declared as an array without having to declare five different variables
(each with its own identifier).
For example, a five element integer array foo may be logically represented as;

where each blank panel represents an element of the array. In this case, these are values of type int.
These elements are numbered from 0 to 4, with 0 being the first while 4 being the last; In C++, the
index of the first array element is always zero. As expected, an n array must be declared prior its use.
A typical declaration for an array in C++ is:
type name [elements];
where type is a valid type (such as int, float ...), name is a valid identifier and the elements field
(which is always enclosed in square brackets []), specifies the size of the array.
Thus, the foo array, with five elements of type int, can be declared as:
int foo [5];
NOTE
: The elements field within square brackets [], representing the number of elements in the array, must
be a constant expression, since arrays are blocks of static memory whose size must be known at
compile time.
INITIALIZING ARRAYS
By default, are left uninitialized. This means that none of its elements are set to anyparticular value;
their contents are undetermined at the point the array is declared.
The initializer can even have no values, just the braces:
int baz [5] = { };
This creates an array of five int values, each initialized with a value of zero:

But, the elements in an array can be explicitly initialized to specific values when it is declared, by
enclosing those initial values in braces {}. For example:
int foo [5] = { 16, 2, 77, 40, 12071 };
This statement declares an array that can be represented like this:

The number of values between braces {} shall not be greater than the number of elements in the
array. For example, in the example above, foo was declared having 5 elements (as specified by the
9
number enclosed in square brackets, []), and the braces {} contained exactly 5 values, one for each
element. If declared with less, the remaining elements are set to their default values (which for
fundamental types, means they are filled with zeroes). For example:
int bar [5] = { 10, 20, 30 };
Will create an array like this:

When an initialization of values is provided for an array, C++ allows the possibility of leaving the
square brackets empty[]. In this case, the compiler will assume automatically a size for the array that
matches the number of values included between the braces {}:
int foo [] = { 16, 2, 77, 40, 12071 };
After this declaration, array foo would be five int long, since we have provided five initialization
values.
Finally, the evolution of C++ has led to the adoption of universal initialization also for arrays.
Therefore, there is no longer need for the equal sign between the declaration and the initializer. Both
these statements are equivalent:
int foo[] = { 10, 20, 30 };
int foo[] { 10, 20, 30 };
Here, the number of the array n is calculated by the compiler by using the formula n= #of
initializers/sizeof(int).
Static arrays, and those declared directly in a namespace (outside any function), are always
initialized. If no explicit initializer is specified, all the elements are default-initialized (with zeroes,
for fundamental types).
ARRAY ACCESSING
The values of any of the elements in an array can be accessed just like the value of a regular variable
of the same type. The syntax is:
name[index]
Following the previous examples in which foo had 5 elements and each of those elements was of
type int, the name which can be used to refer to each element is the following:

For example, the following statement stores the value 75 in the third element of foo:
foo [2] = 75;
and, for example, the following copies the value of the fourth element of foo to a variable called x:
x = foo[3];
Therefore, the expression foo[2] or foo[4] is always evaluated to an int. Notice that the third element
of foo is specified foo[2], the second one is foo[1], since the first one is foo[0]. It’s last element is

10
therefore foo[4]. If we write foo[5], we would be accessing the sixth element of foo, and therefore
actually exceeding the size of the array.
In C++, it is syntactically correct to exceed the valid range of indices for an array. This can create
problems, since accessing out-of-range elements do not cause errors on compilation, but can cause
errors on runtime. The reason for this being allowed because index checking slows down program
execution. At this point, it is important to be able to clearly distinguish between the two uses that
brackets [] have related to arrays. They perform two different tasks: one is to specify the size of
arrays when they are declared; and the second one is to specify indices for concrete array elements
when they are accessed. Do not confuse these two possible uses of brackets [] with arrays.
int foo[5]; // declaration of a new array
foo[2] = 75; // access to an element of the array.
The main difference is that the declaration is preceded by the type of the elements, while the access
is not.
Some other valid operations with arrays:
foo[0] = a;
foo[i] = 75;
b = foo [i+2];
foo[foo[i]] = foo[i] + 5;
FOR EXAMPLE:
// arrays example
#include <iostream>
using namespace std;
int foo [] = {16, 2, 77, 40, 12071};
int i, result=0;
int main ()
{
for ( i=0 ; i<5 ; i++ )
{
result += foo[i];
}
cout << result;
return 0;
}
MULTIDIMENSIONAL ARRAYS
Multidimensional arrays can be described as "arrays of arrays". For example, a bi-dimensional array
can be imagined as a two-dimensional table made of elements, all of them hold same type of
elements.

11
Table represents a bi-dimensional array of 3 per 5 elements of type int. The C++ syntax for this is
int Table [3][5];
and, for example, the way to reference the second element vertically and fourth horizontally in an
expression would be:
Table[1][3]

(remember that array indices always begin with zero).


Multidimensional arrays are not limited to two indices (i.e., two dimensions). They can contain as
many indices as needed. Although be careful: the amount of memory needed for an array increases
exponentially with each dimension. For example:
char century [100][365][24][60][60];
Declares an array with an element of type char for each second in a century. This amounts to more
than 3 billion char! So this declaration would consume more than 3 gigabytes of memory! And such
a declaration is highly improbable and it underscores inefficient use of memory space.
At the end, multidimensional arrays are just an abstraction for programmers, since the same results
can be achieved with a simple array, by multiplying its indices:
int Table [3][5]; // is equivalent to
int Table [15]; // (3 * 5 = 15)
With the only difference that with multidimensional arrays, the compiler automatically remembers
the depth of each imaginary dimension. The following two pieces of code produce the exact same
result, but one uses a bi-dimensional array while the other uses a simple array:
MULTIDIMENSIONAL ARRAY
const int WIDTH = 5;
const int HEIGHT = 3;
int Table [HEIGHT][WIDTH];
int n,m;
int main ()
{
for (n=0; n<HEIGHT; n++)
for (m=0; m<WIDTH; m++)

12
{
Table[n][m]=(n+1)*(m+1);
}
}
PSEUDO-MULTIDIMENSIONAL ARRAY
const int WIDTH = 5;
const int HEIGHT = 3;
int Table [HEIGHT * WIDTH];
int n,m;
int main ()
{
for (n=0; n<HEIGHT; n++)
for (m=0; m<WIDTH; m++)
{
Table[n*WIDTH+m]=(n+1)*(m+1);
}
}
None of the two code snippets above produce any output on the screen, but both assign values to the
memory block called jimmy in the following way:

Note that the code uses named constants for the width and height, instead of using directly their
numerical values. This gives the code a better readability, and allows changes in the code to be made
easily in one place.
USING LOOP TO INPUT AN TWO-DIMENSIONAL ARRAY FROM USER
int mat[3][5], row, col ;
for (row = 0; row < 3; row++)
for (col = 0; col < 5; col++)
cin >> mat[row][col];

ARRAYS AS PARAMETERS
Two-dimensional arrays can be passed as parameters to a function, and they are passed by reference.
This means that the function can directly access and modified the contents of the passed array. When
declaring a two-dimensional array as a formal parameter, we can omit the size of the first dimension,
but not the second; that is, we must specify the number of columns. For example:

13
void print(int A[][3],int N, int M)
In order to pass to this function an array declared as:
int arr[4][3];
we need to write a call like this:
print(arr);
HERE IS A COMPLETE EXAMPLE:
#include <iostream>
using namespace std;
void print(int A[][3],int N, int M)
{
for (R = 0; R < N; R++)
for (C = 0; C < M; C++)
cout << A[R][C];
}
int main ()
{
int arr[4][3] ={{12, 29, 11},
{25, 25, 13},
{24, 64, 67},
{11, 18, 14}};
print(arr,4,3);
return 0;
}
Engineers use two dimensional arrays in order to represent matrices. The code for a function that
finds the sum of the two matrices A and B are shown below.
FUNCTION TO FIND THE SUM OF TWO MATRICES
void Addition(int A[][20], int B[][20],int N, int M)
{
for (int R=0;R<N;R++)
for(int C=0;C<M;C++)
C[R][C]=A[R][C]+B[R][C];
}
FUNCTION TO FIND OUT TRANSPOSE OF A MATRIX A

void Transpose(int A[][20], int B[][20],int N, int M)


{
14
for(int R=0;R<N;R++)
for(int C=0;C<M;C++)
B[R][C]=A[C][R];
}
ARRAYS AS PARAMETERS
At some point, we may need to pass an array to a function as a parameter. In C++, it is not possible
to pass the entire block of memory represented by an array to a function directly as an argument. But
what can be passed instead is its address. In practice, this has almost the same effect, and it is a much
faster and more efficient operation.
To accept an array as parameter for a function, the parameters can be declared as the array type, but
with empty brackets, omitting the actual size of the array. For example:
void procedure (int arg[])
This function accepts a parameter of type "array of int" called arg. In order to pass to this function an
array declared as:
int myarray [40];
it would be enough to write a call like this:
procedure (myarray);
Calculation of address of element of 1-D, 2-D, and 3-D using row-major and column-major
order

Calculating the address of any element In the 1-D array:


A 1-dimensional array (or single dimension array) is a type of linear array. Accessing its
elements involves a single subscript that can either represent a row or column index.
Example:

2-D array
To find the address of an element in an array the following formula is used-
Address of A[I] = B + W * (I – LB)
15
I = Subset of element whose address to be found,
B = Base address,
W = Storage size of one element store in any array(in byte),
LB = Lower Limit/Lower Bound of subscript(If not specified assume zero).
Example: Given the base address of an array A[1300 ………… 1900] as 1020 and the size of each
element is 2 bytes in the memory, find the address of A[1700].
Solution:
Given:
Base address B = 1020
Lower Limit/Lower Bound of subscript LB = 1300
Storage size of one element store in any array W = 2 Byte
Subset of element whose address to be found I = 1700
Formula used:
Address of A[I] = B + W * (I – LB)
Solution:
Address of A[1700] = 1020 + 2 * (1700 – 1300)
= 1020 + 2 * (400)
= 1020 + 800
Address of A[1700] = 1820
Calculate the address of any element in the 2-D array:
The 2-dimensional array can be defined as an array of arrays. The 2-Dimensional arrays are
organized as matrices which can be represented as the collection of rows and columns as
array[M][N] where M is the number of rows and N is the number of columns.
Example:

2-D array
To find the address of any element in a 2-Dimensional array there are the following two ways-
1. Row Major Order
2. Column Major Order
1. Row Major Order:
Row major ordering assigns successive elements, moving across the rows and then down the next
row, to successive memory locations. In simple language, the elements of an array are stored in a
Row-Wise fashion.
To find the address of the element using row-major order uses the following formula:
Address of A[I][J] = B + W * ((I – LR) * N + (J – LC))

16
I = Row Subset of an element whose address to be found,
J = Column Subset of an element whose address to be found,
B = Base address,
W = Storage size of one element store in an array(in byte),
LR = Lower Limit of row/start row index of the matrix(If not given assume it as zero),
LC = Lower Limit of column/start column index of the matrix(If not given assume it as zero),
N = Number of column given in the matrix.
Example: Given an array, arr[1………10][1………15] with base value 100 and the size of each
element is 1 Byte in memory. Find the address of arr[8][6] with the help of row-major order.
Solution:
Given:
Base address B = 100
Storage size of one element store in any array W = 1 Bytes
Row Subset of an element whose address to be found I = 8
Column Subset of an element whose address to be found J = 6
Lower Limit of row/start row index of matrix LR = 1
Lower Limit of column/start column index of matrix = 1
Number of column given in the matrix N = Upper Bound – Lower Bound + 1
= 15 – 1 + 1
= 15
Formula:
Address of A[I][J] = B + W * ((I – LR) * N + (J – LC))
Solution:
Address of A[8][6] = 100 + 1 * ((8 – 1) * 15 + (6 – 1))
= 100 + 1 * ((7) * 15 + (5))
= 100 + 1 * (110)
Address of A[I][J] = 210
2. Column Major Order:
If elements of an array are stored in a column-major fashion means moving across the column and
then to the next column then it’s in column-major order. To find the address of the element using
column-major order use the following formula:
Address of A[I][J] = B + W * ((J – LC) * M + (I – LR))
I = Row Subset of an element whose address to be found,
J = Column Subset of an element whose address to be found,
B = Base address,
W = Storage size of one element store in any array(in byte),
LR = Lower Limit of row/start row index of matrix(If not given assume it as zero),
LC = Lower Limit of column/start column index of matrix(If not given assume it as zero),
M = Number of rows given in the matrix.
Example: Given an array arr[1………10][1………15] with a base value of 100 and the size of each
element is 1 Byte in memory find the address of arr[8][6] with the help of column-major order.
Solution:
Given:
Base address B = 100
Storage size of one element store in any array W = 1 Bytes
Row Subset of an element whose address to be found I = 8
Column Subset of an element whose address to be found J = 6
17
Lower Limit of row/start row index of matrix LR = 1
Lower Limit of column/start column index of matrix = 1
Number of column given in the matrix M = Upper Bound – Lower Bound + 1
= 10 – 1 + 1
= 10
Formula: used
Address of A[I][J] = B + W * ((J – LC) * M + (I – LR))
Address of A[8][6] = 100 + 1 * ((6 – 1) * 10 + (8 – 1))
= 100 + 1 * ((5) * 10 + (7))
= 100 + 1 * (57)
Address of A[I][J] = 157
From the above examples, it can be observed that for the same position two different address
locations are obtained that’s because in row-major order movement is done across the rows and then
down to the next row, and in column-major order, first move down to the first column and then next
column. So both the answers are right.
So it’s all based on the position of the element whose address is to be found for some cases the same
answers is also obtained with row-major order and column-major order and for some cases, different
answers are obtained.
Calculate the address of any element in the 3-D Array:
A 3-Dimensional array is a collection of 2-Dimensional arrays. It is specified by using three
subscripts:
1. Block size
2. Row size
3. Column size
More dimensions in an array mean more data can be stored in that array.
Example:

3-D array
To find the address of any element in 3-Dimensional arrays there are the following two ways-
18
 Row Major Order
 Column Major Order
1. Row Major Order:
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:
Given:
Row Subset of an element whose address to be found I = 5
Column Subset of an element whose address to be found J = -1
Block 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 row/start row index of matrix x = 1
Lower Limit of column/start column index of matrix y = -4
Lower Limit of blocks in matrix z = 5
M = Upper Bound – Lower Bound + 1 = 1 – (-4) + 1 = 6
N = Upper Bound – Lower Bound + 1 = 10 – 5 + 1 = 6
Formula used:
Address of[I][J][K] =B + W (M * N(i-x) + N *(j-y) + (k-z))
Solution:
Address of[][][] = 400 + 2 * {[6 * 6 * (5 – 1)] + 6 * [(-1 + 4)]} + [8 – 5]
= 400 + 2 * ((4 * 6 + 3) * 6 + 3)
= 400 + 2 * (165)
= 730
2. Column Major Order:
To find the address of the element using column-major order, use the following formula:1
Address of A[i][j][k = B + W(M * N(i – x) + M *(k – z) + (j – y))
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
19
y = Lower Bound of Column
z = Lower Bound of Width
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 column-major order?
Solution:
Given:
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 row/start row index of matrix x = 1
Lower Limit of column/start column index of matrix y = -5
Lower Limit of blocks in matrix z = -10
M = Upper Bound – Lower Bound + 1 = 5 + 5 + 1 = 11
N = Upper Bound – Lower Bound + 1 = 5 + 10 + 1 = 16
Formula used:
Address of[i][j][k] = B + W(M * N(i – x) + M * (k – z) + (j – y))
Solution:
Address of[3][3][3] = 400 + 4 * {[(3 – 1)] * 16 + [3 + 10] ]} * 11 + [3 + 5]
= 400 + 4 * ((32 + 13) * 11 + 8)
= 400 + 4 * (503)
= 400 + 2012
= 2412
Sparse Matrix and its representations | Set 1 (Using Arrays and Linked Lists)
A matrix is a two-dimensional data object made of m rows and n columns, therefore having total m x
n values. If most of the elements of the matrix have 0 value, then it is called a sparse matrix.
Why to use Sparse Matrix instead of simple matrix ?
 Storage: There are lesser non-zero elements than zeros and thus lesser memory can be used to
store only those elements.
 Computing time: Computing time can be saved by logically designing a data structure
traversing only non-zero elements..
Example:
00304
00570
00000
02600
Representing a sparse matrix by a 2D array leads to wastage of lots of memory as zeroes in the
matrix are of no use in most of the cases. So, instead of storing zeroes with non-zero elements, we
only store non-zero elements. This means storing non-zero elements with triples- (Row, Column,
value).
Sparse Matrix Representations can be done in many ways following are two common
representations:
1. Array representation
20
2. Linked list representation
Method 1: Using Arrays:
2D array is used to represent a sparse matrix in which there are three rows named as
 Row: Index of row, where non-zero element is located
 Column: Index of column, where non-zero element is located
 Value: Value of the non zero element located at index – (row,column)

character storing in C.
C uses char type to store characters and letters. However, the char type is integer type because
underneath C stores integer numbers instead of characters.
To represent characters, the computer has to map each integer with a corresponding character using a
numerical code. The most common numerical code is ASCII, which stands for American Standard
Code for Information Interchange.
The following table illustrates the ASCII code:

For example, the integer number 65represents a character A in upper case.


In C, the char type has a 1-byte unit of memory so it is more than enough to hold the ASCII codes.
Besides ASCII code, there are various numerical codes available such as extended ASCII codes.
Unfortunately, many character sets have more than 127 even 255 values. Therefore, to fulfill those
needs, Unicode was created to represent various available character sets. Unicode currently has over
40,000 characters.
Using C char type
In order to declare a variable with character type, you use the char keyword followed by the variable
name. The following example declares three charvariables.
char ch;
char key, flag;.

21
In this example, we initialize a character variable with a character literal. A character literal contains
one character that is surrounded by a single quotation ( ').
The following example declares key character variable and initializes it with a character literal ‘A‘:
char key = 'A';
Because the char type is the integer type, you can initialize or assign a charvariable an integer.
However, it is not recommended since the code may not be portable.
ch = 66;
Displaying C character type
To print characters in C, you use the printf() function with %c as a placeholder. If you use %d, you
will get an integer instead of a character. The following example demonstrates how to print
characters in C.
#include <stdio.h>
int main()
{
char ch = 'A';
printf("ch = %c\n",ch);
printf("ch = %d, hence an integer\n",ch);
return 0;
}
In this tutorial, you have learned about C character type and how to declare, use and print character
variables in C.
Character Strings
String variables are typically stored as arrays of chars, terminated by a null byte.
Initializing String Variables
String variables can be initialized either with individual characters or more commonly and easily
with string literals:
char s1[ ] = { 'h', 'e', 'l', 'l', 'o', '\0' };
char s2[ ] = "hello"; // Array of size six
char s3[ 20 ] = "hello"; // Fifteen null bytes
char s4[ 5 ] = "hello"; // Five chars, sacrifices the null byte
char s5[ 3 ] = "hello"; // Illegal
Character Arrays versus Character Pointers
Character arrays and character pointers are often interchangeable, but there can be some very
important differences. Consider the following two variables:
char s6[ ] = "hello", *s7 = "hello";
 s6 is a fixed constant address, determined by the compiler; s7 is a pointer variable, that can be
changed to point elsewhere.
 s6 allocates space for exactly 6 bytes; s7 allocates space for 10 ( typically ) - 6 for the
characters plus another 4 for the pointer veriable.
22
 The contents of s6, can be changed, e.g. s6[ 0 ] = 'J'; The contents of s7 should not be
changed.
Reading and Writing Strings
Writing Strings Using printf
 The standard format specifier for printing strings with printf is %s
o The width parameter can be used to print a short string in a long space
o The .precision parameter limits the length of longer strings.
o Writes the string out to standard output ( the screen ) and automatically appends a
newline character at the end.
This is a lower-level routine that printf, without formatting, and possibly faster.
Reading Strings Using scanf
 The standard format specifier for reading strings with scanf is %s
o scanf reads in a string of characters, only up to the first non-whitespace character. I.e.
it stops reading when it encounters a space, tab, or newline character.
o scanf appends a null byte to the end of the character string stored.
o scanf does skip over any leading whitespace characters in order to find the first non-
whitespace character.
o The width field can be used to limit the maximum number of characters read.
o The argument passed to scanf needs to be of type pointer-to-character, i.e. char *, and
is normally the name of a char array. ( In this case the size of the array -1 should be
given as the width field, to make sure scanf can append the null byte without
overflowing the array.
Reading Strings Character by Character
 Another option for reading in strings is to read them in character by character.
 This is useful when you don't know how long the string might be, or if you want to consider
other stopping conditions besides spaces and newlines. ( E.g. stop on periods, or when two
successive slashes, //, are encountered. )
 The scanf format specifier for reading individual characters is %c
o If a width greater than 1 is given, then multiple characters are read, and stored in
successive positions in a char array.
 Characters scanned this way are often stored in an array, although the could also be read into
an ordinary char variable for further processing first.
Accessing the Characters in a String
Characters in a string can be acessed using either the [ ] notation or a char pointer.
Using the C String Library
 The C language includes a standard library full of routines for working with null-byte
terminated arrays of chars.
 #include < string.h > to use any of these functions.
 Some of the more commonly used and useful routines include:

23
size_t strlen ( const char * str );
 Returns the length of the string, not counting the null byte
char * strcpy ( char * destination, const char * source );
 Copies characters from source to destination, until a null byte is eventually encountered
char * strncpy ( char * destination, const char * source, size_t num );
 Copies from source to destination, up to a maximum of num characters.
 Pads destination with extra null bytes if the length of source is smaller than num.
 May sacrifice the null byte if the source is longer than num.
char * strcat ( char * destination, const char * source );
 Concatenates ( appends ) source onto the end of destination.
 The terminating null byte of destination is over-written by the first char of source, and a new
null-byte is appended at the end of the concatenated string.
 char * strncat ( char * destination, char * source, size_t num ); is a version that sets a limit on
the number of characters concatenated.
int strcmp ( const char * str1, const char * str2 );
 Compares strings str1 and str2, up until the first encountered null byte
o Returns zero if the two strings are equal
o Returns a positive value ( 1? ) if the first encountered difference has a larger value in
str1 than str2
o Returns a negative value ( -1? ) if the first encountered differenc has a smaller value
in str1 than str2
 int strncmp ( const char * str1, const char * str2, size_t num ); checks only up to num
characters.
int atoi (const char * str);
double atof (const char* str);
long int atol ( const char * str );
long long int atoll ( const char * str );
 parses a string of numeric characters into a number of type int, double, long int, or long long
int, respectively.
 Most often used when parsing command line arguments.
 Can also be used for rigorous checking of user input - Read in an entire line into a char array
using gets, fgets, or char-by-char, then rigorously test all the characters in the string, ( e.g. are
they all numeric ), and then use one of these routines to convert the char array into a number
once all the checks have been made.
sscanf( char *, format [ , address . . . ] );
 Reads data from a character string, just as if scanf read it from the keyboard.
 One approach to rigorous input checking is to use getline( ) to read in an entire line of input
from a user, then examine it character by character for any problems, e.g. non-numeric
characters when trying to read in a number. Then when the string has been verified, use scanf
to read in the data from the character string.
See also strchr, strrchr, strstr, and strtok for searching and tokenizing strings.
24
String Idioms
Searching for the End of a String
Copying a String
void strcpy( const char * s, char * d ) {
do {
*d++ = *s++;
} while( *s );
return;
}
Arrays of Strings
 There is a subtle difference between:
o a one-dimensional arrays of pointers to chars, ( char * [ ] ) and
o a two-dimensional array of chars, ( char [ ] [ ] )
 Both can be accessed using double subscripts
 However the storage is different.

25

You might also like