0% found this document useful (0 votes)
64 views

C and Data Structure

The document is about C++ and data structures. It provides an overview of object oriented programming concepts like classes, objects, encapsulation, inheritance and polymorphism. It then discusses C++ fundamentals like operators, expressions, control structures and input/output. The rest of the document outlines the syllabus which covers topics like functions, classes, inheritance, polymorphism, files and various data structures like stacks, queues, linked lists, trees and graphs.

Uploaded by

studentxeroxcud
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
64 views

C and Data Structure

The document is about C++ and data structures. It provides an overview of object oriented programming concepts like classes, objects, encapsulation, inheritance and polymorphism. It then discusses C++ fundamentals like operators, expressions, control structures and input/output. The rest of the document outlines the syllabus which covers topics like functions, classes, inheritance, polymorphism, files and various data structures like stacks, queues, linked lists, trees and graphs.

Uploaded by

studentxeroxcud
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 151

lOMoARcPSD|37280708

C++ and data structure

B.sc(Computer Science) (Thiruvalluvar University)

Scan to open on Studocu

Studocu is not sponsored or endorsed by any college or university


Downloaded by KOLANJI Bala ([email protected])
lOMoARcPSD|37280708

C++ AND DATA STRUCTURE


Prepared by

R.CHERAN [M.Sc. Computer science]

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Syllabus
UNIT-I: Object Oriented Concepts and C++
C++ Fundamentals - Operators, Expressions and Control Structures: If,If..Else, Switch
- Repetitive Statements- for,while,do..while - Input and Output in C++ - manipulators-
manipulators with parameters. - Pointers and arrays
UNIT-II: Functions and Classes
Functions in C++ - Main Function - Function Prototyping - Parameters Passing in
Functions - Values Return by Functions - inline Functions - Function Overloading.
Classes and Objects; Constructors and Destructors; and Operator Overloading - Type
of Constructors
UNIT – III: Inheritance, Polymorphism & Files
Inheritance : Single Inheritance - Multilevel inheritance - Multiple inheritance -
Hierarchical Inheritance - Hybrid Inheritance - Polymorphism - Working with Files :
Classes for File Stream Operations - Opening and Closing a File - End-of-File
Detection - Updating a File - Error Handling during File Operations .
UNIT-IV: Fundamental Data Structures
Definition of a Data structure - primitive and composite Data Types, Stacks (Array) -
Operations –Linked Stack-Operations- Applications of Stack (Infix to Postfix
Conversion).
Queue (Array)- operations-Linked Queue- Operations- - Singly Linked List -
Operations, Application of List ( Polynomial Addition)-. Doubly Linked List -
Operations.
UNIT-V : Trees and Graphs
Trees: Binary Trees –Binary Search Tree- Operations - Recursive Tree Traversals-
Recursion. Graph - Definition, Types of Graphs, Graph Traversal –Dijkstras shortest
path- DFS and BFS.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Unit-I

Introduction

Object oriented Programming

Object oriented Programming is defined as an approach that provides a way of modularizing


programs by creating partitioned memory area for both data and functions that can be used as
templates for creating copies of such modules on demand. Writing object-oriented programs involves
creating classes, creating objects from those classes, and creating applications, which are stand-alone
executable programs that use those objects. After being created, classes can be reused over and over
again to develop new programs. Thinking in an object-oriented manner involves envisioning program
components as objects that belong to classes and are similar to concrete objects in the real world;
then, you can manipulate the objects and have them interrelate with each other to achieve a desired
result.

Basic Concepts of Object oriented Programming

1. Class
A class is a user defined data type. A class is a logical abstraction. It is a template that defines the form
of an object. A class specifies both code and data. It is not until an object of that class has been created
that a physical representation of that class exists in memory. When you define a class, you declare the
data that it contains and the code that operates on that data. Data is contained in instance variables
defined by the class known as data members, and code is contained in functions known as member
functions. The code and data that constitute a class are called members of the class.

2. Object
An object is an identifiable entity with specific characteristics and behavior. An object is said to be
an instance of a class. Defining an object is similar to defining a variable of any data type. Space is
set aside for it in memory.

3. Encapsulation
Encapsulation is a programming mechanism that binds together code and the data it manipulates, and that
keeps both safe from outside interference and misuse. C++‘s basic unit of encapsulation is the class.
Within a class, code or data or both may be private to that object or public. Private code or data is known
to and accessible by only another part of the object. That is, private code or data cannot be accessed by a
piece of the program that exists outside the object. When code or data is public, other parts of your
program can access it even though it is defined within an object. Typically, the public parts of an object
are used to provide a controlled interface to the private elements of the object. This insulation of the data
from direct access by the program is called data hiding.

4. Data abstraction
In object oriented programming, each object will have external interfaces through which it can be
made use of. There is no need to look into its inner details. The object itself may be made of many
smaller objects again with proper interfaces. The user needs to know the external interfaces only to
make use of an object. The internal details of the objects are hidden which makes them abstract. The
technique of hiding internal details in an object is called data abstraction.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

5. Inheritance
Inheritance is the mechanism by which one class can inherit the properties of another. It allows a
hierarchy of classes to be build, moving from the most general to the most specific. When one class
is inherited by another, the class that is inherited is called the base class. The inheriting class is called
the derived class. In general, the process of inheritance begins with the definition of a base class. The
base class defines all qualities that will be common to any derived class. . In OOPs, the concept of
inheritance provides the idea of reusability. In essence, the base class represent the most general
description of a set of traits. The derived class inherits those general traits and adds properties that are
specific to that class.

6. Polymorphism
Polymorphism (from the Greek, meaning ―many forms‖) is a feature that allows one interface to be
used for a general class of actions. The specific action is determined by the exact nature of the
situation. The concept of polymorphism is often expressed by the phrase ―one interface, multiple
methods.‖ This means that it is possible to design a generic interface to a group of related activities.
This helps reduce complexity by allowing the same interface to be used to specify a general class of
action. It is the compiler‘s job to select the specific action as it applies to each situation.

Polymorphism

Compile time Run time


Polymorphism Polymorphism

Function Operator Virtual


overloading overloading functions

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

C++
C++ is an object oriented programming language. It was developed by Bjarne Stroustrup in 1979 at
Bell Laboratories in Murray Hill, New Jersey. He initially called the new language "C with Classes."
However, in 1983 the name was changed to C++.

C++ is a superset of C. Stroustrup built C++ on the foundation of C, including all of C‘s features,
attributes, and benefits. Most of the features that Stroustrup added to C were designed to support
object-oriented programming .These features comprise of classes, inheritance, function overloading
and operator overloading. C++ has many other new features as well, including an improved
approach to input/output (I/O) and a new way to write comments.

C++ is used for developing applications such as editors, databases, personal file systems,
networking utilities, and communication programs. Because C++ shares C‘s efficiency, much high-
performance systems software is constructed using C++.

A Simple C++ Program


#include<iostream.h>
#include<conio.h>
int main()
{
cout<< ―Simple C++ program without using class‖;
return 0;
}

Lines beginning with a hash sign (#) are directives read and interpreted by what is known as the
preprocessor. They are special lines interpreted before the compilation of the program itself
begins. In this case, the directive #include <iostream.h>, instructs the preprocessor to include a
section of standard C++ code, known as header iostream that allows to perform standard input
and output operations, such as writing the output of this program to the screen.

The function named main is a special function in all C++ programs; it is the function called when the
program is run. The execution of all C++ programs begins with the main function, regardless of
where the function is actually located within the code.

The open brace ({) indicates the beginning of main's function definition, and the closing brace (})
indicates its end.
The statement :
cout<< ―Simple C++ program without using class‖;

causes the string in quotation marks to be displayed on the screen. The identifier cout (pronounced as
c out) denotes an object. It points to the standard output device namely the console monitor. The
operator << is called insertion operator. It directs the string on its right to the object on its left.
The program ends with this statement:
return 0;

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

This causes zero to be returned to the calling process (which is usually the operating system).
Returning zero indicates that the program terminated normally. Abnormal program termination should
be signaled by returning a nonzero value.

Identifiers
An identifier is a name assigned to a function, variable, or any other user-defined item. Identifiers
can be from one to several characters long.

Rules for naming identifiers:



 Variable names can start with any letter of the alphabet or an underscore. Next comes a letter, a digit,
or an underscore.
 
 Uppercase and lowercase are distinct.
 
C++ keywords cannot be used as identifier.

Data types
Data type defines size and type of values that a variable can store along with the set of operations
that can be performed on that variable. C++ provides built-in data types that correspond to integers,
characters, floating-point values, and Boolean values. There are the seven basic data types in C++
as shown below:

Type Meaning
char(character) holds 8-bit ASCII characters
wchar_t(Wide character) holds characters that are part of large character sets
int(Integer) represent integer numbers having no fractional part

float(floating point) stores real numbers in the range of about 3.4x10–38to


3.4x10 38,with a precision of seven digits.

double(Double floating point) Stores real numbers in the range from 1.7x10
–308 to1.7x10308 with a precision of 15 digits.
bool(Boolean) can have only two possible values: true and false.
Void Valueless

C++ allows certain of the basic types to have modifiers preceding them. A modifier alters the
meaning of the base type so that it more precisely fits the needs of various situations. The data
type modifiers are: signed, unsigned, long and short
This figure shows all combinations of the basic data types and modifiers along with their size
and range for a 16-bit word machine

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Variable
A variable is a named area in memory used to store values during program execution. Variables
are run time entities. A variable has a symbolic name and can be given a variety of values. When
a variable is given a value, that value is actually placed in the memory space assigned to the
variable. All variables must be declared before they can be used. The general form of a
declaration is:
type variable_list;

Here, type must be a valid data type plus any modifiers, and variable_list may consist of one or
more identifier names separated by commas. Here are some declarations:
int i,j,l;
short int si;
unsigned int ui;
double balance, profit, loss;

Constants
Constants refer to fixed values that the program cannot alter. Constants can be of any of the basic
data types. The way each constant is represented depends upon its type. Constants are also called
literals. We can use keyword const prefix to declare constants with a specific type as follows:
const type variableName = value;
e.g,
const int LENGTH = 10;

Operator
An operator is a symbol that tells the compiler to perform specific mathematical or logical
manipulations. C++ is rich in built-in operators. Generally, there are six type of operators:
Arithmetical operators, Relational operators, Logical operators, Assignment operators, Conditional
operators, Comma operator.

Arithmetical operators
Arithmetical operators +, -, *, /, and % are used to performs an arithmetic (numeric) operation.

Operator Meaning
+ Addition
- Subtraction
* Multiplication
/ Division
% Modulus
You can use the operators +, -, *, and / with both integral and floating-point data types. Modulus or
remainder % operator is used only with the integral data type.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Relational operators
The relational operators are used to test the relation between two values. All relational operators are
binary operators and therefore require two operands. A relational expression returns zero when the
relation is false and a non-zero when it is true. The following table shows the relational operators.

Relational Operators Meaning


< Less than
<= Less than or equal to
== Equal to
> Greater than
>= Greater than or equal to
!= Not equal to

Logical operators
The logical operators are used to combine one or more relational expression. The logical operators are

Operators Meaning
|| OR
&& AND
! NOT

Assignment operator
The assignment operator '=' is used for assigning a variable to a value. This operator takes the
expression on its right-hand-side and places it into the variable on its left-hand-side. For example:
m = 5;
The operator takes the expression on the right, 5, and stores it in the variable on the left, m.
x = y = z = 32;
This code stores the value 32 in each of the three variables x, y, and z. In addition to standard
assignment operator shown above, C++ also support compound assignment operators.

Compound Assignment Operators


Operator Example Equivalent to
+= A+=2 A=A+2
-= A-=2 A=A–2
%= A%=2 A=A%2
/= A/ = 2 A=A/2
*= A*=2 A=A*2

Increment and Decrement Operators


C++ provides two special operators viz '++' and '--' for incrementing and decrementing the value of a
variable by 1. The increment/decrement operator can be used with any type of variable but it cannot
be used with any constant. Increment and decrement operators each have two forms, pre and post.
The syntax of the increment operator is:
Pre-increment: ++variable
Post-increment: variable++
The syntax of the decrement operator is:

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Pre-decrement: ––variable
Post-decrement: variable––
In Prefix form first variable is first incremented/decremented, then evaluated
In Postfix form first variable is first evaluated, then incremented / decremented.

Conditional operator
The conditional operator ?: is called ternary operator as it requires three operands. The format of the
conditional operator is :
Conditional_ expression ? expression1 : expression2;
If the value of conditional expression is true then the expression1 is evaluated, otherwise expression2
is evaluated.
int a = 5, b = 6;
big = (a > b) ? a : b;
The condition evaluates to false, therefore big gets the value from b and it becomes 6.

The comma operator


The comma operator gives left to right evaluation of expressions. When the set of expressions has
to be evaluated for a value, only the rightmost expression is considered.
int a = 1, b = 2, c = 3, i; // comma acts as separator, not as an operator
i = (a, b); // stores b into i would first assign the value of a to i, and then assign value of b to variable i.
So, at the end, variable i would contain the value 2.

The sizeof operator


The sizeof operator can be used to find how many bytes are required for an object to store in
memory. For example
sizeof (char) returns 1
sizeof (float) returns 4

Typecasting
Typecasting is the concept of converting the value of one type into another type. For example, you
might have a float that you need to use in a function that requires an integer.

Implicit conversion
Almost every compiler makes use of what is called automatic typecasting. It automatically converts
one type into another type. If the compiler converts a type it will normally give a warning. For
example this warning: conversion from ‗double‘ to ‗int‘, possible loss of data. The problem with this
is, that you get a warning (normally you want to compile without warnings and errors) and you are
not in control. With control we mean, you did not decide to convert to another type, the compiler did.
Also the possible loss of data could be unwanted.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Explicit conversion
The C++ language have ways to give you back control. This can be done with what is called an
explicit conversion.

Four typecast operators


The C++ language has four typecast operators:
 
 static_cast
 
 reinterpret_cast
 
 const_cast
 
dynamic_cast

Type Conversion
The Type Conversion is that which automatically converts the one data type into another but
remember we can store a large data type into the other. For example we can't store a float
into int because a float is greater than int.
When a user can convert the one data type into then it is called as the type
casting. The type Conversion is performed by the compiler but a casting is done by the
user for example converting a float into int. When we use the Type Conversion then it is
called the promotion. In the type casting when we convert a large data type into another
then it is called as the demotion. When we use the type casting then we can loss some data.

Control Structures
Control structures allows to control the flow of program‘s execution based on certain conditions C++
supports following basic control structures:
1) Selection Control structure
2) Loop Control structure

1) Selection Control structure:


Selection Control structures allows to control the flow of program‘s execution depending upon the state
of a particular condition being true or false .C++ supports two types of selection statements :if and
switch. Condition operator (?:) can also be used as an alternative to the if statement.

A.1) If Statement:
The syntax of an if statement in C++ is:
if(condition)
{
// statement(s) will execute if the condition is true
}

If the condition evaluates to true, then the block of code inside the if statement will be executed. If it
evaluates to false, then the first set of code after the end of the if statement (after the closing curly
brace) will be executed.
Flowchart showing working of if statement

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

// A Program to find whether a given number is even or odd using if … else statement
#include<iostream.h>

#include<conio.h>

int main()

{ int n;

cout<<‖enter number‖;

cin>>n;

if(n%2==0)

cout<<‖Even number‖;

else

cout<<‖Odd number‖;

return 0;

A.2) The if...else Statement


The syntax is shown as:
if(condition){
// statement(s) will execute if the condition is true
}
else{
// statement(s) will execute if condition is false
}

If the condition evaluates to true, then the if block of code will be executed, otherwise else block
of code will be executed.
Flowchart

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

A.3) if...else if...else Statement


An if statement can be followed by an optional else if...else statement, which is very useful to test
various conditions using single if...else if statement.
The Syntax is shown as:
if(condition 1){
// Executes when the condition 1 is true
}
else if(condition 2){
// Executes when the condition 2 is true
}
else if(condition 3){
// Executes when the condition 3 is true
}
else {
// executes when the none of the above condition is true.
}

A.4) Nested if Statement


It is always legal to nest if-else statements, which means you can use one if or
else if statement inside another if or else if statement(s). The syntax for a
nested if statement is as follows:
if( condition 1){

// Executes when the condition 1 is


true if(condition 2){
// Executes when the condition 2 is true
}
}

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

B) Switch
C++ has a built-in multiple-branch selection statement, called switch, which successively tests the
value of an expression against a list of integer or character constants. When a match is found, the
statements associated with that constant are executed. The general form of the switch statement is:
switch (expression) {
case constant1:
statement sequence
break;
case constant2:
statement sequence
break;
case constant3:
statement sequence
break;
.
.
default
statement sequence
}

The expression must evaluate to a character or integer value. Floating-point expressions, for example,
are not allowed. The value of expression is tested, in order, against the values of the constants
specified in the case statements. When a match is found, the statement sequence associated with that
case is executed until the break statement or the end of the switch statement is reached. The default
statement is executed if no matches are found. The default is optional and, if it is not present, no
action takes place if all matches fail.

The break statement is one of C++'s jump statements. You can use it in loops as well as in the switch
statement. When break is encountered in a switch, program execution "jumps" to the line of code
following the switch statement.
Flowchart

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

2) Loop control structures


A loop statement allows us to execute a statement or group of statements multiple times. Loops or
iterative statements tell the program to repeat a fragment of code several times or as long as a certain
condition holds. C++ provides three convenient iterative statements: while, for, and do-while.

while loop
A while loop statement repeatedly executes a target statement as long as a given condition is true. It is
an entry-controlled loop.
The syntax of a while loop in C++ is:
while(condition){
statement(s);
}

Here, statement(s) may be a single statement or a block of statements. The condition may be any
expression, and true is any non-zero value. The loop iterates while the condition is true. After
each execution of the loop, the value of test expression is changed. When the condition becomes
false, program control passes to the line immediately following the loop.
Flowchart

// A program to display numbers from 1 to


100 #include<iostream.h>

#include<conio.h>

int main(){

int i=1;

while(i<=100){

cout<<i ;

i++;

return 0;

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

The do-while Loop


The do-while loop differs from the while loop in that the condition is tested after the body of the loop.
This assures that the program goes through the iteration at least once. It is an exit-controlled loop.
do{
statement(s);
}while( condition );
The conditional expression appears at the end of the loop, so the statement(s) in the loop execute once
before the condition is tested. If the condition is true, the flow of control jumps back up to do, and the
statement(s) in the loop execute again. This process repeats until the given condition becomes false.

// A program to display numbers from 1 to


100 #include<iostream.h>

#include<conio.h>

int main( ){

int i=1;
do

{cout<<i ; i++;

} while(i<=100);

return 0;

for Loop
A for loop is a repetition control structure that allows you to efficiently write a loop that needs
to execute a specific number of times. The syntax of a for loop in C++ is:
for ( init; condition; increment ){
statement(s);
}

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Here is the flow of control in a for loop:


1. The init step is executed first, and only once. This step allows you to declare and initialize any
loop control variables. You are not required to put a statement here, as long as a semicolon appears.
2. Next, the condition is evaluated. If it is true, the body of the loop is executed. If it is false, the body of
the loop does not execute and flow of control jumps to the next statement just after the for loop.

3. After the body of the for loop executes, the flow of control jumps back up to the increment
statement. This statement allows you to update any C++ loop control variables. This statement can
be left blank, as long as a semicolon appears after the condition.

4. The condition is now evaluated again. If it is true, the loop executes and the process repeats itself
(body of loop, then increment step, and then again condition). After the condition becomes false,
the for loop terminates.
Flow Diagram

// A program to display numbers from 1 to


100 #include<iostream.h>

#include<conio.h>
int main() {
int i ;
for (i=1;i<=100;i++)
{
cout<<i ;

return 0;

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

C++ Input/Output
C++ I/O operation is using the stream concept. Stream is the sequence of bytes or
flow of data. It makes the performance fast.

If bytes flow from main memory to device like printer, display screen, or a network
connection, etc, this is called as output operation.

If bytes flow from device like printer, display screen, or a network connection, etc to
main memory, this is called as input operation.

I/O Library Header Files


Let us see the common header files used in C++ programming are:

Header Function and Description


File

<iostream> It is used to define the cout, cin and cerr objects, which correspond to
standard output stream, standard input stream and standard error
stream, respectively.

<iomanip> It is used to declare services useful for performing formatted I/O, such
as setprecision and setw.

<fstream> It is used to declare services for user-controlled file processing.

Standard output stream (cout)


The cout is a predefined object of ostream class. It is connected with the standard
output device, which is usually a display screen. The cout is used in conjunction with
stream insertion operator (<<) to display the output on a console

Let's see the simple example of standard output stream (cout):

#include <iostream>
using namespace std;
int main( ) {
char ary[] = "Welcome to C++ tutorial";
cout << "Value of ary is: " << ary << endl;
}

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Standard input stream (cin)


The cin is a predefined object of istream class. It is connected with the standard input
device, which is usually a keyboard. The cin is used in conjunction with stream
extraction operator (>>) to read the input from a console.

Let's see the simple example of standard input stream (cin):

#include <iostream>
using namespace std;
int main( ) {
int age;
cout << "Enter your age: ";
cin >> age;
cout << "Your age is: " << age << endl;
}

Output:

Enter your age: 22


Your age is: 22

Standard end line (endl)


The endl is a predefined object of ostream class. It is used to insert a new line
characters and flushes the stream.

Let's see the simple example of standard end line (endl):

#include <iostream>
using namespace std;
int main( ) {
cout << "C++ Tutorial";
cout << " Javatpoint"<<endl;
cout << "End of line"<<endl;
}

Output:

C++ Tutorial Javatpoint


End of line

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Manipulators
Manipulators are operators used in C++ for formatting output. The data is manipulated by the
programmer‗s choice of display.
There are numerous manipulators available in C++. Some of the more commonly used manipulators
are provided here below:

endl Manipulator:
This manipulator has the same functionality as the ‗\n‗ newline character.
For example:

cout << ―Exforsys‖ << endl;


cout << ―Training‖;
produces the output:

Exforsys
Training

setw Manipulator:

This manipulator sets the minimum field width on output. The syntax is:

setw(x)

Here setw causes the number or string that follows it to be printed within a field of x characters wide and x
is the argument set in setw manipulator. The header file that must be included while using setw
manipulator is <iomanip.h>
#include <iostream.h>
#include <iomanip.h>
void main( )
{
int x1=12345,x2= 23456, x3=7892;
cout << setw(8) << ‖Exforsys‖ << setw(20) <<
‖Values‖ << endl
1. setw(8) << ―E1234567‖ << setw(20)<< x1 << end
2. setw(8) << ―S1234567‖ << setw(20)<< x2 << end
3. setw(8) << ―A1234567‖ << setw(20)<< x3 << end;

}
The output of the above example is:
setw(8) setw(20)
Exforsys Values
E1234567 12345
S1234567 23456
A1234567 7892

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

setfill Manipulator:

This is used after setw manipulator. If a value does not entirely fill a field, then the character specified in the
setfill argument of the manipulator is used for filling the fields.

#include <iostream.h>
#include <iomanip.h>
void main( )
{
cout << setw(10) << setfill(‗$‗) << 50 << 33 << endl;
}

The output of the above program is

$$$$$$$$5033

This is because the setw sets 10 width for the field and the number 50 has only 2 positions in it. So the
remaining 8 positions are filled with $ symbol which is specified in the setfill argument.

setprecision Manipulator:

The setprecision Manipulator is used with floating point numbers. It is used to set the number of digits
printed to the right of the decimal point. This may be used in two forms:

fixed
scientific

These two forms are used when the keywords fixed or scientific are appropriately used before the
setprecision manipulator.
The keyword fixed before the setprecision manipulator prints the floating point number in
fixed notation.
The keyword scientific before the setprecision manipulator prints the floating point number
in scientific notation.

#include <iostream.h>
#include <iomanip.h>
void main( )
{

float x = 0.1;
cout << fixed << setprecision(3) << x << endl;
cout << sceintific << x << endl;
}

The above gives ouput as:

0.100
1.000000e-001

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

The first cout statement contains fixed notation and the setprecision contains argument 3. This means that
three digits after the decimal point and in fixed notation will output the first cout statement as 0.100. The
second cout produces the output in scientific notation. The default value is used since no setprecision
value is provided.

Manipulators with Parameters


Manipulators with parameters are more complex than those without because there are additional issues to
consider. Before we explore these issues in detail and examine various techniques for implementing
manipulators with parameters, let's take a look at one particular technique, the one that is used to implement
standard manipulators such as std::setprecision(), std::setw(), etc.

The Standard Manipulators


This implementation of the standard iostreams uses a certain technique for implementing most standard
manipulators with parameters: the manipulator type manipT is a function pointer type; the manipulator
object is the function pointed to; and the associated function fmanipT is a non-member function.
The C++ standard informally refers to the manipulator type as smanip. The type itself is implementation-
specified and may not be accessible to user code at all (i.e., it may be defined in some private namespace or
called something entirely different); all you know is that it is returned by some of the standard manipulators.
In this implementation, the type referred to as smanip is a class template:
template<class T>
class smanip {
public:
smanip(ios_base& (*pf)(ios_base&, T), T arg);
};
A standard manipulator like std::setprecision() can be implemented as a non-member function returning
an object of some implementation-specified type smanip:
smanip<int> setprecision(int n)
{
return smanip<int>(sprec, n);
}
The associated function fmanipT is a private function, let's call it sprec:
ios_base& sprec(ios_base& str, int n)
{
str.precision(n);
return str;
}

The Principle of Manipulators with Parameters

The previous section gave an example of a technique for implementing a manipulator with one parameter:
the technique used to implement the standard manipulators in iostreams. However, this is not the only way
to implement a manipulator with parameters. In this section, we examine other techniques. Although all
explanations are in terms of manipulators with one parameter, it is easy to extend the techniques to
manipulators with several parameters.
Let's start right at the beginning: what is a manipulator with a parameter?
A manipulator with a parameter is an object that can be inserted into or extracted from a stream in an
expression like:

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

std::cout << Manip(x);


std::cin >> Manip(x);
Manip(x) must be an object of type manipT, for which the shift operators are overloaded. Here's an
example of the corresponding inserter:
template <class charT, class Traits>
std::basic_ostream<charT,Traits>&
operator<< (std::basic_ostream<charT,Traits>& ostr ,const
manipT& manip)
{ // call the associated function fmanipT, for example
(*manip.fmanipT )(ostr,manip.argf);
return os;
}

With this inserter defined, the expression std::cout << Manip(x); is equivalent to a call to the shift operator
sketched above; that is, operator<<(std::cout, Manip(x)). Note that the name of the operator<<() does not
need to be qualified with the name of any namespace. Since the operator will typically be defined in the
same namespace as one of its arguments, it is in those namespaces that the operator definition will be sought
to resolve the call.
Assuming that a side effect is created by an associated function fmanipT, the manipulator must call the
associated function with its respective argument(s). Hence it must store the associated function together with
its argument(s) for a call from inside the shift operator.
The associated function fmanipT can be a static member or a namespace-scope function, or even a member
function of type manipT, for example.
In the inserter above, we've assumed that the associated function fmanipT is a static or a non-member
function, and that it takes exactly one argument. Generally, the manipulator type manipT might look like
this:
template <class FctPtr, class Arg1, class Arg2, ...>
class manipT
{
public:
manipT(FctPtr, Arg1, Arg2, ...);
private:
FctPtr fp_;
Arg1 arg1_;
Arg2 arg2_;
};
Note that this is only a suggested manipulator, however. In principle, you can define the manipulator type
in any way that makes the associated side effect function and its arguments available for a call from inside
the respective shift operators for the manipulator type. We show other examples of such manipulator types
later in this chapter; for instance, a manipulator type called smanip mentioned by the C++ standard. It is
an implementation-defined function type returned by the standard manipulators. See the Apache C++
Standard Library Reference Guide for details.
Returning now to the example above, the manipulator object provided as an argument to the overloaded
shift operator is obtained by Manip(x), which has three possible solutions:
1. Manip(x) is a function call. In this case, Manip would be the name of a function that takes an argument
of type x and returns a manipulator object of type manipT; that is, Manip is a function with the
following signature:
manipT Manip (X x);

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Manip(x) is a constructor call. In this case, Manip would be the name of a class with a constructor that
takes an argument of type X and constructs a manipulator object of type Manip; that is, Manip and
manipT would be identical:
struct Manip {
Manip(X x);
};
Manip(x) is a call to a function object. In this case, Manip would be an object of a class M, which
defines a function call operator that takes an argument of type x and returns a manipulator object
of type manipT:
struct M {
manipT operator()(X x);
} Manip;
Solutions 1.) and 2.) are semantically different from solution 3.). In solution 1.), Manip is a function and
therefore need not be created by the user. In solution 2.), Manip is a class name and an unnamed temporary
object serves as manipulator object. In solution 3.), however, the manipulator object Manip must be
explicitly created by the user. Hence the user has to write:
manipT Manip;

std::cout << Manip(x);

which is somewhat inconvenient because it forces the user to know an additional name, the manipulator
type manipT, and to create the manipulator object Manip. An alternative could be to provide Manip as a
static or a global object at the user's convenience, but this approach would introduce the well-known order-
of-initialization problems for global
and static objects. For these reasons, solution 3.) is useful if the manipulator has state; that is, if it stores
additional data like a manipulator, let's call it lineno, which provides the next line number each time it is
inserted.
For any of the three solutions just discussed, there is also a choice of associated functions. The
associated function fmanipT can be either:
3) A static or a namespace-scope function;
4) A static member function;
5) A virtual member function.

Among these choices, b.), the use of a static member function, is the preferable in an object-oriented program
because it permits encapsulation of the manipulator together with its associated function. This is particularly
recommended if the manipulator has state, as in solution 3.), where the manipulator is a function object, and
the associated function has to access the manipulator's state. Using c.), a virtual member function, introduces
the overhead of a virtual function call each time the manipulator is inserted or extracted. It is useful if the
manipulator has state, and the state needs to be modified by the associated manipulator function. A static
member function would only be able to access the manipulator's static data; a non-static member function,
however, can access the object-specific data.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Array
In C programming, one of the frequently problem is to handle similar types of data. For example:
if the user wants to store marks of 500 students, this can be done by creating 500 variables
individually but, this is rather tedious and impracticable. These types of problem can be handled
in C programming using arrays.

An array in C Programing can be defined as number of memory locations, each of which can
store the same data type and which can be references through the same variable name. It is a
collective name given to a group of similar quantities. These similar quantities could be marks of
500 students, number of chairs in university, salaries of 300 employees or ages of 250 students.
Thus we can say array is a sequence of data item of homogeneous values (same type). These
values could be all integers, floats or characters etc.

We have two types of arrays:

4. One-dimensional arrays.
5. Multidimensional arrays.

One Dimensional Arrays:


A one-dimensional array is a structured collection of components (often called array elements)
that can be accessed individually by specifying the position of a component with a single index
value. Arrays must be declared before they can be used in the program. Here is the declaration
syntax of one dimensional array:

data_type array_name[array_size];

Here “data_type” is the type of the array we want to define, “array_name” is the name given to
the array and “array_size” is the size of the array that we want to assign to the array. The array
size is always mentioned inside the “*+”.

For example:
Int age[5];

Int age [5];

Here int is Age is the [5] is the size of


the data name of the the array
type array

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

The following will be the result of the above declarations:

age[0] age[1] age[2] age[3] age[4]

Initializing Arrays
Initializing of array is very simple in c programming. The initializing values are enclosed within the curly
braces in the declaration and placed following an equal sign after the array name. Here is an example
which declares and initializes an array of five elements of type int. Array can also be initialized after
declaration. Look at the following code, which demonstrate the declaration and initialization of an array.

int age[5]={2,3,4,5,6};

It is not necessary to define the size of arrays during initialization e.g.

int age[]={2,3,4,5,6};

In this case, the compiler determines the size of array by calculating the number of elements of an array.

age[0] age[1] age[2] age[3] age[4]


2 3 4 5 6

Accessing array elements


In C programming, arrays can be accessed and treated like variables in C.

For example:

 scanf("%d",&age[2]);
//statement to insert value in the third element of array age[]

 printf("%d",age[2]);
//statement to print third element of an array.

Arrays can be accessed and updated using its index.An array of n elements, has indices ranging from 0
to n-1. An element can be updated simply by assigning

A[i] = x;
A great care must be taken in dealing with arrays. Unlike in Java, where array index out of bounds
exception is thrown when indices go out of the 0..n-1 range, C arrays may not display any warnings if out
of bounds indices are accessed. Instead,compiler may access the elements out of bounds, thus leading
to critical run time errors.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Example of array in C programming

/* C program to find the sum marks of n students using arrays */

#include <stdio.h>

int main(){

int i,n;
int marks[n];
int sum=0;

printf("Enter number of students: ");


scanf("%d",&n);

for(i=0;i<n;i++){
printf("Enter marks of student%d: ",i+1);
scanf("%d",&marks[i]); //saving the marks in array
sum+=marks[i];
}

printf("Sum of marks = %d",sum);

return 0;

Output :

Enter number of students: (input by user)3


Enter marks of student1: (input by user) 10
Enter marks of student2: (input by user) 29
Enter marks of student3: (input by user) 11

Sum of marks = 50

Important thing to remember in C arrays


Suppose, you declared the array of 10 students. For example: students[10]. You can use array
members from student[0] to student[9]. But, what if you want to use element student[10],
student[100] etc. In this case the compiler may not show error using these elements but, may cause
fatal error during program execution.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Multidimensional Arrays:
C programming language allows the user to create arrays of arrays known as multidimensional arrays.
To access a particular element from the array we have to use two subscripts one for row number and
other for column number. The notation is of the form array [i] [j] where i stands for row subscripts and j
stands for column subscripts. The array holds i*j elements. Suppose there is a multidimensional array
array[i][j][k][m]. Then this array can hold i*j*k*m numbers of data. In the same way, the array of any
dimension can be initialized in C programming. For example :

int smarks[3][4];

Here, smarks is an array of two dimension, which is an example of multidimensional array. This array
has 3 rows and 4columns. For better understanding of multidimensional arrays, array elements of above
example can be as below:

Col 1 Col 2 Col 3 Col 4


Row 1 smakrs[0][0] smarks[0][1] smarks[0][2] smarks[0][3]

Row 2 smarks[1][0] smarks[1][1] smarks[1][2] smarks[1][3]


Row 3 smarks[2][0] smarks[2][1] smarks[2][2] smarks[2][3]

Make sure that you remember to put each subscript in its own, correct pair of brackets. All three
examples below are wrong.

int a2[5, 7]; /* XXX WRONG */

a2[i, j] = 0; /* XXX WRONG */

a2[j][i] = 0; /* XXX WRONG */

would do anything remotely like what you wanted

Initialization of Multidimensional Arrays


In C, multidimensional arrays can be initialized in different number of ways.

int smarks[2][3]={{1,2,3}, {-1,-2,-3}};


OR
int smarks[][3]={{1,2,3}, {-1,-2,-3}};
OR
int smarks[2][3]={1,2,3,-1,-2,-3};

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Coding example of Multidimensional Array:

This program asks user to enter the size of the matrix (rows and column) then, it asks the user to enter
the elements of two matrices and finally it adds two matrix and displays the result.

Source Code to Add Two Matrix in C programming


#include <stdio.h>

int main(){
int r,c;
int a[r][c];
int b[r][c];
int sum[r][c;

printf("Enter number of rows (between 1 and 100): ");


scanf("%d",&r);

printf("Enter number of columns (between 1 and 100):


"); scanf("%d",&c);

printf("\nEnter elements of 1st matrix:\n");

/* Storing elements of first matrix entered by user. */

for(int i=0;i<r;++i){
for(int j=0;j<c;++j){
printf("Enter element a%d%d: ",i+1,j+1);
scanf("%d",&a[i][j]);
}
}

/* Storing elements of second matrix entered by user. */

printf("Enter elements of 2nd matrix:\n");


for(int i=0;i<r;++i){
for(int j=0;j<c;++j){
printf("Enter element a%d%d: ",i+1,j+1);
scanf("%d",&b[i][j]);
}
}

/*Adding Two matrices */

for(int i=0;i<r;++i)
for(int j=0;j<c;++j)
sum[i][j]=a[i][j]+b[i][j];

/* Displaying the resultant sum matrix. */

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

printf("\nSum of two matrix is: \n\n");


for(int i=0;i<r;++i){
for(int j=0;j<c;++j){
printf("%d ",sum[i][j]);
if(j==c-1)
printf("\n\n");
}

return 0;

Program Output:
Enter number of rows (between 1 and 100): 3
Enter number of rows (between 1 and 100): 2

Enter elements of 1st matrix:


Enter element a11: 4
Enter element a12: -4
Enter element a21: 8
Enter element a22: 5
Enter element a31: 1
Enter element a32: 0
Enter elements of 2nd matrix:
Enter element a11: 4
Enter element a12: -7
Enter element a21: 9
Enter element a22: 1
Enter element a31: 4
Enter element a32: 5

Sum of two matrix is:

8 -11

6) 5

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Dynamic Arrays and Resizing


Arrays by definition are static structures, meaning that size cannot be changed during run time. When
an array is defined as

int A[n];

then A is considered a static array and memory is allocated from the run time stack for A. When A goes
out of scope, the memory is deallocated and A no longer can be referenced. C allows dynamic
declaration of an array as follows:

int* A = (int*)malloc(n* sizeof(int))

The above code declares a memory block of size n*sizeof(int) that can be accessed using the pointer A.
For example, A can be initialized as follows:

int i;
for (i=0; i<n; i++)
A[i] = 0;

Note that although A was declared as a pointer, A can be treated as an array. The difference between

int A[10] and int* A = malloc(10*sizeof(int)) is that latter is assigned memory in the dynamic heap (and

hence must be managed by the programmer) and former is assigned memory from the run time stack
(and hence managed by the compiler). Static arrays are used when we know the amount of bytes in array
at compile time while the dynamic array is used where we come to know about the size on run time.
Arrays can also be initialized using the calloc() functions instead of the the malloc(). Calloc function is
used to reserve space for dynamic arrays. Has the following form.

array =(cast-type*)calloc(n,element-size);

Number of elements in the first argument specifies the size in bytes of one element to the second
argument. A successful partitioning, that address is returned, NULL is returned on failure. For example,
an int array of 10 elements can be allocated as follows.
int * array = (int *) calloc (10, sizeof (int));

Note that this function can also malloc, written as follows.

int * array = (int *) malloc (sizeof (int) * 10)

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Arrays and Functions

In C, Arrays can be passed to functions using the array name. Array name is a const pointer to the array.
both one-dimensional and multi-dimensional array can be passed to function as argument. Individual
element is passed to function using pass by value. Original Array elements remain unchanged, as the
actual element is never passed to function. Thus function body cannot modify original value in this case.
If we have declared an array ‘array *5+‘ then instead of passing individual elements, a for loop is useful
in this case to pass all 5 elements of the array.

Passing One-dimensional Array In Function

C program to pass a single element of an array to function


#include <stdio.h>
void display(int a)
{
printf("%d",a);
}
int main(){
int c[]={2,3,4};
display(c[2]); //Passing array element c[2] only.
return 0;
}

Output

4
Single element of an array can be passed in similar manner as passing variable to a function.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Passing entire one-dimensional array to a function


While passing arrays to the argument, the name of the array is passed as an argument(,i.e, starting
address of memory area is passed as argument).

C program to pass an array containing age of person to a function. This function will return
average age and display the average age in main function.

#include <stdio.h>
float average(float a[]);
int main(){
float avg, c[]={23.4, 55, 22.6, 3, 40.5, 18};
avg=average(c); /* Only name of array is passed as argument. */
printf("Average age=%.2f",avg);
return 0;
}
float average(float a[]){
int i;
float avg, sum=0.0;
for(i=0;i<6;++i){
sum+=a[i];
}
avg =(sum/6);
return avg;
}

Output
Average age=27.08

Passing Multi-dimensional Arrays to Function


To pass two-dimensional array to a function as an argument, starting address of memory area reserved
is passed as in one dimensional array

Example to pass two-dimensional arrays to function


#include
void Function(int c[2][2]);
int main(){
int c[2][2],i,j;
printf("Enter 4 numbers:\n");
for(i=0;i<2;++i)
for(j=0;j<2;++j){

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

scanf("%d",&c[i][j]);
}
Function(c); /* passing multi-dimensional array to function */
return 0;
}
void Function(int c[2][2]){
/* Instead to above line, void Function(int c[][2]){ is also valid
*/ int i,j;
printf("Displaying:\n");
for(i=0;i<2;++i)
for(j=0;j<2;++j)
printf("%d\n",c[i][j]);

Output
Enter 4 numbers:
2
3
4
5
Displaying:
2
3
4
5

Pointers
A variable in a program is something with a name, the value of which can vary. The way the compiler
and linker handles this is that it assigns a specific block of memory within the computer to hold the value
of that variable. The size of that block depends on the range over which the variable is allowed to vary.
For example, on 32 bit PC's the size of an integer variable is 4 bytes. On older 16 bit PCs integers were 2
bytes. In C the size of a variable type such as an integer need not be the same on all types of machines.
We have integers, long integers and short integers which you can read up on in any basic text on C. This
document assumes the use of a 32 bit system with 4 byte integers.

When we declare a variable we inform the compiler of two things, the name of the variable and the
type of the variable. For example, we declare a variable of type integer with the name k by writing:

int k;

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

On seeing the "int" part of this statement the compiler sets aside 4 bytes of memory to hold the value of
the integer. It also sets up a symbol table. In that table it adds the symbol k and the relative address in
memory where those 4 bytes were set aside.

Thus, later if we write:

k = 2;

We expect that, at run time when this statement is executed, the value 2 will be placed in that memory
location reserved for the storage of the value of k. In C we refer to a variable such as the integer k as an
"object".

In a sense there are two "values" associated with the object k. One is the value of the integer stored
there and the other the "value" of the memory location, i.e., the address of k. Some texts refer to
these two values with the nomenclature rvalue.

Now consider the following:

int j, k;
k = 2;
j = 7; <-- line 1
k = j; <-- line 2

Here the compiler interprets the j in line 1 as the address of the variable j and creates code to copy the
value 7 to that address. In line 2, however, the j is interpreted as its rvalue. That is, here the j refers to
the value stored at the memory location set aside for j. So,7 is copied to the address designated to k.

In C when we define a pointer variable we do so by preceding its name with an asterisk. We also give our
pointer a type which, in this case, refers to the type of data stored at the address we will be storing in
our pointer. For example, consider the variable declaration:

int *ptr;

ptr is the name of our variable, the '*' informs the compiler that we want a pointer variable, i.e. to set
aside however many bytes is required to store an address in memory. The int says that we intend to use
our pointer variable to store the address of an integer. Such a pointer is said to "point to" an integer. A
pointer initialized in this manner is called a "null" pointer.

The actual bit pattern used for a null pointer may or may not evaluate to zero since there is no value
assigned to it. Thus, setting the value of a pointer using the NULL macro, as with an assignment
statement such as ptr = NULL, guarantees that the pointer has become a null pointer.

Suppose now that we want to store in ptr the address of our integer variable k. To do this we use the
unary & operator and write:

ptr = &k;

The "dereferencing operator" is the asterisk and it is used as follows:

*ptr = 7;

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

will copy 7 to the address pointed to by ptr. Thus if ptr "points to" (contains the address of) k, the above
statement will set the value of k to 7. That is, when we use the '*' this way we are referring to the value
of that which ptr is pointing to, not the value of the pointer itself.

Similarly, we could write:

printf("%d\n",*ptr);

to print to the screen the integer value stored at the address pointed to by ptr.

Arrays and Pointers


Arrays and pointers are closely related in C. In fact an array declared as

int A[10];

can be accessed using its pointer representation. The name of the array A is a constant pointer to the
first element of the array. So A can be considered a const int*. Since A is a constant pointer, A = NULL
would be an illegal statement. Arrays and pointers are synonymous in terms of how they use to access
memory. But, the important difference between them is that, a pointer variable can take different
addresses as value whereas, in case of array it is fixed.

Consider the following array:

Int age[5];
Here ‘age’ points
to the first
element of the
age[0] age[1] age[2] age[3] age[4]

In C , name of the array always points to the first element of an array. Here, address of first element of
an array is &age[0]. Also, age represents the address of the pointer where it is pointing. Hence, &age[0]
is equivalent to age. Note, value inside the address &age[0] and address age are equal. Value in
address &age[0] is age[0] and value in address age is *age. Hence, age[0] is equivalent to *age.

C arrays can be of any type. We define array of ints, chars, doubles etc. We can also define an array of
pointers as follows. Here is the code to define an array of n char pointers or an array of strings.

char* A[n];

each cell in the array A[i] is a char* and so it can point to a character. Now if you would like to assign
a string to each A[i] you can do something like this.

A[i] = malloc(length_of_string + 1);

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Again this only allocates memory for a string and you still need to copy the characters into this string.
So if you are building a dynamic dictionary (n words) you need to allocate memory for n char*’s and
then allocate just the right amount of memory for each string.

In C, you can declare an array and can use pointer to alter the data of an array. This program declares
the array of six element and the elements of that array are accessed using pointer, and returns the sum.

//Program to find the sum of six numbers with arrays and pointers.
#include <stdio.h>
int main(){
int i,class[6],sum=0;
printf("Enter 6 numbers:\n");
for(i=0;i<6;++i){
scanf("%d",(class+i)); // (class+i) is equivalent to &class[i]
sum += *(class+i); // *(class+i) is equivalent to class[i]
}
printf("Sum=%d",sum);
return 0;
}

Output

Enter 6 numbers:
2
3
4
5
3
4
Sum=21

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Pointer Array
A pointer is a place in memory that keeps address An array is a single, pre allocated chunk of
of another place inside contiguous elements (all of the same type), fixed
in size and location.
th
Allows us to indirectly access variables. In other Expression a[4] refers to the 5 element of the
words, we can talk about its address rather than array a.
its value

Pointer can’t be initialized at definition Array can be initialized at definition. Example

int num[] = { 2, 4, 5}
Pointer is dynamic in nature. The memory They are static in nature. Once memory is
allocation can be resized or freed later. allocated , it cannot be resized or freed
dynamically

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Unit-II
Functions and Classes
C++ Functions
A function groups a number of program statements into a unit and gives it a name. This unit can then
be invoked from other parts of the program. The function‘s code is stored in only one place in
memory, even though the function is executed many times in the course of the program‘s execution.
Functions help to reduce the program size when same set of instructions are to be executed again and
again. A general function consists of three parts, namely, function declaration (or prototype),
function definition and function call.

Function declaration — prototype:


A function has to be declared before using it, in a manner similar to variables and constants. A
function declaration tells the compiler about a function's name, return type, and parameters and how
to call the function. The general form of a C++ function declaration is as follows:
return_type function_name( parameter list );

Function definition
The function definition is the actual body of the function. The function definition consists of two parts
namely, function header and function body.
The general form of a C++ function definition is as follows:
return_type function_name( parameter list )
{ body of the function }

Here, Return Type: A function may return a value. The return_type is the data type of the value
the function returns. Some functions perform the desired operations without returning a value. In
this case, the return_type is the keyword void.
Function Name: This is the actual name of the function.

Parameters: A parameter is like a placeholder. When a function is invoked, you pass a value to
the parameter. This value is referred to as actual parameter or argument. The parameter list refers to
the type, order, and number of the parameters of a function. Parameters are optional; that is, a
function may contain no parameters.

Function Body: The function body contains a collection of statements that define what the function
does.

Calling a Function
To use a function, you will have to call or invoke that function. To call a function, you simply need
to pass the required parameters along with function name, and if function returns a value, then you
can store returned value.
A c++ program calculating factorial of a number using functions

#include<iostream.h>

#include<conio.h>

int factorial(int n); //function declaration

int main(){

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

int no, f;

cout<<‖enter the positive number:-―;

cin>>no;

f=factorial(no); //function call

cout<<‖\nThe factorial of a number‖<<no<<‖is‖<<f;

return 0;

int factorial(int n) //function definition

{ int i , fact=1;
for(i=1;i<=n;i++){

fact=fact*i;

return fact;

Inline Functions
An inline function is a function that is expanded inline at the point at which it is invoked, instead of
actually being called. The reason that inline functions are an important addition to C++ is that they
allow you to create very efficient code. Each time a normal function is called, a significant amount of
overhead is generated by the calling and return mechanism. Typically, arguments are pushed onto the
stack and various registers are saved when a function is called, and then restored when the function
returns. The trouble is that these instructions take time. However, when a function is expanded inline,
none of those operations occur. Although expanding function calls in line can produce faster run
times, it can also result in larger code size because of duplicated code. For this reason, it is best to
inline only very small functions. inline is actually just a request, not a command, to the compiler. The
compiler can choose to ignore it. Also, some compilers may not inline all types of functions. If a
function cannot be inlined, it will simply be called as a normal function.
A function can be defined as an inline function by prefixing the keyword inline to the function header
as given below:
inline function header {
function body
}
// A program illustrating inline

function #include<iostream.h>

#include<conio.h>

inline int max(int x, int


y){ if(x>y)

return x;

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

else

return y;

int main( ) {

int a,b;

cout<<‖enter two numbers‖;

cin>>a>>b;

cout << "The max is: " <<max(a,,b) << endl;

return 0;

Macros Vs inline functions


Preprocessor macros are just substitution patterns applied to your code. They can be used almost
anywhere in your code because they are replaced with their expansions before any compilation
starts. Inline functions are actual functions whose body is directly injected into their call site. They
can only be used where a function call is appropriate.

inline functions are similar to macros (because the function code is expanded at the point of the call
at compile time), inline functions are parsed by the compiler, whereas macros are expanded by the
preprocessor. As a result, there are several important differences:
 
 Inline functions follow all the protocols of type safety enforced on normal functions.

  as any other function except that they include
Inline functions are specified using the same syntax
the inline keyword in the function declaration.
 
 Expressions passed as arguments to inline functions are evaluated once.
 
 In some cases, expressions passed as arguments to macros can be evaluated more than once.


 at pre-compile time, you cannot use them for debugging, but you can use
macros are expanded
inline functions.

Reference variable
A reference variable is an alias, that is, another name for an already existing variable. Once a
reference is initialized with a variable, either the variable name or the reference name may be used to
refer to the variable. To declare a reference variable or parameter, precede the variable's name with
the &.The syntax for declaring a reference variable is:
datatype &Ref = variable name;
Example:

int main(){

int var1=10; //declaring simple variable

int & var2=var1; //declaring reference variable

cout<<―\n value of var2 =‖ << var2;

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

return 0;

var2 is a reference variable to var1.Hence, var2 is an alternate name to var1.This code prints the value
of var2 exactly as that of var1.

Call by reference
Arguments can be passed to functions in one of two ways: using call-by-value or call-by-reference.
When using call-by-value, a copy of the argument is passed to the function. Call-by-reference passes
the address of the argument to the function. By default, C++ uses call-by-value.

Provision of the reference variables in c++ permits us to pass parameter to the functions by
reference. When we pass arguments by reference, the formal arguments in the called function
become aliases to the actual arguments in the calling function. This means that when the function is
working with its own arguments, it is actually working on the original data.

Example
#include <iostream.h>

#include<conio.h>

void swap(int &x, int &y); // function declaration

int main (){

int a = 10, b=20;

cout << "Before swapping‖<<endl;

cout<< ―value of a :" << a <<‖ value of b :" << b << endl;

swap(a, b); //calling a function to swap the values.

cout << "After swapping‖<<endl;

cout<<‖ value of a :" << a<< ―value of b :" << b << endl;

return 0;

void swap(int &x, int &y) { //function definition to swap the values.

int temp;

temp = x;

x = y;

y = temp;

Output:

Before swapping value of a:10 value of b:20

After swapping value of a:20 value of b:10

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Function Overloading
Function overloading is the process of using the same name for two or more functions. Each
redefinition of the function must use either different types of parameters or a different number of
parameters. It is only through these differences that the compiler knows which function to call in any
given situation. Overloaded functions can help reduce the complexity of a program by allowing
related operations to be referred to by the same name. To overload a function, simply declare and
define all required versions. The compiler will automatically select the correct version based upon
the number and/or type of the arguments used to call the function. Two functions differing only in
their return types cannot be overloaded.
Example
#include<iostream.h>

#include<conio.h>

int sum(int p,int q,int r);

double sum(int l,double m);

float sum(float p,float q)

int main(){

cout<<‖sum=‖<< sum(11,22,33); //calls func1

cout<<‖sum=‖<< sum(10,15.5); //calls func2

cout<<‖sum=‖<< sum(13.5,12.5); //calls func3

return 0;

int sum(int p,int q,int r){ //func1

return(a+b+c);

double sum(int l,double m){ //func2

return(l+m);

float sum(float p,float q){ //func3

return(p+q);

Default arguments
C++ allows a function to assign a parameter a default value when no argument corresponding to that
parameter is specified in a call to that function. The default value is specified in a manner
syntactically similar to a variable initialization. All default parameters must be to the right of any
parameters that don't have defaults. We cannot provide a default value to a particular argument in the
middle of an argument list. When you create a function that has one or more default arguments, those
arguments must be specified only once: either in the function's prototype or in the function's definition
if the definition precedes the function's first use.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Default arguments are useful if you don‘t want to go to the trouble of writing arguments that, for
example, almost always have the same value. They are also useful in cases where, after a program is
written, the programmer decides to increase the capability of a function by adding another
argument. Using default arguments means that the existing function calls can continue to use the old
number of arguments, while new function calls can use more.
Example
#include <iostream.h>

#include<conio.h>

int sum(int a, int b=20){

return( a + b);

int main (){

int a = 100, b=200, result;

result = sum(a, b); //here a=100 , b=200

cout << "Total value is :" << result << endl;

result = sum(a); //here a=100 , b=20(using default value)

cout << "Total value is :" << result << endl;

return 0;

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Class
A class is a user defined data type. A class is a logical abstraction. It is a template that defines the
form of an object. A class specifies both code and data. It is not until an object of that class has been
created that a physical representation of that class exists in memory. When you define a class, you
declare the data that it contains and the code that operates on that data. Data is contained in instance
variables defined by the class known as data members, and code is contained in functions known as
member functions. The code and data that constitute a class are called members of the class. The
general form of class declaration is:
class class-name {
access-specifier:
data and functions
access-specifier:
data and functions
// ...
access-specifier:
data and functions
} object-list;
The object-list is optional. If present, it declares objects of the class. Here, access-specifier is one of
these three C++ keywords:
public private protected

By default, functions and data declared within a class are private to that class and may be accessed
only by other members of the class. The public access_specifier allows functions or data to be
accessible to other parts of your program. The protected access_specifier is needed only when
inheritance is involved.
Example:

#include<iostream.h>

#include<conio.h>

Class myclass { // class declaration

// private members to myclass


int a;

public:

// public members to
myclass void set_a(intnum);

int get_a( );
};

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Object
An object is an identifiable entity with specific characteristics and behavior. An object is said to be
an instance of a class. Defining an object is similar to defining a variable of any data type: Space is
set aside for it in memory. Defining objects in this way means creating them. This is also called
instantiating them. Once a Class has been declared, we can create objects of that Class by using the
class Name like any other built-in type variable as shown:
className objectName
Example
void main( ) {
myclass ob1, ob2; //these are object of type myclass

// ... program code


}

Accessing Class Members


The main() cannot contain statements that access class members directly. Class members can be
accessed only by an object of that class. To access class members, use the dot (.) operator. The dot
operator links the name of an object with the name of a member. The general form of the dot operator
is shown here:
object.member
Example
ob1.set_a(10);

The private members of a class cannot be accessed directly using the dot operator, but through the
member functions of that class providing data hiding. A member function can call another
member function directly, without using the dot operator.
C++ program to find sum of two numbers using classes

#include<iostream.h>

#include<conio.h>

class A{

int a,b,c;

public:

void sum(){

cout<<"enter two numbers";

cin>>a>>b;

c=a+b;

cout<<"sum="<<c;

};

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

int main(){

A u;

u.sum();

getch();

return(0);

Scope Resolution operator


Member functions can be defined within the class definition or separately using scope resolution
operator (::). Defining a member function within the class definition declares the function inline, even
if you do not use the inline specifier. Defining a member function using scope resolution operator
uses following declaration
return-type class-name::func-name(parameter- list) {
// body of function
}

Here the class-name is the name of the class to which the function belongs. The scope resolution
operator (::) tells the compiler that the function func-name belongs to the class class-name. That is,
the scope of the function is restricted to the class-name specified.
Class myclass {
int a;
public:
void set_a(intnum); //member function declaration
int get_a( ); //member function declaration

};
//member function definition outside class using scope resolution operator
void myclass :: set_a(intnum)
{
a=num;
}
int myclass::get_a( ) {
return a;
}

Another use of scope resolution operator is to allow access to the global version of a variable. In many
situation, it happens that the name of global variable and the name of the local variable are same .In

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

this while accessing the variable, the priority is given to the local variable by the compiler. If we want
to access or use the global variable, then the scope resolution operator (::) is used. The syntax for
accessing a global variable using scope resolution operator is as follows:-
:: Global-variable-name

Static Data Members


When you precede a member variable's declaration with static, you are telling the compiler that only
one copy of that variable will exist and that all objects of the class will share that variable. Unlike
regular data members, individual copies of a static member variable are not made for each object. No
matter how many objects of a class are created, only one copy of a static data member exists. Thus,
all objects of that class use that same variable. All static variables are initialized to zero before the
first object is created. When you declare a static data member within a class, you are not defining it.
(That is, you are not allocating storage for it.) Instead, you must provide a global definition for it
elsewhere, outside the class. This is done by redeclaring the static variable using the scope resolution
operator to identify the class to which it belongs. This causes storage for the variable to be allocated.
One use of a static member variable is to provide access control to some shared resource used
by all objects of a class. Another interesting use of a static member variable is to keep track of the
number of objects of a particular class type that are in existence.

Static Member Functions


Member functions may also be declared as static. They may only directly refer to other static
members of the class. Actually, static member functions have limited applications, but one good use
for them is to "preinitialize" private static data before any object is actually created. A static member
function can be called using the class name instead of its objects as follows:
class name :: function name
//Program showing working of static class members

#include <iostream.h>

#include<conio.h>

class static_type {

static int i; //static data member

public:

static void init(int x) {i = x;} //static member function

void show() {cout << i;}};

int static_type :: i; // static data member definition

int main(){

static_type::init(100); //Accessing static function

static_type x;

x.show();

return 0;

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Constructor:
A constructor is a special member function whose task is to initialize the objects of its class. It is
special because its name is same as the class name. The constructor is invoked whenever an object
of its associated class is created. It is called constructor because it construct the value data members
of the class. The constructor functions have some special characteristics.
 
 They should be declared in the public section.
 
 They are invoked automatically when the objects are created.
 
 They do not have return types, not even void and therefore, they cannot return values.
 
They cannot be inherited, though a derived class can call the base class constructor.

Example:

#include< iostream.h>

#include<conio.h>

class myclass { // class declaration

int a;

public:

myclass( ); //default constructor

void show( );

};

myclass :: myclass( ) {

cout <<"In constructor\n";

a=10;

myclass :: show( ) {

cout<< a;

int main( ) {

int ob; // automatic call to constructor

ob.show( );

return0;

In this simple example the constructor is called when the object is created, and the
constructor initializes the private variable a to10.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Default constructor
The default constructor for any class is the constructor with no arguments. When no arguments are
passed, the constructor will assign the values specifically assigned in the body of the constructor. It
can be zero or any other value. The default constructor can be identified by the name of the class
followed by empty parentheses. Above program uses default constructor. If it is not defined
explicitly, then it is automatically defined implicitly by the system.

Parameterized Constructor
It is possible to pass arguments to constructors. Typically, these arguments help initialize an object
when it is created. To create a parameterized constructor, simply add parameters to it the way you
would to any other function. When you define the constructor's body, use the parameters to initialize
the object.
#include <iostream.h>

#include<conio.h>

class myclass {

int a, b;

public:

myclass(int i, int j) //parameterized constructor

{a=i; b=j;}

void show() { cout << a << " " << b;}

};

int main() {

myclass ob(3, 5); //call to constructor

ob.show();

return 0;

C++ supports constructor overloading. A constructor is said to be overloaded when the same
constructor with different number of argument and types of arguments initializes an object.

Copy Constructors
The copy constructor is a constructor which creates an object by initializing it with an object of the
same class, which has been created previously. If class definition does not explicitly include copy
constructor, then the system automatically creates one by default. The copy constructor is used to:
 
 Initialize one object from another of the same type.
 
 Copy an object to pass it as an argument to a function.
 
Copy an object to return it from a function.

The most common form of copy constructor is shown here:


classname (const classname &obj) {
// body of constructor

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

}
Here, obj is a reference to an object that is being used to initialize another object. The keyword const
is used because obj should not be changed.

Destructor
A destructor destroys an object after it is no longer in use. The destructor, like constructor, is a member
function with the same name as the class name. But it will be preceded by the character Tilde
(~).A destructor takes no arguments and has no return value. Each class has exactly one destructor. . If
class definition does not explicitly include destructor, then the system automatically creates one by
default. It will be invoked implicitly by the compiler upon exit from the program to clean up storage
that is no longer accessible.
// A Program showing working of constructor and
destructor #include<iostream.h>

#include<conio.h>

class Myclass{

public:

int x;

Myclass(){ //Constructor

x=10; }

~Myclass(){ //Destructor

cout<<‖Destructing….‖ ;

int main(){

Myclass ob1, ob2;

cout<<ob1.x<<‖ ―<<ob2.x;

return 0; }

10 10
Destructing……..

Destructing……..

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Operator overloading
There is another useful methodology in C++ called operator overloading. The language allows not only
functions to be overloaded, but also most of the operators, such as +, -, *, /, etc. As the name suggests,
here the conventional operators can be programmed to carry out more complex operations. This
overloading concept is fundamentally the same i.e. the same operators can be made to perform

different operations depending on the context. Such operators have to be specifically defined and
appropriate function programmed. When an operator is overloaded, none of its original meaning is
lost. It is simply that a new operation, relative to a specific class, is defined. For example, a class that
defines a linked list might use the + operator to add an object to the list. A class that implements a
stack might use the + to push an object onto the stack.

An operator function defines the operations that the overloaded operator will perform relative to
the class upon which it will work. An operator function is created using the keyword operator. The
general form of an operator function is
type classname::operator#(arg-list) { // operations
}

Here, the operator that you are overloading is substituted for the #, and type is the type of value
returned by the specified operation. Operator functions can be either members or nonmembers of a
class. Nonmember operator functions are often friend functions of the class.
These operators cannot be overloaded:- ., : :, .*, ?
The process of overloading involves the following steps:
 
 Create a class that defines the data type that is to be used in the overloading operation.
 
 Declare the operator function operator op() in the public part of the class.
 
Define the operator function to implement the required operations.

Overloading a unary operator using member function


Overloading a unary operator using a member function, the function takes no parameters. Since,
there is only one operand, it is this operand that generates the call to the operator function. There is
no need for another parameter.
Overloading unary minus operator

#include<iostream.h>

#include<conio.h>

class A {

int x,y,z;

public:

void getdata(int a,int b,int c) {

x=a;

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

y=b;

z=c;

void display() {

cout<<"\nx="<<x<<"\ny="<<y<<"\nz="<<z;

void operator -() //unary minus overload function

x=-x;

y=-y;

z=-z;

};

int main() {

A a;

a.getdata(2,3,4);

a.display();
-a;

a.display();

getch();

return 0;

Overloading binary operator


When a member operator function overloads a binary operator, the function will have only one
parameter. This parameter will receive the object that is on the right side of the operator. The object
on the left side is the object that generates the call to the operator function and is passed implicitly by
this pointer. ‗this‘ can be used in overloading + operator .
#include<iostream.h>

#include<conio.h>

class A{

int x,y;

public:

void input() {

cin>>x>>y;

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

void display() {

cout<<"\nx="<<x<<"\ny="<<y<<"\nx+y="<<x+y;

A operator+(A p ); //overload binary + operator

};

A A :: operator+(A p) {

A t;

t.x=x + p.x;

t.y=y + p.y;

return t;

int main(){

A a1, a2, a3;

a1.input();

a2.input();

a3=a2+a1; //activates operator+() function

a3.display();

getch();

return 0;

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Unit-III
Inheritance, Polymorphism & Files
Inheritance
Inheritance is the mechanism by which one class can inherit the properties of another. It allows a
hierarchy of classes to be build, moving from the most general to the most specific. When one class
is inherited by another, the class that is inherited is called the base class. The inheriting class is called
the derived class. In general, the process of inheritance begins with the definition of a base class. The
base class defines all qualities that will be common to any derived class. In essence, the base class
represent the most general description of a set of traits. The derived class inherits those general traits
and adds properties that are specific to that class. When one class inherits another, it uses this general
form:
class derived-class-name : access base-class-name{
// ...
}

Here access is one of the three keywords: public, private, or protected. The access
specifier determines how elements of the base class are inherited by the derived class.

When the access specifier for the inherited base class is public, all public members of the base class
become public members of the derived class. If the access specifier is private, all public members of
the base class become private members of the derived class. In either case, any private members of
the base class remain private to it and are inaccessible by the derived class.

It is important to understand that if the access specifier is private, public members of the base
become private members of the derived class. If the access specifier is not present, it is private
by default.

The protected access specifier is equivalent to the private specifier with the sole exception that
protected members of a base class are accessible to members of any class derived from that base.
Outside the base or derived classes, protected members are not accessible. When a protected member
of a base class is inherited as public by the derived class, it becomes a protected member of the
derived class. If the base class is inherited as private, a protected member of the base becomes a
private member of the derived class. A base class can also be inherited as protected by a derived
class. When this is the case, public and protected members of the base class become protected
members of the derived class (of course, private members of the base remain private to it and are not
accessible by the derived class).
Program to illustrate concept of inheritance

#include<iostream.h>

#include<conio.h>

class base //base class

int x,y;

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

public:

void show() {

cout<<"In base class";

};

class derived : public base //derived class

int a,b;

public:

void show2() {

cout<<"\nIn derived class";

};

int main() {

derived d;

d.show(); //uses base class‘s show() function

d.show2(); //uses derived class‘s show2() function

getch();

return 0;

Types of Inheritances

Single Inheritance
The process in which a derived class inherits traits from only one base class, is called single
inheritance. In single inheritance, there is only one base class and one derived class. The derived class
inherits the behavior and attributes of the base class. However the vice versa is not true. The derived
class can add its own properties i.e. data members (variables) and functions. It can extend or use
properties of the base class without any modification to the base class. We declare the base class and
derived class as given below:
class base_class {
};
class derived_ class : visibility-mode base_ class {
};

Program to illustrate concept of single inheritance

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

#include<iostream.h>

#include<conio.h>

class base

int x,y;

public:

void show() {
//base class

cout<<"In base class";

};

class derived : public base //derived class

int a,b;

public:

void show2() {

cout<<"\nIn derived class";

};

int main() {

derived d;

d.show(); //uses base class‘s show() function

d.show2(); //uses derived class‘s show2() function

getch();

return 0;

Ambiguity in single Inheritance


Whenever a data member and member functions are defined with the same name in both the base and
derived class, ambiguity occurs. The scope resolution operator must be used to refer to particular
class as: object name.class name :: class member

Multiple Inheritance
The process in which a derived class inherits traits from several base classes, is called multiple
inheritance. In Multiple inheritance, there is only one derived class and several base classes.
We declare the base classes and derived class as given below:
class base_class1{
};

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

class base_class2{
};
class derived_ class : visibility-mode base_ class1 , visibility-mode base_ class2 {
};

Multilevel Inheritance
The process in which a derived class inherits traits from another derived class, is called Multilevel
Inheritance. A derived class with multilevel inheritance is declared as :
class base_class {
};
class derived_ class1 : visibility-mode base_ class {
};
class derived_ class 2: visibility-mode derived_ class1 {
};
Here, derived_ class 2 inherits traits from derived_ class 1 which itself inherits from base_class.

Hierarchical Inheritance
The process in which traits of one class can be inherited by more than one class is known as
Hierarchical inheritance. The base class will include all the features that are common to the
derived classes. A derived class can serve as a base class for lower level classes and so on.

Hybrid Inheritance
The inheritance hierarchy that reflects any legal combination of other types of inheritance is known
as hybrid Inheritance.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Polymorphism
C++ Virtual Function
A virtual function is a member function that is declared within a base class and redefined by a derived
class. In order to make a function virtual, you have to add keyword virtual in front of a function
definition. When a class containing a virtual function is inherited, the derived class redefines the
virtual function relative to the derived class. The virtual function within the base class defines the
form of the interface to that function. Each redefinition of the virtual function by a derived class
implements its operation as it relates specifically to the derived class. That is, the redefinition creates
a specific method. When a virtual function is redefined by a derived class, the keyword virtual is not
needed. A virtual function can be called just like any member function. However, what makes a
virtual function interesting, and capable of supporting run-time polymorphism, is what happens when
a virtual function is called through a pointer. When a base pointer points to a derived object that
contains a virtual function and that virtual function is called through that pointer, C++ determines
which version of that function will be executed based upon the type of object being pointed to by the
pointer. And this determination is made at run time. Therefore, if two or more different classes are
derived from a base class that contains a virtual function, then when different objects are pointed to by
a base pointer, different versions of the virtual function are executed.
// A simple example using a virtual function.

#include<iostream.h> #include<conio.h>

class base
{ public:

virtual void func( ) {

cout<< "Using base version of func(): ";

};

class derived1 : public base


{ public:

voidfunc( ) {

cout<< "Using derived1's version of func(): ";

};

class derived2 : public base


{ public:

voidfunc( ) {

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

cout<< "Using derived2's version of func(): ";

};

int main( ) {

base *p;

base ob;

derived1 d_ob1;

derived2 d_ob2;

p = &ob;

p- >func( ); // use base's func( )

p = &d_ob1;

p- >func( ); // use derived1's func( )

p = &d_ob2;

p- >func( ); // use derived2's func( )

return 0;

Pure virtual functions


Sometimes when a virtual function is declared in the base class, there is no meaningful operation for it
to perform. This situation is common because often a base class does not define a complete class by
itself. Instead, it simply supplies a core set of member functions and variables to which the derived
class supplies the remainder. When there is no meaningful action for a base class virtual function to
perform, the implication is that any derived class must override this function. To ensure that this will
occur, C++ supports pure virtual functions. A pure virtual function has no definition relative to the
base class. Only the function prototype is included. To make a pure virtual function, use this general
form:
virtual type func-name(parameter-list) = 0;

The key part of this declaration is the setting of the function equal to 0. This tells the compiler that no
body exists for this function relative to the base class. When a virtual function is made pure, it forces
any derived class to override it. If a derived class does not, a compile-time error results. Thus,
making a virtual function pure is a way to guaranty that a derived class will provide its own
redefinition.

Abstract class
When a class contains atleast one pure virtual function, it is referred to as an abstract class. Since, an
abstract class contains atleast one function for which no body exists, it is, technically, an incomplete
type, and no objects of that class can be created. Thus, abstract classes exist only to be inherited. It is
important to understand, however, that you can still create a pointer to an abstract class, since it is
through the use of base class pointers that run-time polymorphism is achieved. (It is also possible to
have a reference to an abstract class.) .

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

classes for file stream operations


The C++ I/O system operates through streams. A stream is logical device that either produces or
consumes information. A stream is linked to a physical device by the C++ I/O system. All streams
behave in the same manner, even if the actual physical devices they are linked to differ. Because
all streams act the same, the I/O system presents the programmer with a consistent interface.
Two types of streams:
Output stream: a stream that takes data from the program and sends (writes) it to destination.
Input stream: a stream that extracts (reads) data from the source and sends it to the program.

C++ provides both the formatted and unformatted IO functions. In formatted or high-level IO, bytes
are grouped and converted to types such as int, double, string or user-defined types. In unformatted
or low-level IO, bytes are treated as raw bytes and unconverted. Formatted IO operations are
supported via overloading the stream insertion (<<) and stream extraction (>>) operators, which
presents a consistent public IO interface.

C++ provides supports for its I/O system in the header file< iostream>. Just as there are different
kinds of I/O (for example, input, output, and file access), there are different classes depending on the
type of I/O. The following are the most important stream classes:

Class istream :- Defines input streams that can be used to carry out formatted and unformatted input
operations. It contains the overloaded extraction (>>) operator functions. Declares input functions
such get(), getline() and read().

Class ostream :- Defines output streams that can be used to write data. Declares output functions
put and write().The ostream class contains the overloaded insertion (<<) operator function

When a C++ program begins, these four streams are automatically opened:

Stream Meaning Default Device


cin Standard input Keyboard
cout Standard output Screen
cerr Standard error Screen
clog Buffer version of cerr Screen

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

File Handling
File. The information / data stored under a specific name on a storage
device, is called a file.
Stream. It refers to a sequence of bytes.
Text file. It is a file that stores information in ASCII characters. In text
files, each line of text is terminated with a special character known as
EOL (End of Line) character or delimiter character. When this EOL
character is read or written, certain internal translations take place.
Binary file. It is a file that contains information in the same format as it is
held in memory. In binary files, no delimiters are used for a line and no
translations occur here.
Classes for file stream operation
ofstream: Stream class to write on files
ifstream: Stream class to read from files
fstream: Stream class to both read and write from/to files.
Opening a file
OPENING FILE USING
CONSTRUCTOR ofstream
fout(“results”); //output only
ifstream fin(“data”); //input only
OPENING FILE USING open()
Stream-object.open(“filename”,
mode)
ofstream ofile;
ofile.open(“data1”);

ifstream ifile;
ifile.open(“data2”);
File mode parameter Meaning
ios::app Append to end of file
ios::ate go to end of file on opening
ios::binary file open in binary mode
ios::in open file for reading only
ios::out open file for writing only
ios::nocreate open fails if the file does not exist
ios::noreplace open fails if the file already exist
ios::trunc delete the contents of the file if it exist

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

All these flags can be combined using the bitwise operator OR (|). For
example, if we want to open the file example.bin in binary mode to add data
we could do it by the following call to member function open():
fstream file;
file.open ("example.bin", ios::out | ios::app | ios::binary);
Closing File
fout.close();
fin.close();
INPUT AND OUTPUT OPERATION
put() and get() function
the function put() writes a single character to the associated stream. Similarly,
the function get() reads a single character form the associated stream.
example :
file.get(ch);
file.put(ch);
write() and read() function
write() and read() functions write and read blocks of binary data.
example:
file.read((char *)&obj, sizeof(obj));
file.write((char *)&obj, sizeof(obj));
ERROR HANDLING FUNCTION
FUNCTION RETURN VALUE AND MEANING
returns true (non zero) if end of file is encountered while reading;
eof() otherwise return false(zero)
fail() return true when an input or output operation has failed
returns true if an invalid operation is attempted or any
bad() unrecoverable error has occurred.
good() returns true if no error has occurred.

File Pointers And Their Manipulation


All i/o streams objects have, at least, one internal stream pointer:
ifstream, like istream, has a pointer known as the get pointer that points to
the element to be read in the next input operation.
ofstream, like ostream, has a pointer known as the put pointer that points
to the location where the next element has to be written.
Finally, fstream, inherits both, the get and the put pointers, from
iostream (which is itself derived from both istream and ostream).

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

The other prototype for these functions


is: seekg(offset, refposition );
seekp(offset, refposition );
The parameter offset represents the number of bytes the file pointer is to be
moved from the location specified by the parameter refposition. The
refposition takes one of the following three constants defined in the ios class.
ios::beg start of the file
ios::cur current position of the pointer
ios::end end of the file
example:
file.seekg(-10, ios::cur)

Basic Operation On Text File In C++


Program to write in a text file
#include<fstream.h>
int main()
{
ofstream fout;
fout.open("out.txt");
char str[300]="Time is a great teacher but unfortunately it kills all its
pupils. Berlioz";
fout<<str;
fout.close();
return 0;
}
Program to read from text file and display it
#include<fstream.h>
#include<conio.h>
int main()
{
ifstream fin;
fin.open("out.txt");
char ch;
while(!fin.eof())
{
fin.get(ch);
cout<<ch;
}
fin.close();

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

getch();
return 0;
}
Program to count number of characters.
#include<fstream.h>
#include<conio.h>
int main()
{
ifstream fin;
fin.open("out.txt");
clrscr();
char ch; int count=0;
while(!fin.eof())
{
fin.get(ch);
count++;
}
cout<<"Number of characters in file is "<<count;
fin.close();
getch();
return 0;
}
Program to count number of words
#include<fstream.h>
#include<conio.h>
int main()
{
ifstream fin;
fin.open("out.txt");
char word[30]; int count=0;
while(!fin.eof())
{

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

fin>>word;
count++;
}
cout<<"Number of words in file is "<<count;
fin.close();
getch();
return 0;
}
Program to count number of lines
#include<fstream.h>
#include<conio.h>
int main()
{
ifstream fin;
fin.open("out.txt");
char str[80]; int count=0;
while(!fin.eof())
{
fin.getline(str,80);
count++;
}
cout<<"Number of lines in file is "<<count;
fin.close();
getch();
return 0;
}
Program to copy contents of file to another file.
#include<fstream.h>
int main()
{
ifstream fin;
fin.open("out.txt");
ofstream fout;
fout.open("sample.txt");
char ch;
while(!fin.eof())
{
fin.get(ch);

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

fout<<ch;
}
fin.close();
return 0;
}
Basic Operation On Binary File In C++
class student
{
int admno;
char name[20];
public:
void getdata()
{
cout<<"\nEnter The admission no. ";
cin>>admno;
cout<<"\n\nEnter The Name of The Student
"; gets(name);
}
void showdata()
{
cout<<"\nAdmission no. : "<<admno;
cout<<"\nStudent Name : ";
puts(name);
}
int retadmno()
{
return admno;
}
};

function to write in a binary file


void write_data()
{
student obj;
ofstream fp2;
fp2.open("student.dat",ios::binary|ios::app);
obj.getdata();

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

fp2.write((char*)&obj,sizeof(obj));
fp2.close();
}
function to display records of file
void display()
{
student obj;
ifstream fp1;
fp1.open("student.dat",ios::binary);
while(fp1.read((char*)&obj,sizeof(obj)))
{
obj.showdata();
}
}
fp.close();
}
Function to search and display from binary file
void search (int n)
{
student obj;
ifstream fp1;
fp1.open("student.dat",ios::binary);
while(fp1.read((char*)&obj,sizeof(obj)))
{
if(obj.retadmno()==n)
obj.showdata();
}
fp1.close();
}
Function to delete a record
void deleterecord(int n)
{
student obj;
ifstream fp1;
fp1.open("student.dat",ios::binary);
ofstream fp2;
fp2.open("Temp.dat",ios::out|ios::binary);

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

while(fp1.read((char*)&obj,sizeof(obj)))
{
if(obj.retadmno!=n)
fp2.write((char*)&obj,sizeof(obj));
}
fp1.close();
fp2.close();
remove("student.dat");
rename("Temp.dat","student.dat");
}
Function to modify a record
void modifyrecord(int n)
{
fstream fp;
student obj;
int found=0;
fp.open("student.dat",ios::in|ios::out);
while(fp.read((char*)&obj,sizeof(obj)) && found==0)
{
if(obj.retadmno()==n)
{
obj.showdata();
cout<<"\nEnter The New Details of
student"; obj.getdata();
int pos=-1*sizeof(obj);
fp.seekp(pos,ios::cur);
fp.write((char*)&obj,sizeof(obj));
found=1;
}
}
fp.close();
}

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

UNIT-IV
Fundamental Data Structures
Introduction to Data Structure
 Computer is an electronic machine which is used for data processing and manipulation.

 When programmer collects such type of data for processing, he would require to store all of
them in computer’s main memory.

  In order to make computer work we need to know o Representation of data in computer.
 o Accessing of data.
 o How to solve problem step by step.
 For doing this task we use data structure.

 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.

 It is defined as the way of storing and manipulating data in organized form so that it can be
used efficiently.
 Data Structure mainly specifies the following four things
Organization of Data o Accessing methods o Degree of associativity
o Processing alternatives for information
 Algorithm + Data Structure = Program
 Data structure study covers the following points o Amount of memory require to store.
o Amount of time require to process. o Representation of data in memory. o Operations
performed on that data.

DATA
STRUCTURE

PRIMITIVE NON
PRIMITIVE

INTEGER FLOATING CHARACTER POINTER ARRAY LIST FILE


POINT

LINEAR LIST NON


LINEAR LIST

STACK QUEUE GRAPH TREE

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Data Structures are normally classified into two broad categories

Primitive Data Structure

Non-primitive data Structure

Data types
A particular kind of data item, as defined by the values it can take, the programming
language used, or the operations that can be performed on it.

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.

 Integers, floats, character and pointers are examples of primitive data structures.
 These data types are available in most programming languages as built in type.
o Integer: It is a data type which allows all values without fraction part. We can use it for
 whole numbers.
 o Float: It is a data type which use for storing fractional numbers.
o Character: It is a data type which is used for character values.
Pointer: A variable that holds memory address of another variable are called pointer.

Non primitive Data Type



 These are more sophisticated data structures.
 These are derived from primitive data structures.

 The non-primitive data structures emphasize on structuring of a group of homogeneous or
 heterogeneous data items.

 Examples of Non-primitive data type are Array, List, and File etc.

 A Non-primitive data type is further divided into Linear and Non-Linear data structure
 o Array: An array is a fixed-size sequenced collection of elements of the same data type.
o List: An ordered set containing variable number of elements is called as Lists.

o File: A file is a collection of logically related information. It can be viewed as a large list of
records consisting of various fields.

Linear data structures


 A data structure is said to be Linear, if its elements are connected in linear fashion by means of
logically or in sequence memory locations.

 There are two ways to represent a linear data structure
 in memory, o Static memory allocation
o 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 Stack and Queue.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

 Stack: Stack is a data structure in which insertion and deletion operations are performed at one
end only. o The insertion operation is referred to as ‘PUSH’ and deletion operation is referred
to as ‘POP’ operation. o Stack is also called as Last in First out (LIFO) data structure.

 Queue: The data structure which permits the insertion at one end and Deletion at another end,
known as Queue.

o End at which deletion is occurs is known as FRONT end and another end at which insertion
 occurs is known as REAR end.
o Queue is also called as First in First out (FIFO) data structure.

Nonlinear data structures


 Nonlinear data structures are those data structure in which data items are not arranged in a
 sequence.
 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.
o Trees represent the hierarchical relationship between various elements.

o Tree consist of nodes connected by edge, the node represented by circle and edge lives
connecting to circle.

Difference between Linear and Non Linear Data Structure


Linear Data Structure Non-Linear Data Structure
Every item is related to its previous and next time. Every item is attached with many other items.
Data is arranged in linear sequence. Data is not arranged in sequence.
Data items can be traversed in a single run. Data cannot be traversed in a single run.
Eg. Array, Stacks, linked list, queue. Eg. tree, graph.
Implementation is easy. Implementation is difficult.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Stacks Operations:
A stack is a container of objects that are inserted and removed according to the last-in first-out
(LIFO) principle. In the pushdown stacks only two operations are allowed: push the item into the
stack, and pop the item out of the stack. A stack is a limited access data structure - elements can be
added and removed from the stack only at the top. Push adds an item to the top of the stack, pop
removes the item from the top. A helpful analogy is to think of a stack of books; you can remove
only the top book, also you can add a new book on the top.

A stack may be implemented to have a bounded capacity. If the stack is full and does not contain
enough space to accept an entity to be pushed, the stack is then considered to be in an overflow state.
The pop operation removes an item from the top of the stack. A pop either reveals previously
concealed items or results in an empty stack, but, if the stack is empty, it goes into underflow state,
which means no items are present in stack to be removed.

Stack (ADT) Data Structure:

Stack is an Abstract data structure (ADT) works on the principle Last In First Out (LIFO). The last
element add to the stack is the first element to be delete. Insertion and deletion can be takes place at
one end called TOP. It looks like one side closed tube.
 The add operation of the stack is called push operation

 The delete operation is called as pop operation.

 Push operation on a full stack causes stack overflow.

 Pop operation on an empty stack causes stack underflow.

 SP is a pointer, which is used to access the top element of the stack.

 If you push elements that are added at the top of the stack;

 In the same way when we pop the elements, the element at the top of the stack is deleted.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Operations of stack:
There are two operations applied on stack they are
1. push
2. pop.
While performing push & pop operations the following test must be conducted on the stack.
1) Stack is empty or not
2) Stack is full or not
Push:
Push operation is used to add new elements in to the stack. At the time of addition first check the stack is
full or not. If the stack is full it generates an error message "stack overflow". Pop:

Pop operation is used to delete elements from the stack. At the time of deletion first check the stack is
empty or not. If the stack is empty it generates an error message "stack underflow".
Representation of a Stack using Arrays:

Let us consider a stack with 6 elements capacity. This is called as the size of the stack. The number of
elements to be added should not exceed the maximum size of the stack. If we attempt to add new
element beyond the maximum size, we will encounter a stack overflow condition. Similarly, you cannot
remove elements beyond the base of the stack. If such is the case, we will reach a stack underflow
condition.

When a element is added to a stack, the operation is performed by push().

When an element is taken off from the stack, the operation is performed by pop().

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Source code for stack operations, using array:

STACK: Stack is a linear data structure which works under the principle of last in first out. Basic
operations: push, pop, display.

1. PUSH: if (top==MAX), display Stack overflow else reading the data and making stack [top]
=data and incrementing the top value by doing top++.

2. POP: if (top==0), display Stack underflow else printing the element at the top of the stack and
decrementing the top value by doing the top.

3. DISPLAY: IF (TOP==0), display Stack is empty else printing the elements in the stack from
stack [0] to stack [top].

# Python program for implementation of stack

# import maxsize from sys module


# Used to return -infinite when stack is empty from sys import maxsize

# Function to create a stack. It initializes size of stack as 0


def createStack():
stack = []
return stack

# Stack is empty when stack size is 0


def isEmpty(stack):
return len(stack) == 0

# Function to add an item to stack. It increases size by 1


def push(stack, item):
stack.append(item)
print("pushed to stack " + item)

# Function to remove an item from stack. It decreases size by 1


def pop(stack):
if (isEmpty(stack)):
print("stack empty")

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

return str(-maxsize -1) #return minus infinite

return stack.pop()

# Driver program to test above functions


stack = createStack() print("maximum
size of array is",maxsize) push(stack,
str(10))
push(stack, str(20))
push(stack, str(30))
print(pop(stack) + " popped from stack")
print(pop(stack) + " popped from stack")
print(pop(stack) + " popped from stack")
print(pop(stack) + " popped from stack")
push(stack, str(10))
push(stack, str(20))
push(stack, str(30))
print(pop(stack) + " popped from stack")

Linked List Implementation of Stack:


We can represent a stack as a linked list. In a stack push and pop operations are performed at one end
called top. We can perform similar operations at one end of list using top pointer.

Source code for stack operations, using linked list:

# Python program for linked list implementation of stack

# Class to represent a node


class StackNode:

# Constructor to initialize a node


def __init__(self, data):
self.data = data

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

self.next = None

class Stack:

# Constructor to initialize the root of linked list


def __init__(self):
self.root = None

def isEmpty(self):
return True if self.root is None else False

def push(self, data):


newNode = StackNode(data)
newNode.next = self.root
self.root = newNode
print ("%d pushed to stack" %(data))

def pop(self):
if (self.isEmpty()):
return float("-inf")
temp = self.root
self.root = self.root.next
popped = temp.data
return popped

def peek(self):
if self.isEmpty():
return float("-inf")
return self.root.data

# Driver program to test above class


stack = Stack()
stack.push(10)
stack.push(20)
stack.push(30)

print ("%d popped from stack" %(stack.pop()))


print ("Top element is %d " %(stack.peek()))
Stack Applications:
1. Stack is used by compilers to check for balancing of parentheses, brackets and braces.

2. Stack is used to evaluate a postfix expression.

3. Stack is used to convert an infix expression into postfix/prefix form.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

4. In recursion, all intermediate arguments and return values are stored on the processor‟s stack.

5. During a function call the return address and arguments are pushed onto a stack and on return
they are popped off.

6. Depth first search uses a stack data structure to find an element from a graph.

In-fix- to Postfix Transformation:

Procedure:

Procedure to convert from infix expression to postfix expression is as follows:

1. Scan the infix expression from left to right.

2. a)If the scanned symbol is left parenthesis, push it onto the stack.

b) If the scanned symbol is an operand, then place directly in the postfix expression
(output).

c) If the symbol scanned is a right parenthesis, then go on popping all the items from
the stack and place them in the postfix expression till we get the matching left
parenthesis.

d) If the scanned symbol is an operator, then go on removing all the operators from the
stack and place them in the postfix expression, if and only if the precedence of the
operator which is on the top of the stack is greater than (or equal) to the precedence
of the scanned operator and push the scanned operator onto the stack otherwise,
push the scanned operator onto the stack.

Convert the following infix expression A + B * C – D / E * H into its equivalent postfix expression.

Symbol Postfix string Stack Remarks

A A

+ A +

B AB +

* AB +*

C ABC -

- ABC*+ -

D ABC*+D -

/ ABC*+D -/

E ABC*+DE -/

* ABC*+DE/ -*

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

H ABC*+DE/H -*

End of The input is now empty. Pop the output symbols from the
string ABC*+DE/H*- stack until it is empty.

Source Code:
# Python program to convert infix expression to postfix

# Class to convert the expression


import string
class Conversion:

# Constructor to initialize the class variables


def __init__(self, capacity):
self.top = -1
self.capacity = capacity
# This array is used a
stack self.array = []
# Precedence setting
self.output = []
self.precedence = {'+':1, '-':1, '*':2, '/':2, '^':3}

# check if the stack is empty


def isEmpty(self):
return True if self.top == -1 else False

# Return the value of the top of the stack


def peek(self):
return self.array[-1]

# Pop the element from the stack


def pop(self):
if not self.isEmpty():
self.top -= 1
return self.array.pop()
else:
return "$"

# Push the element to the stack


def push(self, op):
self.top += 1
self.array.append(op)

# A utility function to check is the given character


# is operand
def isOperand(self, ch):
return ch.isalpha()

# Check if the precedence of operator is strictly


# less than top of stack or not

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

def notGreater(self, i):


try:
a = self.precedence[i]
b = self.precedence[self.peek()]
return True if a <= b else False
except KeyError:
return False

# The main function that converts given infix expression


# to postfix expression
def infixToPostfix(self, exp):

# Iterate over the expression for


conversion for i in exp:
# If the character is an operand,
# add it to output
if self.isOperand(i):
self.output.append(i)

# If the character is an '(', push it to


stack elif i == '(':
self.push(i)

# If the scanned character is an ')', pop and


# output from the stack until and '(' is
found elif i == ')':
while( (not self.isEmpty()) and self.peek() !=
'('): a = self.pop()
self.output.append(a)
if (not self.isEmpty() and self.peek() !=
'('): return -1
else:
self.pop()

# An operator is encountered
else:
while(not self.isEmpty() and self.notGreater(i)):
self.output.append(self.pop())
self.push(i)

# pop all the operator from the


stack while not self.isEmpty():
self.output.append(self.pop())

result= "".join(self.output)
print(result)
# Driver program to test above function
exp = "a+b*(c^d-e)^(f+g*h)-i"
obj = Conversion(len(exp))
obj.infixToPostfix(exp)

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Evaluating Arithmetic Expressions:

Procedure:

The postfix expression is evaluated easily by the use of a stack. When a number is seen, it is pushed onto
the stack; when an operator is seen, the operator is applied to the two numbers that are popped from the
stack and the result is pushed onto the stack.

Evaluate the postfix expression: 6 5 2 3 + 8 * + 3 + *

Symbol Operand 1 Operand 2 Value Stack Remarks

6 6

5 6, 5

2 6, 5, 2

The first four symbols are


3 6, 5, 2, 3
placed on the stack.

Next a „+‟ is read, so 3 and 2


+ 2 3 5 6, 5, 5 are popped from the stack and
their sum 5, is pushed

8 2 3 5 6, 5, 5, 8 Next 8 is pushed

Now a „*‟ is seen, so 8 and 5


* 5 8 40 6, 5, 40 are popped as 8 * 5 = 40 is
pushed

Next, a „+‟ is seen, so 40 and


+ 5 40 45 6, 45 5 are popped and 40 + 5 = 45
is pushed

3 5 40 45 6, 45, 3 Now, 3 is pushed

Next, „+‟ pops 3 and 45 and


+ 45 3 48 6, 48
pushes 45 + 3 = 48 is pushed

Finally, a „*‟ is seen and 48


* 6 48 288 288 and 6 are popped, the result 6
* 48 = 288 is pushed

Source Code:

# Python program to evaluate value of a postfix expression

# Class to convert the expression


class Evaluate:

# Constructor to initialize the class variables


def __init__(self, capacity):
self.top = -1

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

self.capacity = capacity
# This array is used a
stack self.array = []

# check if the stack is empty


def isEmpty(self):
return True if self.top == -1 else False

# Return the value of the top of the stack


def peek(self):
return self.array[-1]

# Pop the element from the stack


def pop(self):
if not self.isEmpty():
self.top -= 1
return self.array.pop()
else:
return "$"

# Push the element to the stack


def push(self, op):
self.top += 1
self.array.append(op)

# The main function that converts given infix expression


# to postfix expression
def evaluatePostfix(self, exp):

# Iterate over the expression for


conversion for i in exp:

# If the scanned character is an operand


# (number here) push it to the stack
if i.isdigit():
self.push(i)

# If the scanned character is an operator,


# pop two elements from stack and apply
it. else:
val1 = self.pop() val2 = self.pop()
self.push(str(eval(val2 + i +
val1)))

return int(self.pop())

# Driver program to test above function


exp = "231*+9-"
obj = Evaluate(len(exp))
print ("Value of {0} is {1}".format(exp, obj.evaluatePostfix(exp)))

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Queue Operations:
A queue is a data structure that is best described as "first in, first out". A queue is another special kind of
list, where items are inserted at one end called the rear and deleted at the other end called the front. A
real world example of a queue is people waiting in line at the bank. As each person enters the bank, he or
she is "enqueued" at the back of the line. When a teller becomes available, they are "dequeued" at the
front of the line.

Representation of a Queue using Array:

Let us consider a queue, which can hold maximum of five elements. Initially the queue is empty.

0 1 2 3 4

Q u e u e E mp t y
F RO NT = RE A R = 0

F R

Now, insert 11 to the queue. Then queue status will be:

0 1 2 3 4

11
REA R = REA R + 1 = 1
F RO NT = 0

F R

Next, insert 22 to the queue. Then the queue status is:

0 1 2 3 4

11 22

RE A R = RE A R + 1 = 2
F RO NT = 0
F R

Again insert another element 33 to the queue. The status of the queue is:

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

0 1 2 3 4
RE A R = RE A R + 1 = 3
11 22 33
F RO NT = 0

F R

Now, delete an element. The element deleted is the element at the front of the queue. So the status of the
queue is:

0 1 2 3 4
RE A R = 3
22 33
F RO NT = F R O NT + 1 = 1

F R

Again, delete an element. The element to be deleted is always pointed to by the FRONT pointer. So, 22
is deleted. The queue status is as follows:

0 1 2 3 4
RE A R = 3
33
F RO NT = F R O NT + 1 = 2

F R

Now, insert new elements 44 and 55 into the queue. The queue status is:

0 1 2 3 4
RE A R = 5
33 44 55
F RO NT = 2

F R

Next insert another element, say 66 to the queue. We cannot insert 66 to the queue as the rear crossed the
maximum size of the queue (i.e., 5). There will be queue full signal. The queue status is as follows:

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

0 1 2 3 4
RE A R = 5
33 44 55
F RO NT = 2

F R

Now it is not possible to insert an element 66 even though there are two vacant positions in the linear
queue. To over come this problem the elements of the queue are to be shifted towards the beginning of
the queue so that it creates vacant position at the rear end. Then the FRONT and REAR are to be
adjusted properly. The element 66 can be inserted at the rear end. After this operation, the queue status is
as follows:

0 1 2 3 4
RE A R = 4
33 44 55 66
F RO NT = 0

F R

This difficulty can overcome if we treat queue position with index 0 as a position that comes after
position with index 4 i.e., we treat the queue as a circular queue.

Procedure for Queue operations using array:

In order to create a queue we require a one dimensional array Q(1:n) and two variables front and rear.
The conventions we shall adopt for these two variables are that front is always 1 less than the actual
front of the queue and rear always points to the last element in the queue. Thus, front = rear if and only if
there are no elements in the queue. The initial condition then is front = rear = 0.

The various queue operations to perform creation, deletion and display the elements in a queue are as
follows:

1. insertQ(): inserts an element at the end of queue Q.

2. deleteQ(): deletes the first element of Q.

3. displayQ(): displays the elements in the queue.

Linked List Implementation of Queue: We can represent a queue as a linked list. In a queue data is
deleted from the front end and inserted at the rear end. We can perform similar operations on the two
ends of a list. We use two pointers front and rear for our linked queue implementation.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Source Code:

front = 0

rear = 0

mymax = 3

# Function to create a stack. It initializes size of stack as

0 def createQueue():

queue = []

return queue

# Stack is empty when stack size is 0

def isEmpty(queue):

return len(queue) == 0

# Function to add an item to stack. It increases size by

1 def enqueue(queue,item):

queue.append(item)

# Function to remove an item from stack. It decreases size by

1 def dequeue(queue):

if (isEmpty(queue)): return

"Queue is empty"

item=queue[0]

del queue[0]

return item

# Driver program to test above


functions queue = createQueue()

while True: print("1

Enqueue") print("2

Dequeue")

print("3 Display")

print("4 Quit")

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

ch=int(input("Enter choice"))

if(ch==1):

if(rear < mymax):

item=input("enter item")

enqueue(queue, item)

rear = rear + 1

else:

print("Queue is full")

elif(ch==2):

print(dequeue(queue))

elif(ch==3):

print(queue)

else:

break

Applications of Queues:

1. It is used to schedule the jobs to be processed by the CPU.

2. When multiple users send print jobs to a printer, each printing job is kept in the printing queue.
Then the printer prints those jobs according to first in first out (FIFO) basis.

3. Breadth first search uses a queue data structure to find an element from a graph.

Disadvantages of Linear Queue:


There are two problems associated with linear queue. They are:

 Time consuming: linear time to be spent in shifting the elements to the beginning of the queue.

 Signaling queue full: even if the queue is having vacant position.

Round Robin Algorithm:

The round-robin (RR) scheduling algorithm is designed especially for time-sharing systems. It is similar
to FCFS scheduling, but pre-emption is added to switch between processes. A small unit of time, called
a time quantum or time slices, is defined. A time quantum is generally from 10 to 100 milliseconds. The
ready queue is treated as a circular queue. To implement RR scheduling

 We keep the ready queue as a FIFO queue of processes.



 New processes are added to the tail of the ready queue.

 The CPU scheduler picks the first process from the ready queue, sets a timer to interrupt after 1
time quantum, and dispatches the process.

 The process may have a CPU burst of less than 1 time quantum.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

o In this case, the process itself will release the CPU voluntarily.
o The scheduler will then proceed to the next process in the ready queue.

 Otherwise, if the CPU burst of the currently running process is longer than 1 time quantum,

o The timer will go off and will cause an interrupt to the OS.

o A context switch will be executed, and the process will be put at the tail of the ready
queue.
o The CPU scheduler will then select the next process in the ready queue.

The average waiting time under the RR policy is often long. Consider the following set of processes that
arrive at time 0, with the length of the CPU burst given in milliseconds: (a time quantum of 4
milliseconds)

Burst Waiting Turnaround

Process Time Time Time

24 6 30

3 4 7

3 7 10

Average - 5.66 15.66

Using round-robin scheduling, we would schedule these processes according to the following chart:

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

DEQUE(Double Ended Queue):

A double-ended queue (dequeue, often abbreviated to deque, pronounced deck) generalizes a queue,
for which elements can be added to or removed from either the front (head) or back (tail).It is also often
called a head-tail linked list. Like an ordinary queue, a double-ended queue is a data structure it
supports the following operations: enq_front, enq_back, deq_front, deq_back, and empty. Dequeue can
be behave like a queue by using only enq_front and deq_front , and behaves like a stack by using only
enq_front and deq_rear.

The DeQueue is represented as follows.

DEQUE can be represented in two ways they are

1) Input restricted DEQUE(IRD)

2) output restricted DEQUE(ORD)

The output restricted DEQUE allows deletions from only one end and input restricted DEQUE allow
insertions at only one end. The DEQUE can be constructed in two ways they are

1) Using array

2)Using linked list

Operations in DEQUE

1. Insert element at back

2. Insert element at front

3. Remove element at front

4. Remove element at back

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Applications of DEQUE:

1. The A-Steal algorithm implements task scheduling for several processors (multiprocessor
scheduling).

2. The processor gets the first element from the deque.

3. When one of the processor completes execution of its own threads it can steal a thread from
another processor.

4. It gets the last element from the deque of another processor and executes it.

Circular Queue:

Circular queue is a linear data structure. It follows FIFO principle. In circular queue the last node is
connected back to the first node to make a circle.

 Circular linked list fallow the First In First Out principle



 Elements are added at the rear end and the elements are deleted at front end of the queue

 Both the front and the rear pointers points to the beginning of the array.

 It is also called as ―Ring buffer‖.

 Items can inserted and deleted from a queue in O(1) time.

1. Using single linked list

2. Using double linked list

3. Using arrays

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Representation of Circular Queue:

Let us consider a circular queue, which can hold maximum (MAX) of six elements. Initially the queue is
empty.

F R

5 0

1 Q u e u e E mp t y
4 MAX = 6
F RO NT = RE A R = 0
C O U NT = 0

2
3
C irc u lar Q u e u e

Now, insert 11 to the circular queue. Then circular queue status will be:

5 0
R
11

1 F RO NT = 0
4 RE A R = ( RE A R + 1) % 6 = 1
C O U NT = 1

2
3

C irc u lar Q u e u e

Insert new elements 22, 33, 44 and 55 into the circular queue. The circular queue status is:

F
R

0
5
11

22 1 F RO NT = 0, RE A R = 5
4 55 RE A R = RE A R % 6 = 5
C O U NT = 5

44 33
2
3

C irc u lar Q u e u e

Now, delete an element. The element deleted is the element at the front of the circular queue. So, 11 is
deleted. The circular queue status is as follows:

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

R
0
5
F

22 1 F RO NT = (F R O NT + 1) % 6 = 1 RE A R
4 55 =5
C O U NT = C O U NT - 1 = 4

44 33
2
3

C irc u lar Q u e u e

Again, delete an element. The element to be deleted is always pointed to by the FRONT pointer. So, 22
is deleted. The circular queue status is as follows:

0
5

1 F RO NT = (F R O NT + 1) % 6 = 2
4 55 RE A R = 5
C O U NT = C O U NT - 1 = 3

44 33
F
3 2

C irc u lar Q u e u e

Again, insert another element 66 to the circular queue. The status of the circular queue is:

0
5
66

1
4 55 F RO NT = 2
RE A R = ( RE A R + 1) % 6 = 0
C O U NT = C O U NT + 1 = 4
44 33

3 2 F

C irc u lar Q u e u e

Now, insert new elements 77 and 88 into the circular queue. The circular queue status is:

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

0
5
66 77

88 1
4 55 F RO NT = 2, RE A R = 2
RE A R = RE A R % 6 = 2
C O U NT = 6
44 33
R
3 2 F
C irc u lar Q u e u e

Now, if we insert an element to the circular queue, as COUNT = MAX we cannot add the element to
circular queue. So, the circular queue is full.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

LINKED LISTS
Linked lists and arrays are similar since they both store collections of data. Array is the most common
data structure used to store collections of elements. Arrays are convenient to declare and provide the easy
syntax to access any element by its index number. Once the array is set up, access to any element is
convenient and fast.
The disadvantages of arrays are:
• The size of the array is fixed. Most often this size is specified at compile time. This makes the
programmers to allocate arrays, which seems "large enough" than required.
• Inserting new elements at the front is potentially expensive because existing elements need to be
shifted over to make room.
• Deleting an element from an array is not possible. Linked lists have their own strengths and
weaknesses, but they happen to be strong where arrays are weak.
 Generally array's allocates the memory for all its elements in one block whereas linked lists use
an entirely different strategy. Linked lists allocate memory for each element separately and only
when necessary.
Linked List Concepts:
A linked list is a non-sequential collection of data items. It is a dynamic data structure. For every data
item in a linked list, there is an associated pointer that would give the memory location of the next data
item in the linked list. The data items in the linked list are not in consecutive memory locations. They
may be anywhere, but the accessing of these data items is easier as each data item contains the address of
the next data item.
Advantages of linked lists:
Linked lists have many advantages. Some of the very important advantages are:
1. Linked lists are dynamic data structures. i.e., they can grow or shrink during the execution of a
program.
2. Linked lists have efficient memory utilization. Here, memory is not preallocated. Memory is
allocated whenever it is required and it is de-allocated (removed) when it is no longer needed.
3. Insertion and Deletions are easier and efficient. Linked lists provide flexibility in inserting a data
item at a specified position and deletion of the data item from the given position.
4. Many complex applications can be easily carried out with linked lists.

Disadvantages of linked lists:


1. It consumes more space because every node requires a additional pointer to store address of the
next node.
2. Searching a particular element in list is difficult and also time consuming.
Types of Linked Lists:
Basically we can put linked lists into the following four items:
1. Single Linked List.
2. Double Linked List.
3. Circular Linked List.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

4. Circular Double Linked List.


A single linked list is one in which all nodes are linked together in some sequential manner. Hence, it is
also called as linear linked list.
A double linked list is one in which all nodes are linked together by multiple links which helps in
accessing both the successor node (next node) and predecessor node (previous node) from any arbitrary
node within the list. Therefore each node in a double linked list has two link fields (pointers) to point to
the left node (previous) and the right node (next). This helps to traverse in forward direction and
backward direction.
A circular linked list is one, which has no beginning and no end. A single linked list can be made a
circular linked list by simply storing address of the very first node in the link field of the last node.
A circular double linked list is one, which has both the successor pointer and predecessor pointer in the
circular manner.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Applications of linked list:


1. Linked lists are used to represent and manipulate polynomial. Polynomials are expression containing
terms with non zero coefficient and exponents. For example: P(x) = a0 Xn + a1 Xn-1 + …… + an-1
X + an
2. Represent very large numbers and operations of the large number such as addition, multiplication and
division.
3. Linked lists are to implement stack, queue, trees and graphs. 4. Implement the symbol table in
compiler construction.
Single Linked List:
A linked list allocates space for each element separately in its own block of memory called a "node". The
list gets an overall structure by using pointers to connect all its nodes together like the links in a chain.
Each node contains two fields; a "data" field to store whatever element, and a "next" field which is a
pointer used to link to the next node. Each node is allocated in the heap using malloc(), so the node
memory continues to exist until it is explicitly de-allocated using free(). The front of the list is a pointer to
the ―start‖ node.

A single linked list


The beginning of the linked list is stored in a "start" pointer which points to the first node. The first node
contains a pointer to the second node. The second node contains a pointer to the third node, ... and so on.
The last node in the list has its next field set to NULL to mark the end of the list. Code can access any
node in the list by starting at the start and following the next pointers.
The start pointer is an ordinary local pointer variable, so it is drawn separately on the left top to show that
it is in the stack. The list nodes are drawn on the right to show that they are allocated in the heap.
The basic operations in a single linked list are:
• Creation.
• Insertion.
• Deletion.
• Traversing.
Creating a node for Single Linked List:
Creating a singly linked list starts with creating a node. Sufficient memory has to be allocated for creating
a node. The information is stored in the memory.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Insertion of a Node:
One of the most primitive operations that can be done in a singly linked list is the insertion of a node.
Memory is to be allocated for the new node (in a similar way that is done while creating a list) before
reading the data. The new node will contain empty data field and empty next field. The data field of the
new node is then stored with the information read from the user. The next field of the new node is
assigned to NULL. The new node can then be inserted at three different places namely:
• Inserting a node at the beginning.
• Inserting a node at the end.
• Inserting a node at intermediate position.

 Inserting a node at the beginning.

 Inserting a node at the end:

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

 Inserting a node into the single linked list at a specified intermediate position other than
beginning and end.

Deletion of a node:
Another primitive operation that can be done in a singly linked list is the deletion of a node. Memory is
to be released for the node to be deleted. A node can be deleted from the list from three different places
namely.
• Deleting a node at the beginning.
• Deleting a node at the end.
• Deleting a node at intermediate position.
Deleting a node at the beginning:

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Deleting a node at the end:

Deleting a node at Intermediate position:


The following steps are followed, to delete a node from an intermediate position in the list (List must
contain more than two node).

Traversal and displaying a list (Left to Right):


To display the information, you have to traverse (move) a linked list, node by node from the first node,
until the end of the list is reached.
Traversing a list involves the following steps:
• Assign the address of start pointer to a temp pointer.
• Display the information from the data field of each node. The function traverse () is used for traversing
and displaying the information stored in the list from left to right.
Source Code for creating and inserting the Implementation of Single Linked List:
class Item:
'''An Item that stores the data of a Linked List'''
def __init__(self, data):
'''Initializes the data of the Item'''
self._content = data # non-public data
self.next = None

class SingleLikedList:
'''Single Linked List Implementation'''
def __init__(self):
self._start = None

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

self._count = 0

def getItemAtIndex(self, pos):


if self._start == None:
return None
i=0
cursor = self._start
while cursor != None:
if i == pos:
return cursor
i += 1
cursor = cursor.next

return None

def insert(self, data, pos = 0):


item = Item(data)

if self._start == None:
self._start = item
else:
cursor = self.getItemAtIndex(pos)
item.next = cursor.next
item.next = cursor.next
cursor.next = item

self._count += 1
def display(self):
cursor = self._start
while cursor != None:
print(cursor._content, end=' ')
cursor = cursor.next
l = SingleLikedList()
l.insert(10)
l.insert(20)

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

l.insert(30)
l.insert(40)
l.insert(50, 3)
l.display()

Source Code for creating , inserting ,deleting the Implementation of Single Linked List:

class Node(object):
def __init__(self, data=None, next_node=None):
self.data = data
self.next_node = next_node
def get_data(self):
return self.data
def get_next(self):
return self.next_node
def set_next(self, new_next):
self.next_node = new_next

class LinkedList(object):
def __init__(self, head=None):
self.head = head
def insert(self, data):
new_node = Node(data)
new_node.set_next(self.head)
self.head = new_node
def size(self):
current = self.head
count = 0
while current:
count += 1
current = current.get_next()
return count
def search(self, data):
current = self.head
found = False

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

while current and found is False:


if current.get_data() == data:
found = True
else:
current = current.get_next()
if current is None:
raise ValueError("Data not in list")
return current
def delete(self, data):
current = self.head
previous = None
found = False
while current and found is False:
if current.get_data() == data:
found = True
else:
previous = current
current = current.get_next()
if current is None:
raise ValueError("Data not in list")
if previous is None:
self.head = current.get_next()
else:
previous.set_next(current.get_next())

Source Code for creating , inserting ,deleting the Implementation of Single Linked List:
import sys
import os.path
sys.path.append(os.path.join(os.path.abspath(os.pardir), "/home/satya/PycharmProjects/DataStractures"))
from LinkedList2 import LinkedList
import unittest
class TestLinkedList(unittest.TestCase):
def setUp(self):
self.list = LinkedList()
def tearDown(self):

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

self.list = None
def test_insert(self):
self.list.insert("David")
self.assertTrue(self.list.head.get_data() == "David")
self.assertTrue(self.list.head.get_next() is None)
def test_insert_two(self):
self.list.insert("David")
self.list.insert("Thomas")
self.assertTrue(self.list.head.get_data() == "Thomas")
head_next = self.list.head.get_next()
self.assertTrue(head_next.get_data() == "David")
def test_nextNode(self):
self.list.insert("Jacob")
self.list.insert("Pallymay")
self.list.insert("Rasmus")
self.assertTrue(self.list.head.get_data() == "Rasmus")
head_next = self.list.head.get_next()
self.assertTrue(head_next.get_data() == "Pallymay")
last = head_next.get_next()
self.assertTrue(last.get_data() == "Jacob")
def test_positive_search(self):
self.list.insert("Jacob")
self.list.insert("Pallymay")
self.list.insert("Rasmus")
found = self.list.search("Jacob")
self.assertTrue(found.get_data() == "Jacob")
found = self.list.search("Pallymay")
self.assertTrue(found.get_data() == "Pallymay")
found = self.list.search("Jacob")
self.assertTrue(found.get_data() == "Jacob")
def test_searchNone(self):
self.list.insert("Jacob")
self.list.insert("Pallymay")
# make sure reg search works
found = self.list.search("Jacob")

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

self.assertTrue(found.get_data() == "Jacob")
with self.assertRaises(ValueError):
self.list.search("Vincent")
def test_delete(self):
self.list.insert("Jacob")
self.list.insert("Pallymay")
self.list.insert("Rasmus")
# Delete the list head self.list.delete("Rasmus")
self.assertTrue(self.list.head.get_data() ==
"Pallymay")
# Delete the list tail
self.list.delete("Jacob")
self.assertTrue(self.list.head.get_next() is None)
def test_delete_value_not_in_list(self):
self.list.insert("Jacob")
self.list.insert("Pallymay")
self.list.insert("Rasmus")
with self.assertRaises(ValueError):
self.list.delete("Sunny")
def test_delete_empty_list(self):
with self.assertRaises(ValueError):
self.list.delete("Sunny")
def test_delete_next_reassignment(self):
self.list.insert("Jacob")
self.list.insert("Cid")
self.list.insert("Pallymay")
self.list.insert("Rasmus")
self.list.delete("Pallymay")
self.list.delete("Cid")
self.assertTrue(self.list.head.next_node.get_data() == "Jacob")
Source Code for creating , inserting ,deleting the Implementation of Single Linked List:

class Node(object):
def __init__(self, data, next):
self.data = data

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

self.next = next
class SingleList(object):
head = None
tail = None
def show(self):
print "Showing list data:"
current_node = self.head
while current_node is not None:
print current_node.data, " -> ",
current_node = current_node.next
print None
def append(self, data):
node = Node(data, None)
if self.head is None:
self.head = self.tail = node
else:
self.tail.next = node
self.tail = node
def remove(self, node_value):
current_node = self.head
previous_node = None
while current_node is not None:
if current_node.data == node_value:
# if this is the first node (head)
if previous_node is not None:
previous_node.next = current_node.next
else:
self.head = current_node.next

# needed for the next iteration


previous_node = current_node
current_node = current_node.next
s = SingleList()
s.append(31)
s.append(2)

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

s.append(3)
s.append(4)
s.show()
s.remove(31)
s.remove(3)
s.remove(2)
s.show()

Using a header node:


A header node is a special dummy node found at the front of the list. The use of header node is an
alternative to remove the first node in a list. For example, the picture below shows how the list with data
10, 20 and 30 would be represented using a linked list without and with a header node:

Note that if your linked lists do include a header node, there is no need for the special case code given
above for the remove operation; node n can never be the first node in the list, so there is no need to check
for that case. Similarly, having a header node can simplify the code that adds a node before a given node
n.
Note that if you do decide to use a header node, you must remember to initialize an empty list to contain
one (dummy) node, you must remember not to include the header node in the count of "real" nodes in the
list.
It is also useful when information other than that found in each node of the list is needed. For example,
imagine an application in which the number of items in a list is often calculated. In a standard linked list,
the list function to count the number of nodes has to traverse the entire list every time. However, if the
current length is maintained in a header node, that information can be obtained very quickly. 3.5. Array
based linked lists: Another alternative is to allocate the nodes in blocks. In fact, if you know the

maximum size of a list a head of time, you can pre-allocate the nodes in a single array. The result is a
hybrid structure – an array based linked list.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

shows an example of null terminated single linked list where all the nodes are allocated contiguously in
an array.

Double Linked List:


A double linked list is a two-way list in which all nodes will have two links. This helps in accessing both
successor node and predecessor node from the given node position. It provides bi-directional traversing.
Each node contains three fields:
 Left link.
 Data.
 Right link.
The left link points to the predecessor node and the right link points to the successor node. The data field
stores the required data.
Many applications require searching forward and backward thru nodes of a list. For example searching
for a name in a telephone directory would need forward and backward scanning thru a region of the whole
list.
The basic operations in a double linked list are:
 Creation.
 Insertion.
 Deletion.
 Traversing.

A double linked list is shown in figure

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

The beginning of the double linked list is stored in a "start" pointer which points to the first node. The
first node‟s left link and last node‟s right link is set to NULL.
Creating a node for Double Linked List:
Creating a double linked list starts with creating a node. Sufficient memory has to be allocated for
creating a node. The information is stored in the memory.
Double Linked List with 3 nodes:

Inserting a node at the beginning:

Inserting a node at the end:

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Inserting a node at an intermediate position:

Deleting a node at the beginning:

Deleting a node at the end:

Traversal and displaying a list (Left to Right):


To display the information, you have to traverse the list, node by node from the first node, until the end
of the list is reached. The function traverse_left_right() is used for traversing and displaying the
information stored in the list from left to right.
Traversal and displaying a list (Right to Left):
To display the information from right to left, you have to traverse the list, node by node from the first
node, until the end of the list is reached. The function traverse_right_left() is used for traversing and
displaying the information stored in the list from right to left.

1.Source Code for the Implementation of Double Linked List:


class DList:
def __init__(self):
self.head = None
self.size = 0
def insert(self, data):
self.size += 1

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

if self.head is None:
self.head = Node(data)
else:
p = Node(data)
p.next = self.head
self.head.previous = p
self.head = p
def remove(self, index):
if self.head is None:
raise ValueError('Removing off an empty list')
if index < 0 or index >= self.size:
raise IndexError("Index is either negative or greater than the list size.")current = self.head
if index == 0:
self.head = self.head.next
self.head.previous = None
else:
for _ in range(index -1):
current = current.next
p = current.next.next
if p is None:
current.next = None
else:
current.next = p
p.previous = current
def __sizeof__(self):
return self.size
def __repr__(self):
res = '[ '
current = self.head
while current is not None:
res += str(current.data)
res += ' '
current = current.next
res += ']'
return res
class Node:
def __init__(self, data):

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

if data is None:
raise ValueError('Node value cannot be None')
self.data = data
self.previous = None
self.next = None

Source Code for the Implementation of Double Linked List:


class Node(object):
def __init__(self, data, prev, next):
self.data = data
self.prev = prev
self.next = next

class DoubleList(object):
head = None
tail = None
def append(self, data):
new_node = Node(data, None, None)
if self.head is None:
self.head = self.tail = new_node
else:
new_node.prev = self.tail
new_node.next = None
self.tail.next = new_node
self.tail = new_node
def remove(self, node_value):
current_node = self.head

while current_node is not None:


if current_node.data == node_value:
# if it's not the first element
if current_node.prev is not None:
current_node.prev.next = current_node.next
current_node.next.prev = current_node.prev
else:

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

# otherwise we have no prev (it's None), head is the next one, and prev becomes
None self.head = current_node.next
current_node.next.prev = None

current_node = current_node.next

def show(self):
print "Show list data:"
current_node = self.head
while current_node is not None:
print current_node.prev.data if hasattr(current_node.prev, "data") else

None, print current_node.data,


print current_node.next.data if hasattr(current_node.next, "data") else None

current_node = current_node.next
print "*"*50
d = DoubleList()
d.append(5)
d.append(6)
d.append(50)
d.append(30)
d.show()
d.remove(50)
d.remove(5)
d.show()

Polynomials:
A polynomial is of the form: i n i ∑ ci Where, ci is the coefficient of the ith term and n is the degree of
the polynomial
Some examples are:
5x2 + 3x + 1
12x3 – 4x
5x4 – 8x3 + 2x2 + 4x1 + 9x0

It is not necessary to write terms of the polynomials in decreasing order of degree. In other words the two
polynomials 1 + x and x + 1 are equivalent.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

The computer implementation requires implementing polynomials as a list of pairs of coefficient and
exponent. Each of these pairs will constitute a structure, so a polynomial will be represented as a list of
structures.

A linked list structure that represents polynomials 5x4 – 8x3 + 2x2 + 4x1 + 9x0

Addition of Polynomials:
To add two polynomials we need to scan them once. If we find terms with the same exponent in the two
polynomials, then we add the coefficients; otherwise, we copy the term of larger exponent into the sum
and go on. When we reach at the end of one of the polynomial, then remaining part of the other is copied
into the sum.
To add two polynomials follow the following steps:
• Read two polynomials
• Add them.
• Display the resultant polynomial.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Unit-V
Trees and Graphs
Trees Basic Concepts:

A tree is a non-empty set one element of which is designated the root of the tree while the remaining
elements are partitioned into non-empty sets each of which is a sub-tree of the root.

A tree T is a set of nodes storing elements such that the nodes have a parent-child relationship that
satisfies the following

• If T is not empty, T has a special tree called the root that has no parent.

• Each node v of T different than the root has a unique parent node w; each node with parent w is a
child of w.

Tree nodes have many useful properties. The depth of a node is the length of the path (or the number of
edges) from the root to that node. The height of a node is the longest path from that node to its leaves.
The height of a tree is the height of the root. A leaf node has no children -- its only path is up to its
parent.

Binary Tree:

In a binary tree, each node can have at most two children. A binary tree node called the root together with two
binary trees called the left subtree and the right subtree.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Tree Terminology:

Leaf node

A node with no children is called a leaf (or external node). A node which is not a leaf is called an internal
node.

Path: A sequence of nodes n1, n2, . . ., nk, such that ni is the parent of ni + 1 for i = 1, 2,. . ., k - 1. The
length of a path is 1 less than the number of nodes on the path. Thus there is a path of length zero from a
node to itself.

Siblings: The children of the same parent are called siblings.

Ancestor and Descendent If there is a path from node A to node B, then A is called an ancestor of B
and B is called a descendent of A.

Subtree: Any node of a tree, with all of its descendants is a subtree.

Level: The level of the node refers to its distance from the root. The root of the tree has level O, and the
level of any other node in the tree is one more than the level of its parent.
n
The maximum number of nodes at any level is 2 .

Height:The maximum level in a tree determines its height. The height of a node in a tree is the length of a
longest path from the node to a leaf. The term depth is also used to denote height of the tree.

Depth:The depth of a node is the number of nodes along the path from the root to that node.

Assigning level numbers and Numbering of nodes for a binary tree: The nodes of a binary tree can be
numbered in a natural way, level by level, left to right. The nodes of a complete binary tree can be
numbered so that the root is assigned the number 1, a left child is assigned twice the number assigned its
parent, and a right child is assigned one more than twice the number assigned its parent.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Properties of Binary Trees:

Some of the important properties of a binary tree are as follows:

1. If h = height of a binary tree, then


h
a. Maximum number of leaves = 2
h+1
b. Maximum number of nodes = 2 -1

2. If a binary tree contains m nodes at level l, it contains at most 2m nodes at level l + 1.


l
3. Since a binary tree can contain at most one node at level 0 (the root), it can contain at most 2
node at level l.

4. The total number of edges in a full binary tree with n node is n - 1.

Strictly Binary tree:

If every non-leaf node in a binary tree has nonempty left and right subtrees, the tree is termed a strictly
binary tree. Thus the tree of figure 7.2.3(a) is strictly binary. A strictly binary tree with n leaves
always contains 2n - 1 nodes.

Full Binary Tree:

A full binary tree of height h has all its leaves at level h. Alternatively; All non leaf nodes of a full binary
tree have two children, and the leaf nodes have no children.
h+1
A full binary tree with height h has 2 - 1 nodes. A full binary tree of height h is a strictly binary tree
all of whose leaves are at level h.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

3+1
For example, a full binary tree of height 3 contains 2 – 1 = 15 nodes.

Complete Binary Tree:

A binary tree with n nodes is said to be complete if it contains all the first n nodes of the above
numbering scheme.

A complete binary tree of height h looks like a full binary tree down to level h-1, and the level h is
filled from left to right.

Perfect Binary Tree:

A Binary tree is Perfect Binary Tree in which all internal nodes have two children and all leaves are at
same level.
Following are examples of Perfect Binary Trees.

18

/ \

15 30

/ \ / \

40 50 100 40

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

18

/ \

15 30

h
A Perfect Binary Tree of height h (where height is number of nodes on path from root to leaf) has 2 – 1
node.

Example of Perfect binary tree is ancestors in family. Keep a person at root, parents as children, parents
of parents as their children.

Tree Traversals:
Traversal of a binary tree means to visit each node in the tree exactly once. The tree traversal is used in all
t it.

In a linear list nodes are visited from first to last, but a tree being a non linear one we need definite rules.
Th ways to traverse a tree. All of them differ only in the order in which they visit the nodes.

The three main methods of traversing a tree are:


  
Inorder Traversal
  Preorder Traversal

 
Postorder Traversal

 

In all of them we do not require to do anything to traverse an empty tree. All the traversal methods arebase

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

functions since a binary tree is itself recursive as every child of a node in a binary tree is itself a binary
tree.

Inorder Traversal:

To traverse a non empty tree in inorder the following steps are followed recursively.

 Visit the Root


 Traverse the left subtree
 Traverse the right subtree

The inorder traversal of the tree shown below is as follows.

Preorder Traversal:

Algorithm Pre-order(tree)

1. Visit the root.


2. Traverse the left sub-tree, i.e., call Pre-order(left-sub-tree)
3. Traverse the right sub-tree, i.e., call Pre-order(right-sub-tree)

Post-order Traversal:
Algorithm Post-order(tree)

1. Traverse the left sub-tree, i.e., call Post-order(left-sub-tree)


2. Traverse the right sub-tree, i.e., call Post-order(right-sub-tree)
3. Visit the root.

# Python program for tree traversals

# A class that represents an individual node in a


# Binary Tree
class Node:
def __init__(self,key):
self.left = None
self.right = None
self.val = key

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

# A function to do inorder tree


traversal def printInorder(root):

if root:

# First recur on left child


printInorder(root.left)

# then print the data of


node print(root.val),

# now recur on right child


printInorder(root.right)

# A function to do postorder tree traversal


def printPostorder(root):

if root:

# First recur on left child


printPostorder(root.left)

# the recur on right child


printPostorder(root.right)

# now print the data of


node print(root.val),

# A function to do postorder tree traversal


def printPreorder(root):

if root:

# First print the data of


node print(root.val),

# Then recur on left child


printPreorder(root.left)

# Finally recur on right child


printPreorder(root.right)

# Driver code

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(4)
root.left.right = Node(5)
print "Preorder traversal of binary tree is"
printPreorder(root)

print "\nInorder traversal of binary tree is"


printInorder(root)

print "\nPostorder traversal of binary tree is"


printPostorder(root)

Time Complexity: O(n^2).

Binary Search Trees:


An important special kind of binary tree is the binary search tree (BST). In a BST, each node
stores some information including a unique key value, and perhaps some associated data. A
binary tree is a BST iff, for every node n in the tree:

 All keys in n's left subtree are less than the key in n, and
 All keys in n's right subtree are greater than the key in n.

In other words, binary search trees are binary trees in which all values in the node‘s left subtree are less
than node value all values in the node‘s right subtree are greater than node value.

Here are some BSTs in which each node just stores an integer key:

These are not BSTs:

In the left one 5 is not greater than 6. In the right one 6 is not greater than 7.

The reason binary-search trees are important is that the following operations can be
implemented efficiently using a BST:

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

 insert a key value


 determine whether a key value is in the tree
 remove a key value from the tree
 print all of the key values in sorted order

Let's illustrate what happens using the following BST:

and searching for 12:

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

What if we search for 15:

Properties and Operations:

A BST is a binary tree of nodes ordered in the following way:

1. Each node contains one key (also unique)


2. The keys in the left subtree are < (less) than the key in its parent node
3. The keys in the right subtree > (greater) than the key in its parent node
4. Duplicate node keys are not allowed.

Inserting a node

A naïve algorithm for inserting a node into a BST is that, we start from the root node, if the node to insert
is less than the root, we go to left child, and otherwise we go to the right child of the root. We continue
this process (each node is a root for some sub tree) until we find a null pointer (or leaf node) where we
cannot go any further. We then insert the node as a left or right child of the leaf node based on node is less
or greater than the leaf node. We note that a new node is always inserted as a leaf node. A recursive
algorithm for inserting a node into a BST is as follows. Assume we insert a node N to tree T. if the tree is
empty, the we return new node N as the tree. Otherwise, the problem of inserting is reduced to inserting
the node N to left of right sub trees of T, depending on N is less or greater than T. A definition is as
follows.

Insert(N, T) = N if T is empty
= insert(N, T.left) if N < T
= insert(N, T.right) if N > T

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Searching for a node


Searching for a node is similar to inserting a node. We start from root, and then go left or right until we
find (or not find the node). A recursive definition of search is as follows. If the node is equal to root, then
we return true. If the root is null, then we return false. Otherwise we recursively solve the problem for
T.left or T.right, depending on N < T or N > T. A recursive definition is as follows. Search should return
a true or false, depending on the node is found or not.
Search(N, T) = false if T is empty
= true if T = N
search(N, T.left) if N < T
= search(N, T.right) if N > T
Deleting a node

A BST is a connected structure. That is, all nodes in a tree are connected to some other node. For
example, each node has a parent, unless node is the root. Therefore deleting a node could affect all sub
trees of that node. For example, deleting node 5 from the tree could result in losing sub trees that are
rooted at 1 and 9.

Hence we need to be careful about deleting nodes from a tree. The best way to deal with deletion seems to
be considering special cases. What if the node to delete is a leaf node? What if the node is a node with
just one child? What if the node is an internal node (with two children). The latter case is the hardest to
resolve. But we will find a way to handle this situation as well.
Case 1 : The node to delete is a leaf node
This is a very easy case. Just delete the node 46. We are done

Case 2 : The node to delete is a node with one child.


This is also not too bad. If the node to be deleted is a left child of the parent, then we connect the left
pointer of the parent (of the deleted node) to the single child. Otherwise if the node to be deleted is a right
child of the parent, then we connect the right pointer of the parent (of the deleted node) to single child.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Case 3: The node to delete is a node with two children


This is a difficult case as we need to deal with two sub trees. But we find an easy way to handle it. First
we find a replacement node (from leaf node or nodes with one child) for the node to be deleted. We need
to do this while maintaining the BST order property. Then we swap leaf node or node with one child with
the node to be deleted (swap the data) and delete the leaf node or node with one child (case 1 or case 2)

Next problem is finding a replacement leaf node for the node to be deleted. We can easily find this as
follows. If the node to be deleted is N, the find the largest node in the left sub tree of N or the smallest
node in the right sub tree of N. These are two candidates that can replace the node to be deleted without
losing the order property. For example, consider the following tree and suppose we need to delete the root
38.

Then we find the largest node in the left sub tree (15) or smallest node in the right sub tree (45) and
replace the root with that node and then delete that node. The following set of images demonstrates this
process.

Let‘s see when we delete 13 from that tree.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Recursive Algorithms:

GCD Design: Given two integers a and b, the greatest common divisor is recursively found using the
formula

gcd(a,b) = a if b=0
Base case
b if a=0
gcd(b, a mod b) General case

Fibonacci Design: To start a fibonacci series, we need to know the first two numbers.

Fibonacci(n) = 0 if n=0 Base case


1 if n=1
General case
Fibonacci(n-1) + fibonacci(n-2)

Difference between Recursion and Iteration:

// A function is said to be recursive if it calls itself again and again within its body whereas iterative
functions are loop based imperative functions.

// Reursion uses stack whereas iteration does not use stack.

// Recursion uses more memory than iteration as its concept is based on stacks.

// Recursion is comparatively slower than iteration due to overhead condition of maintaining stacks.

// Recursion makes code smaller and iteration makes code longer.

// Iteration terminates when the loop-continuation condition fails whereas recursion terminates when
a base case is recognized.

// While using recursion multiple activation records are created on stack for each call where as in
iteration everything is done in one activation record.

// Infinite recursion can crash the system whereas infinite looping uses CPU cycles repeatedly.

// Recursion uses selection structure whereas iteration uses repetetion structure.

Types of Recursion:

Recursion is of two types depending on whether a function calls itself from within itself or whether two
functions call one another mutually. The former is called direct recursion and the later is called

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

indirect recursion. Thus there are two types of recursion:

 Direct Recursion

 Indirect Recursion

Recursion may be further categorized as:

 Linear Recursion

 Binary Recursion

 Multiple Recursion

Linear Recursion:

It is the most common type of Recursion in which function calls itself repeatedly until base condition
[termination case] is reached. Once the base case is reached the results are return to the caller function.
If a recursive function is called only once then it is called a linear recursion.

Binary Recursion:

Some recursive functions don't just have one call to themselves; they have two (or more). Functions
with two recursive calls are referred to as binary recursive functions.

Example1: The Fibonacci function fib provides a classic example of binary recursion. The Fibonacci
numbers can be defined by the rule:

fib(n) = 0 if n is 0,

// 1 if n is 1,

// fib(n-1) + fib(n-2) otherwise

For example, the first seven Fibonacci numbers are

Fib(0) = 0

Fib(1) = 1

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Fib(2) = Fib(1) + Fib(0) = 1

Fib(3) = Fib(2) + Fib(1) = 2

Fib(4) = Fib(3) + Fib(2) = 3

Fib(5) = Fib(4) + Fib(3) = 5

Fib(6) = Fib(5) + Fib(4) = 8

B Program to display the Fibonacci sequence up to n-th term where n is provided by the user

C change this value for a different result

nterms = 10

// uncomment to take input from the user

#nterms = int(input("How many terms? "))

// first two terms

n1 = 0

n2 = 1

count = 0

check if the number of terms is


valid if nterms <= 0:

print("Please enter a positive

integer") elif nterms == 1:

print("Fibonacci sequence

upto",nterms,":") print(n1)

else:

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

print("Fibonacci sequence upto",nterms,":")

while count < nterms:

print(n1,end=' , ')

nth = n1 + n2

update
values n1 = n2

n2 = nth

count += 1

Tail Recursion:

Tail recursion is a form of linear recursion. In tail recursion, the recursive call is the last thing the
function does. Often, the value of the recursive call is returned. As such, tail recursive functions can
often be easily implemented in an iterative manner; by taking out the recursive call and replacing it with
a loop, the same effect can generally be achieved. In fact, a good compiler can recognize tail recursion
and convert it to iteration in order to optimize the performance of the code.

A good example of a tail recursive function is a function to compute the GCD, or Greatest Common
Denominator, of two numbers:

def factorial(n):
if n == 0: return 1
else: return factorial(n-1) * n

def tail_factorial(n, accumulator=1):


if n == 0: return 1
else: return tail_factorial(n-1, accumulator * n)
Recursive algorithms for Factorial, GCD, Fibonacci Series and Towers of Hanoi:

Factorial(n)
Input: integer n ≥ 0

Output: n!

// If n = 0 then return (1)

// else return prod(n, factorial(n − 1))

GCD(m, n)

Input: integers m > 0, n ≥ 0

Output: gcd (m, n)

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

11 If n = 0 then return (m)

12 else return gcd(n,m mod

n) Time-Complexity: O(ln n)

Fibonacci(n)

Input: integer n ≥ 0

Output: Fibonacci Series: 1 1 2 3 5 8 13………………………………..

if n=1 or n=2

then Fibonacci(n)=1

else Fibonacci(n) = Fibonacci(n-1) + Fibonacci(n-2)

Towers of Hanoi

Input: The aim of the tower of Hanoi problem is to move the initial n different sized disks from needle
A to needle C using a temporary needle B. The rule is that no larger disk is to be placed above the
smaller disk in any of the needle while moving or at any time, and only the top of the disk is to be
moved at a time from any needle to any needle.

Output:

A If n=1, move the single disk from A to C and return,

B If n>1, move the top n-1 disks from A to B using C as temporary.

C Move the remaining disk from A to C.

D Move the n-1 disk disks from B to C, using A as temporary.

def TowerOfHanoi(n , from_rod, to_rod, aux_rod):

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

if n == 1:

print "Move disk 1 from rod",from_rod,"to rod",to_rod

return

TowerOfHanoi(n-1, from_rod, aux_rod, to_rod)

print "Move disk",n,"from rod",from_rod,"to rod",to_rod

TowerOfHanoi(n-1, aux_rod, to_rod, from_rod)

n=4

TowerOfHanoi(n, 'A', 'C', 'B')

Graph
A graph is a pictorial representation of a set of objects where some pairs of
objects are connected by links. The interconnected objects are represented
by points termed as vertices, and the links that connect the vertices are
called edges.

Formally, a graph is a pair of sets (V, E), where V is the set of vertices and
E is the set of edges, connecting the pairs of vertices. Take a look at the
following graph −

In the above graph,

V = {a, b, c, d, e}

E = {ab, ac, bd, cd, de}


Mathematical graphs can be represented in data structure. We can
represent a graph using an array of vertices and a two-dimensional array of
edges. Before we proceed further, let's familiarize ourselves with some
important terms −

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Vertex − Each node of the graph is represented as a vertex. In the


following example, the labeled circle represents vertices. Thus, A to
G are vertices. We can represent them using an array as shown in
the following image. Here A can be identified by index 0. B can be
identified using index 1 and so on.

Edge − Edge represents a path between two vertices or a line


between two vertices. In the following example, the lines from A to
B, B to C, and so on represents edges. We can use a two-
dimensional array to represent an array as shown in the following
image. Here AB can be represented as 1 at row 0, column 1, BC as 1
at row 1, column 2 and so on, keeping other combinations as 0.

Adjacency − Two node or vertices are adjacent if they are connected


to each other through an edge. In the following example, B is
adjacent to A, C is adjacent to B, and so on.

Path − Path represents a sequence of edges between the two


vertices. In the following example, ABCD represents a path from A
to D.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Basic Operations
Following are basic primary operations of a Graph −

Add Vertex − Adds a vertex to the graph.

Add Edge − Adds an edge between the two vertices of the graph.

Display Vertex − Displays a vertex of the graph.

To know more about Graph, please read Graph Theory Tutorial . We shall
learn about traversing a graph in the coming chapters.

Graph Traversal:
Graphs are one of the unifying themes of computer science – an abstract representation
which describes the organization of transportation systems, electrical circuits, human
interactions, and telecommunication networks. That so many different structures can be
modeled using a single formalism is a source of great power to the educated programmer.
In this chapter, we focus on problems which require only an elementary knowledge of
graph algorithms, specifically the appropriate use of graph data structures and traversal
algorithms. In Chapter 10, we will present problems relying on more advanced graph
algorithms that find minimum spanning trees, shortest paths, and network flows.

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Graph Traversal: Breadth-First:


The basic operation in most graph algorithms is completely and systematically traversing the
graph. We want to visit every vertex and every edge exactly once in some well-defined order.
There are two primary traversal algorithms: breadth-first search (BFS) and depth-first search
(DFS). For certain problems, it makes absolutely no different which one you use, but in other
cases the distinction is crucial.
Both graph traversal procedures share one fundamental idea, namely, that it is necessary to mark
the vertices we have seen before so we don‘t try to explore them again. Otherwise we get
trapped in a maze and can‘t find our way out. BFS and DFS differ only in the order in which
they explore vertices.

Breadth-first search is appropriate if (1) we don‘t care which order we visit the vertices and
edges of the graph, so any order is appropriate or (2) we are interested in shortest paths on
unweighted graphs.

Breadth-First Search:
You are given the maze figure below and asked to find a way to the exit with a minimum
number of decisions to make (a decision is required whenever there is at least one available
direction to go). We have pointed out these critical positions and given them numbers.

On the basis of the above diagram we will draw a graph with the following rules :

// the vertices are the critical positions


// there is an edge from X to Y if we can go from X to Y by making exactly one decision

Also the circles colored in cyan are the start (1) and the finish (10).

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

It is easy to see now that the minimum length path is 1, 3, 14, 15, 10 with 4 decisions to make (the
number of edges connecting the vertices). This is because we have an overview of the maze, we
know every detail about it in advance. But what if we do not ? We would never be aware of the
consequences of our current decision until we make it. What would be our strategy then ?

One possibility is to gather an infinite number of people (this is for instructional purposes only) and
put them in the start position of the maze.

Then every time we are to make a decision, leave one single person in the current position and split
the group into N smaller ones, where N is the number of the current possible decisions to make.
These groups each go a different way and so on, until someone reaches the finish. It is clear that the
path found by this group of people is of minimum length, since every group has to make only one
decision at a time (the length of each step is the same for everyone) and this group made it first to the
finish. Note that passing through a point that already has one person standing there is not permitted.

To reconstruct the minimum length path, let us assume that every person that is left in a certain
point knows exactly the position where the group came from. For example the person in point 2
knows that the group came from the 1st position before it left him there. Now if we start with the
last position of the winning group (the finish) we may go backwards as we know its previous
position, and so on until we reach the start. We have now constructed the exact minimum path (in
terms of decisions to make) to arrive at the finish of the maze, but in reversed order. The last
operation is to reverse the path in order to find the correct one.

This is a version of Lee's algorithm for finding the shortest path between two particular vertices in an
undirected graph. But let us now concentrate on the method of traversal, which in terms of graph
theory is known as Breadth First Search ( BFS in short ). I assume you already know the algorithm,
it is all in the way the groups of people move from one point to another - at each step the groups

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

separate into smaller ones, then go to the next positions and also leave a person behind. Remember
it is not allowed to pass through a point with one person already standing there. This separation
process continues until there are no more available positions to visit.

For a better understanding let us try and traverse the next graph starting from vertex 3 using this
method. The steps are already described graphically below but let us make a few comments.

First there is a group of 5 people (which is enough for this situation) positioned in vertex 3. Then one
person goes to vertex 1, one to vertex 5, two persons go to vertex 2 and one stays in 3. At the next
phase of the process we clearly see that the person in vertex 1 has nowhere to go, since both its next
possible positions (2 and 3) are occupied. Because 2 is smaller than 5 (considering the integer
numbers order) we will search first for its available positions. The single one is vertex 4, so we leave
one person in 2 and send one to 4. This seems like our last move - no person can move from its
current position anymore since all are occupied.

The BFS method shows the vertices that are visited through each step of the traversal process.

In the example above we would get the following listing :

3, 1, 2, 5, 4

To implement this method in C++ we will use a queue to store the current position of each group of
people and search for their available directions to go. Also we will use an additional Boolean array
to store information about each vertex (whether it is occupied or not) :

visited [ k ] = true if position k is occupied, otherwise visited [ k ] = false

The Breadth First Search pseudocode looks like this (assuming x is the first node to start the
traversal) :

for (all vertices 1<= i <= n) do


visited [ i ] = false
ADD x to Queue
visited [ x ] = true
while (Queue is not empty) do
extract information from the Queue to variable k
display k
for (all vertices 1<= i <= n) do

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

if (visited[ i ] == false AND there is an edge between k and i) then


ADD i to Queue
visited [ i ] = true
end if
end while
The minimum length path algorithm is very similar to this. The only difference is that we need to
store the position from which every person came in the traversal process in order to reconstruct the
path. We will achieve this using an array and displaying it in reverse order at the end of the
traversal. Below you will find the listing that implements both BFS and the minimum path
algorithm by encapsulating them inside the Graph class. We have also implemented a Queue class
since both use this type of container.

#include <iostream>

using namespace std;

struct node
{
int info;
node *next;
};

class Queue
{
public:
Queue();
~Queue();
bool isEmpty();
void add(int);
int get();
private:
node *first, *last;
};

class Graph
{
public:
Graph(int size = 2);
~Graph();
bool isConnected(int, int);
// adds the (x, y) pair to the edge set
void addEdge(int x, int y);
// performs a Breadth First Search starting with node x
void BFS(int x);
// searches for the minimum length path
// between the start and target vertices
void minPath(int start, int target);

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

private :
int n;
int **A;
};

Queue::Queue()
{
first = new node;
first->next = NULL;
last = first;
}

Queue::~Queue()
{
delete first;
}

bool Queue::isEmpty()
{
return (first->next == NULL);
}

void Queue::add(int x)
{
node *aux = new node;
aux->info = x;
aux->next = NULL;
last->next = aux;
last = aux;
}

int Queue::get()
{
node *aux = first->next;
int value = aux->info;
first->next = aux->next;
if (last == aux) last = first;
delete aux;
return value;
}

Graph::Graph(int size)
{
int i, j;
if (size < 2)
n = 2;
else
n = size;

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

A = new int*[n];
for (i = 0; i < n; ++i)

A[i] = new int[n];


for (i = 0; i < n; ++i)
for (j = 0; j < n; ++j)
A[i][j] = 0;
}

Graph::~Graph()
{
for (int i = 0; i < n; ++i)
delete [] A[i];
delete [] A;
}

bool Graph::isConnected(int x, int y)


{
return (A[x-1][y-1] == 1);
}

void Graph::addEdge(int x, int y)


{
A[x-1][y-1] = A[y-1][x-1] = 1;
}

void Graph::BFS(int x)
{
Queue Q;
bool *visited = new bool[n+1];
int i;

for (i = 1; i <= n; ++i)


visited[i] = false;

Q.add(x);
visited[x] = true;
cout << "Breadth First Search starting from vertex ";
cout << x << " : " << endl;

while (!Q.isEmpty())
{
int k = Q.get();
cout << k << " ";
for (i = 1; i <= n; ++i)
if (isConnected(k, i) && !visited[i])
{
Q.add(i);

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

visited[i] = true;
}
}

cout << endl;


delete [] visited;
}

void Graph::minPath(int start, int target)


{
Queue Q;
int i, p, q;
bool found;
struct aux
{
int current, prev;
};

aux *X = new aux[n+1];


int *Y = new int[n+1];
bool *visited = new bool[n+1];
for (i = 1; i <= n; ++i)
visited[i] = false;

Q.add(start);
visited[start] = true;
found = false;
p = q = 0;
X[0].current = start;
X[0].prev = 0;

while (!Q.isEmpty() && !found)


{
int k = Q.get();
for (i = 1; i <= n && !found; ++i)
if (isConnected(k, i) && !visited[i])
{
Q.add(i);
++q;
X[q].current = i;
X[q].prev = p;
visited[i] = true;

if (i == target)
found = true;
}
++p;
}

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

cout << "The minimum length path from " << start;
cout << " to " << target << " is : " << endl; p = 0;

while (q)
{
Y[p] = X[q].current;
q = X[q].prev;
++p;
}

Y[p] = X[0].current;
for (q = 0; q <= p/2; ++q)
{
int temp = Y[q];
Y[q] = Y[p-q];
Y[p-q] = temp;
}

for (q = 0; q <= p; ++q)


cout << Y[q] << " ";
cout << endl;
cout << "Length = " << q-1 << endl;

delete [] visited;
delete [] X;
delete [] Y;
}

void Traversal()
{
Graph g(5);
g.addEdge(1, 2); g.addEdge(1, 3); g.addEdge(2, 4);
g.addEdge(3, 5); g.addEdge(4, 5); g.addEdge(2, 3);
g.BFS(3);
}

void Maze()
{
Graph f(15);
f.addEdge(1, 2); f.addEdge(1, 3); f.addEdge(2, 4);
f.addEdge(3, 14); f.addEdge(4, 5); f.addEdge(4, 6);
f.addEdge(5, 7); f.addEdge(6, 13); f.addEdge(7, 8);
f.addEdge(7, 9); f.addEdge(8, 11); f.addEdge(9, 10);
f.addEdge(10, 12); f.addEdge(10, 15); f.addEdge(11, 12);
f.addEdge(13, 14); f.addEdge(14, 15); f.minPath(1, 10);

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

void main()
{
Traversal();
cout << endl;
Ma ze();
}

Sample input / output:

Graph Traversal: Depth-Fir st:


Depth-f irst search (DFS) is an algorithm for traversing or searc hing a tree, tree structu re, or grap
h. One starts at the ro ot (selecting some nod e as the ro ot in the gra ph case) an d explores as far as
possibl e along eac h branch before backtracking.
Formally, DFS is a n uninform ed search that progresses by expanding the first child no de of the
search t ree that ap pears and th us going d eeper and deeper until a goal node is found, o r until it hi
ts a node that has no c hildren. The n the search backtrack s, returning to the mos t recent no de it
hasn't finishe d exploring. In a non-r ecursive implementatio n, all freshly expande d nodes are added
to a stack fo r explorati on.

Order in w hich the no des are exp anded

For the following graph:

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

a depth-first search starting at A, assuming that the left edges in the shown graph are chosen before
right edges, and assuming the search remembers previously-visited nodes and will not repeat them
(since this is a small graph), will visit the nodes in the following order: A, B, D, F, E, C, G.

#include<iostream>

using namespace std;

class graph
{
private:
int n;
graph* next;
public:
graph* read_graph(graph*);
void dfs(int); //dfs for a single node
void dfs(); //dfs of the entire graph
void ftraverse(graph*);
};

graph *g[100];
int visit[100];
int dfs_span_tree[100][100];

graph* graph::read_graph(graph*head)
{
int x;
graph* last;
head=last=NULL;

cout<<"Enter adjecent node ,-1 to stop:\n";


cin>>x;
while(x!=-1)
{
graph*NEW;
NEW=new graph;
NEW->n=x;
NEW->next=NULL;

if(head==NULL)
head=NEW;
else
last->next=NEW;

last=NEW;

cout<<"Enter adjecent node ,-1 to stop:\n";


cin>>x;

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

return head;
}

void graph::ftraverse(graph*h)
{
while(h!=NULL)
{
cout<<h->n<<"->";
h=h->next;
}

cout<<"NULL"<<endl;
}

void graph::dfs(int x)
{
cout<<"node "<<x<<" is visited\n";
visit[x]=1;

graph *p;
p=g[x];
while(p!=NULL)
{
int x1=p->n;
if(visit[x1]==0)
{
cout<<"from node "<<x<<' ';
//Add the edge to the dfs spanning tree
dfs_span_tree[x][x1]=1;
dfs(x1);
}

p=p->next;
}
}

void graph::dfs()
{
int i;
cout<<"*****************************************************\n";
cout<<"This program is to implement dfs for an unweighted graph \n";
cout<<"*****************************************************\n";

cout<<"Enter the no of nodes ::";


cin>>n;
for(i=1;i<=n;i++)

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

g[i]=NULL;

for(i=1;i<=n;i++)
{
cout<<"Enter the adjacent nodes to node no. "<<i<<endl;
cout<<"***************************************\n";
g[i]=read_graph(g[i]);
}

//display the graph


cout<<"\n\nThe entered graph is ::\n";
for(i=1;i<=n;i++)
{
cout<<" < "<<i<<" > ::";
ftraverse(g[i]);
}

for(i=1;i<=n;i++)
visit[i]=0; //mark all nodes as unvisited

cout<<"\nEnter the start vertex ::";


int start;
cin>>start;

for(i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dfs_span_tree[i][j]=0;

cout<<"\nThe dfs for the above graph is ::\n";


dfs(start);

cout<<"\n\nThe required dfs spanning tree is ::\n";

for(i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
cout<<dfs_span_tree[i][j]<<' ';
cout<<endl;
}
}

int main()
{
graph obj;
obj.dfs();
return 0;
}

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Sample input / output:

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

Dijkstra’s Algorithm
[Note: this chapter covers material of about 1 lecture.]
Earlier on, we looked at the problem of finding shortest paths in graphs, and used Breadth First Search
(BFS) to solve this problem. At the time, our graphs did not have any edge costs or weights. The task gets a
little more interesting when there are edge costs: then, the equivalent algorithm is called Dijkstra’s
1
Algorithm .
Dijkstra’s algorithm is the right choice when all we are given is the graph with its edge costs/weights.
But often, there is more information, such as geography, which can be used to guide a shortest-path
search to speed it up. The improved version of Dijkstra’s Algorithm taking advantage of extra information
is called A∗ search, and is particularly important in the field of Artificial Intelligence.

Dijkstra’s Algorithm
As we said, we now assume that each edge e = (v, w) of our graph has a cost (or length) c e = c[v][w] ≥
2
0. First, we might just try to run BFS. But that’s clearly not correct, as we can see from Figure 27.1.

v3
1
v2
1 1
v1 6
1
10.
u w

Figure 27.1: An example with edge costs in which BFS does not find the shortest path from u to w.

When we process u (the start node), we add v1 and w to the queue. We next process v1, and add v2.
But when we process w, we are done with it, and never revisit its distance label. So we think that it is at
distance 10 from u, when it really is at distance 4.
The mistake we are making here is that processing w is premature. The node v2 is a much better
candidate to explore next, because it is closer to u; the fact that it is closer means that it may lie on an

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

actual shortest path from u to w (as it does here), so we shouldn’t conclude anything about the distance
from u to w until we’ve made sure that there isn’t another, shorter, path.
What this suggests is that nodes shouldn’t just be stored in a queue. When a newly added node —
like v2 in our example — is closer to u, then it should be allowed to jump ahead of other nodes and be
processed before them. But we’ve already seen a data structure built exactly for this purpose: a Priority
Queue. So Dijkstra’s Algorithm is obtained pretty much exactly by replacing the Queue in the BFS
algorithm with a Priority Queue. Beyond that change, we just need some small modifications, mostly to
take care of the fact that the estimated distance of a node may be updated multiple times. For instance, in
our example in Figure 27.1, when we explore v2, we update our distance estimate for w to 8 instead of
10, but we later update it to 4, which is the final value. The more formal algorithm we get is as follows:
int d[n]; // will store distances from u
int p[n]; // will store predecessors of nodes on shortest paths from u
int c[n][n]; // contains the costs of edges

void Dijkstra (int u) {


bool visited[n] = {false}; // no node is visited yet.
PriorityQueue<int> pq ();
/* empty priority queue to start. We assume that the priority
queue always returns the element v with smallest d[v] value,
and can deal with updating the d[v] value for an element. */

visited[u] = true; d[u] = 0;


pq.add (u);
while (!pq.isEmpty()) {
int v = pq.peek();
pq.remove ();
for (all nodes w with an edge (v,w) in E)
if (!visited[w] || d[v] + c[v][w] < d[w]) { // found a shorter
path to w d[w] = d[v] + c[v][w];
p[w] = v;
if (!visited[w])
{
visited[w] = true;
pq.add(w);
}
else pq.update(w);
}
}
}

Notice the strong similarity to the BFS algorithm. The main change is the we use a priority queue instead
of a queue, and that we have an additional condition that allows us to process a node w: not only when
the node hasn’t been visited at all, but also when we found a strictly shorter distance to get to w. In the
latter case, the node will already be in the priority queue, so instead of adding it, we need to update the
associated value.
When we first learned about Priority Queues (in Chapter 22), we didn’t discuss how to update an entry after
its priority has changed. It’s pretty clear that when its priority gets higher (i.e., its distance gets smaller), we
should trickle the element up. And when the priority gets smaller, we should trickle it down. The not-so-obvious
thing is how we find it in the heap in the first place, so we can trickle it up or down. A linear search through all
elements would take Ω(n), and thus completely defeat the purpose of using a heap in the first place. The most
obvious way to solve this problem is to store somewhere (e.g., in the struct for a node of the graph) an
integer index describing where in the heap the element is located. Then, any time

Downloaded by KOLANJI Bala ([email protected])


lOMoARcPSD|37280708

two elements swap positions in the heap, we can update their entries, at an additional
constant cost. If we don’t like the idea of storing heap information in a node’s struct (since
it’s really not part of the node’s description, but part of the algorithm), we could instead have
another array inside the Priority Queue: that array tells us for each of the nodes (in their
original ordering in the graph) where it is located in the heap.

Either way, it is easy to implement a lookup operation so that we only incur a constant times
as much cost for each step.
The correctness proof for Dijkstra’s Algorithm would use induction over the iterations of
the while loop. It requires a bit more care in the formulation of a loop invariant, and you may
see it in CSCI 270 (or CSCI 570 or 670, if you take it). We won’t go over it here, even though
it’s not all that difficult.
The running time analysis gets a little more interesting than for BFS. The remove() and
add() operations now both take Θ(log n) time (while peek() is still Θ(1)). So the content of
the for loop takes time Θ(log n), and since it executes Θ(out-degree(v)) times, the total time
of the for loop is Θ(out-degree(v) log n). This in turn gives us that the stuff inside the while
loop takes time Θ((1 + out-degree(v)) · log n), which we now have to sum up over all nodes
v, as usual:
Θ((1 + out-degree(v)) · log n) = Θ(log X
X out-degree(v))) = Θ(log n · (n
n·( + m)).
v V

For Dijkstra’s Algorithm, even though in principle, we could have the case m < n just like we could
for BFS, people usually ignore the n part of n + m, and simply describe the running time as Θ(m
log n). Not quite linear time, but it’s still quite fast, and a pretty cool application of priority queues.
In fact, Dijkstra’s Algorithm and A∗ search are really the main reason computer scientists need to
care about priority queues.

Downloaded by KOLANJI Bala ([email protected])

You might also like