Vous êtes sur la page 1sur 207

DEPARTMENT OF INFORMATION

TECHNOLOGY

CS6301 PROGRAMMING AND


DATASTRUCTURES II
LECTURE NOTES
1
www.cseitquestions.in

UNIT I
OBJECT ORIENTED PROGRAMMING FUNDAMENTALS

C++ Programming features - Data Abstraction - Encapsulation - class - object constructors static members constant members member functions pointers
references - Role of this pointer Storage classes function as arguments.

1.1 C++ PROGRAMMING FEATURES:


1. The C++ programming language is based on the C language.
2. Although C++ is a descendant of the C language, the two languages are not always
compatible.
3. In C++, you can develop new data types that contain functional descriptions (member
functions) as well as data representations. These new data types are called classes.
4. The work of developing such classes is known as data abstraction. You can work with
a combination of classes from established class libraries, develop your own classes, or
derive new classes from existing classes by adding data descriptions and functions.
5. New classes can contain (inherit) properties from one or more classes. The classes
describe the data types and functions available, but they can hide (encapsulate) the
implementation details from the client programs.

6. You can define a series of functions with different argument types that all use the
same function name. This is called function overloading. A function can have the
same name and argument types in base and derived classes.
7. Declaring a class member function in a base class allows you to override its
implementation in a derived class. If you use virtual functions, class-dependent
behavior may be determined at run time. This ability to select functions at run time,
depending on data types, is called polymorphism.
8. You can redefine the meaning of the basic language operators so that they can
perform operations on user-defined classes (new data types), in addition to operations
on system-defined data types, such as int, char, and float. Adding properties to
operators for new data types is called operator overloading.
9. The C++ language provides templates and several keywords not found in the C
language. Other features include try-catch-throw exception handling, stricter type
checking and more versatile access to data and functions compared to the C language.
2
www.cseitquestions.in

1.2 DATA ABSTRACTION:

Data abstraction refers to, providing only essential information to the outside world
and hiding their background details, i.e., to represent the needed information in

program without presenting the details.

Data abstraction is a programming (and design) technique that relies on the separation
of interface and implementation.

Let's take one real life example of a TV, which you can turn on and off, change the
channel, adjust the volume, and add external components such as speakers, VCRs,
and DVD players, BUT you do not know its internal details, that is, you do not know
how it receives signals over the air or through a cable, how it translates them, and

finally displays them on the screen.

Thus, we can say a television clearly separates its internal implementation from its
external interface and you can play with its interfaces like the power button, channel

changer, and volume control without having zero knowledge of its internals.

Now, if we talk in terms of C++ Programming, C++ classes provides great level of
data abstraction. They provide sufficient public methods to the outside world to play
with the functionality of the object and to manipulate object data, i.e., state without

actually knowing how class has been implemented internally.

In C++, we use classes to define our own abstract data types (ADT). You can use the
cout object of class ostream to stream data to standard output like this:

#include <iostream.h>
int main( )
{
cout << "Hello C++" <<endl;
return 0;
}

Here, you don't need to understand how cout displays the text on the user's screen.
You need to only know the public interface and the underlying implementation of
cout is free to change.

3
www.cseitquestions.in

Access Labels Enforce Abstraction:

In C++, we use access labels to define the abstract interface to the class. A class may
contain zero or more access labels:

Members defined with a public label are accessible to all parts of the program. The
data-abstraction view of a type is defined by its public members.

Members defined with a private label are not accessible to code that uses the class.
The private sections hide the implementation from code that uses the type.

There are no restrictions on how often an access label may appear. Each access label
specifies the access level of the succeeding member definitions. The specified access
level remains in effect until the next access label is encountered or the closing right
brace of the class body is seen.

Benefits of Data Abstraction:

Data abstraction provides two important advantages:

Class internals are protected from inadvertent user-level errors, which might corrupt
the state of the object.

The class implementation may evolve over time in response to changing requirements
or bug reports without requiring change in user-level code.

By defining data members only in the private section of the class, the class author is
free to make changes in the data. If the implementation changes, only the class code
needs to be examined to see what affect the change may have. If data are public, then
any function that directly accesses the data members of the old representation might
be broken.

Data Abstraction Example:

Any C++ program where you implement a class with public and private members is
an example of data abstraction. Consider the following example:

#include <iostream.h>
using namespace std;

class Adder
{
public:
4
www.cseitquestions.in

// constructor
Adder(int i = 0)
{
total = i;
}
// interface to outside world
void addNum(int number)
{
total += number;
}
// interface to outside world
int getTotal()
{
return total;
};
private:
// hidden data from outside
world int total;
};
int main( )
{
Adder a;
a.addNum(10);
a.addNum(20);
a.addNum(30);
cout << "Total " << a.getTotal() <<endl;
return 0;
}
When the above code is compiled and executed, it produces the following result: Total 60

Above class adds numbers together, and returns the sum. The public members
addNum and getTotal are the interfaces to the outside world and a user needs to
know them to use the class. The private member total is something that the user
doesn't need to know about, but is needed for the class to operate properly.

5
www.cseitquestions.in

1.3 DATA ENCAPSULATION:

Data encapsulation is a mechanism of bundling the data, and the functions that use
them and data abstraction is a mechanism of exposing only the interfaces and hiding
the implementation details from the user.

C++ supports the properties of encapsulation and data hiding through the creation of
user-defined types, called classes. We already have studied that a class can contain
private, protected and public members. By default, all items defined in a class are
private.

For example:
class Box
{
public:
double getVolume(void)
{
return length * breadth * height;
}
private:
double length;

// Length of a box

double breadth; // Breadth of a box


double height;

// Height of a box

};

The variables length, breadth, and height are private. This means that they can be
accessed only by other members of the Box class, and not by any other part of your

program. This is one way encapsulation is achieved.

To make parts of a class public (i.e., accessible to other parts of your program), you
must declare them after the public keyword. All variables or functions defined after

the public specifier are accessible by all other functions in your program.

Making one class a friend of another exposes the implementation details and reduces
encapsulation. The ideal is to keep as many of the details of each class hidden from all
other classes as possible.

6
www.cseitquestions.in

Data Encapsulation Example:


Any C++ program where you implement a class with public and private members is an
example of data encapsulation and data abstraction. Consider the following example:

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

{
public:
// constructor
Adder(int i = 0)
{
total = i;
}
// interface to outside world
void addNum(int number)
{
total += number;
}
// interface to outside world
int getTotal()
{
return total;
};
private:
// hidden data from outside
world int total;
};
int main( )
{
Adder a;
a.addNum(10);
a.addNum(20);
a.addNum(30);
7
www.cseitquestions.in

cout << "Total " ;


cout<< a.getTotal();
cout <<endl;
return 0;
}

When the above code is compiled and executed, it produces the following result: Total 60
Above class adds numbers together, and returns the sum. The public members
addNum and getTotal are the interfaces to the outside world and a user needs to know them
to use the class. The private member total is something that is hidden from the outside world,

but is needed for the class to operate properly.


Designing Strategy:
Most of us have learned through bitter experience to make class members private by
default unless we really need to expose them. That's just good encapsulation.
This wisdom is applied most frequently to data members, but it applies equally to all
members, including virtual functions.
1.4 CLASS:
In oop, class is a user defined data type that can hold data and their associated
functions into single unit.
The class members are divided into two types:
1. Data Member
2. Function Member
In class there are certain privilege for accessing both data and function members.
They are said to be access specifiers.
It is divided into three categories. They are,
1.Public
2.private
3.Protected
By default the data members are private. So the private members of a class are not
accessible from outside the class. If the data members are specified as public then the
members of a class can be accessible from inside and outside of the class.

8
www.cseitquestions.in

Syntax of a class
class class_name
{
Access Specifier:
Data Members
Access Specifier:
Function Members
};

Example:
Consider an example of class
class student
{
public:
int rollno,age;

Data Members

char *name;
void getdetail()
{
Cin>>rollno>>age;
Cin>>name;
}

Function Members

void printdetail()
{
Cout<<rollno<<age;
Cout<<name;
}
};
In this example a class named student with data members such rollno, age and name
and with function members getdetail() and printdetail() is defined within the class.The access
specifiers of this class is public.

9
www.cseitquestions.in

Function Definition outside the Class


The function members which are declared inside the class can be defined outside of
the class using Scope Resolution Operator ::

Syntax for Defining the Function outside the Class:


Return Type class_name::function_name()
{
Function Body
}

Return type specifies the type of a function. Class name specifies the name of a class
in which the function belongs. The operator:: denotes scope resolution operator. Function
name specifies the name of a function.

Example:
class student
{
public:
int rollno,age;
char *name; void
getdetail(); void
printdetail(); };
void student::getdetail()
{
Cin>>rollno>>age;
Cin>>name;
}
void student::printdetail()
{
Cout<<rollno<<age;
Cout<<name;
}
10
www.cseitquestions.in

1.5 OBJECTS:
Objects are the variables of user defined data type called class. Once a Class has been
created we can declare any number of variables belongs to that class. In the above example
class student we can declare any number of variables of class student in the main function.
Using objects we can access any public members of a class using Dot Operator.

For accessing Data Members and assigning value:


object_name.data_member=value;

For accessing Function Members:


Object_name.function_name();

Syntax:
Class_Name object1, object2, object3.object n;
void main ()
{

class Name

student s1, s2,s3;


s1.rollno=28;

s1,s2,s3 are objects(variables) of class Student


Object s1 assigns the value for the data member rollno=28

s1.getdetail (); Object s1 access (call) the function member getdetail () of student class
s1.printdetail ();

Object s1 access (call) the function member


printdetail () of student class

Memory Requirement for Objects and Class:


Once the object is created memory is allocated for the data members of a class and not
for its function Members .So each object holds the total memory size of the data members.
For example in the class student the object s1 holds the memory size of 5 bytes. Char I byte,
int 2 bytes.
Once the class is created only single copy of function member is maintained which
is common for all the objects.

11
www.cseitquestions.in

Class student
Function Members:
Void getdetail()
Void printdetail()

Object s1:

Object s2:

Object s3:

Data Member Name

Data Member Name

Data Member Name

Data Member Rollno

Data Member Rollno

Data Member Rollno

Data Member age

Data Member age

Data Member age

1.6 CONSTRUCTOR:
The main use of constructors is to initialize objects. The function of initialization is
automatically carried out by the use of a special member function called a constructor.
General Syntax of Constructor
A constructor is a special member function that takes the same name as the class
name. The default constructor for a class X has the form
X::X()
In the above example, the arguments are optional. The constructor is automatically
named when an object is created. A constructor is named whenever an object is defined or
dynamically allocated using the new operator.
There are several forms in which a constructor can take its shape namely:

Default Constructor:
This constructor has no arguments in it. The default Constructor is also called as the
no argument constructor.
For example:
class Exforsys
{
12
www.cseitquestions.in

private:
int a,b;
public:
Exforsys();
...
};

Exforsys :: Exforsys()
{
a=0;
b=0;
}

Parameterized Constructor:
A default constructor does not have any parameter, but if you need, a constructor
can have parameters. This helps you to assign initial value to an object at the time of its
creation as shown in the following example:
#include <iostream>
class Line

{
public:
void setLength( double len );
double getLength( void );

Line(double len); // This is the constructor

private:
double length;
};

// Member functions definitions including


constructor Line::Line( double len)
{
cout << "Object is being created, length = " << len << endl;
length = len;
13
www.cseitquestions.in

}
void Line::setLength( double len )
{
length = len;
}
double Line::getLength( void )
{
return length;
}
// Main function for the
program int main( )
{
Line line(10.0);
// get initially set length.
cout << "Length of line : " << line.getLength() <<endl;
// set line length again
line.setLength(6.0);
cout << "Length of line : " << line.getLength() <<endl;

return 0;
}
When the above code is compiled and executed, it produces the following result:
Object is being created, length = 10
Length of line : 10
Length of line : 6

Copy constructor:
This constructor takes one argument, also called one argument constructor. The main
use of copy constructor is to initialize the objects while in creation, also used to copy an
object. The copy constructor allows the programmer to create a new object from an existing
one by initialization.
For example to invoke a copy constructor the programmer
writes: Exforsys e3(e2);
or
14
www.cseitquestions.in

Exforsys e3=e2;
Both the above formats can be sued to invoke a copy constructor.

For Example:
#include <iostream>
using namespace std;
class Exforsys

{
private:
int a;
public:
Exforsys()
{
}
Exforsys(int w)
{
a=w;
}
Exforsys(Exforsys& e)
{
a=e.a;
cout << " Example of Copy Constructor";
}
void result()
{
cout<< a;
}
};
void main()
{
Exforsys e1(50);
Exforsys e3(e1);
cout<< "ne3=";e3.result();
}
15
www.cseitquestions.in

Destructors
Destructors are also special member functions used in C++ programming language.
Destructors have the opposite function of a constructor. The main use of destructors is to
release dynamic allocated memory.
Destructors are used to free memory, release resources and to perform other clean up.
Destructors are automatically named when an object is destroyed. Like constructors,
destructors also take the same name as that of the class name.

General Syntax of Destructors


~ classname();
The above is the general syntax of a destructor. In the above, the symbol tilda ~
represents a destructor which precedes the name of the class.
Some important points about destructors:

Destructors take the same name as the class name.

Like the constructor, the destructor must also be defined in the public. The destructor
must be a public member.

The Destructor does not take any argument which means that destructors cannot be
overloaded.

No return type is specified for destructors.

For example:
class Exforsys
{
private:
...
public:
Exforsys()
{
}
~ Exforsys()
{
}
}

16
www.cseitquestions.in

1.7 STATIC MEMBERS:


The Static Data Member of a class is like a global variable. Once it is defined the
static member will be initialized to zero. When the static member is declared inside the class
it should be defined outside of the class. Static Data Member of a class will be common to all
the objects which are declared in the class.
Syntax:
class stat
{
static int count; //static Data Member Declaration
}
int stat::count; //static Data member Defintion

Example Program:
#include<iostream.h>
#include<conio.h>
class count

{
public:
static int countt;
void dispcount()

{
countt++;
cout<<"Object\t"<<countt<<"\n";
}
};
int count::countt;
void main()

{
count c1,c2,c3,c4,c5;
clrscr();
c1.dispcount();
c2.dispcount();
c3.dispcount();
17
www.cseitquestions.in

c4.dispcount();
c5.dispcount();
getch();
}

In this example class count has a static data member countt.This program is used for
counting the number of objects which is declared in the class.So when an object c1 access the
function dispcount() the static variable has the value 1.when s5 access the function the value
will be incremented to 5.

Output:
Object 1
Object 2
Object 3
Object 4
Object 5

NOTE:
Once the static data member is defined it is automatically initialized to zero.

1.8 CONSTANT MEMBERS:


Constant Objects and Constant Functions

Once the object is declared as constant it cannot be modified by any function.

Initially the value for the data members is set by constructor during the object
creation.

Constant objects can access only the constant member function .The constant function
is read only function it cannot alter the value of object data members

Syntax- Constant Function & Constant objects


class class_name{
class_name(parameters)
{

18
www.cseitquestions.in

initialize the datamember with parameters;


}
return_type function_name() const

//Constant member function

{
//read only function
}
};
void main()
{
const class_name object( parameter);

//constant objects

object.function(); //constant objects access Constant member function


}

Ex:
void printdetails() const
{
cout<<Roll No is:<<rollno;
cout<<Name is:<<name;
cout<<Address is:<<address;

rollno=10; / / the following line is erroneous


}

Mutable Data Members


In some cases if the static function need to modify the data member of an object, then the
data member should be declared as mutable, so that static function can modify it.
mutable int rollno; void
printdetails() const
{
rollno=10; //it is allowed
}

19
www.cseitquestions.in

Example program for constant function and constant objects


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

{
public:
int hour,minute,second;
time(int temphr,int tempmin,int tempsec)
{
hour=temphr;
minute=tempmin;
second=tempsec;
}
void disp() const

//constant member function

{
cout<<"Time is:"<<hour<<"Hour:\t"<<minute<<"Minutes:\t"<<second<<"Seconds:\n";
}
~time()
{
}
void get() const
{
cin>>hour>>minute>>second;
}
};

void main()
{
clrscr();
const time t1(8,55,50);

//Constant objects

t1.disp();
t1.get();

//cannot modify the datamembers of t1

t1.disp();
getch();
}
20
www.cseitquestions.in

Output
Time is:8Hour: 55Minutes:

50Seconds:

5
50
40
Time is:8Hour: 55Minutes:

50Seconds:

In this example, the object of this time class is set with the default value of 8 hour 55
minutes and 50 seconds and it is initialized with constructor. Since this object t1 is a n
constant object it cannot be modified and it can access only the constant function in a class.

1.9 MEMBER FUNCTIONS:


1.9.1 Static Function
Static member functions have a class scope and they do not have access to the 'this'
pointer of the class. When a member is declared as static, a static member of class, it has only
one data for the entire class even though there are many objects created for the class. The
main usage of static function is when the programmer wants to have a function which is
accessible even when the class is not instantiated.

Syntax
class stat
{
static return_type function_name()
{
Statement;
}
};
Calling Static Function in the main Function
void main()
{
class_name::static function name();
}
21
www.cseitquestions.in

Example:
#include<iostream.h>
#include<conio.h>
class count

{
public:
static int
countt; count()
{
countt++;
cout<<"Object\t"<<countt<<"\n";
}
static void statfun()
{
cout<<"Object\t"<<countt<<"\n";
}
};
int count::countt;
void main()
{
count c1,c2,c3,c4,c5;
clrscr();
count::statfun();//calling the constructor using classname
getch();//scope resolution operator and the static funtion name

Output:
Object 5

The programmer must note the following while using static member functions:

A static member function can only access static member data, static member functions
and data and functions outside the class. The programmer must take note not to use
static member function in the same manner as non-static member function, as nonstatic member function can access all of the above including the static data member.
22
www.cseitquestions.in

A non-static member function can be declared as virtual but care must be taken not to
declare a static member function as virtual. .

The programmer must first understand the concept of static data while learning the
context of static functions. It is possible to declare a data member of a class as static
irrespective of it being a public or a private type in class definition. If a data is
declared as static, then the static data is created and initialized only once. Non-static
data members are created again and again. For each separate object of the class, the
static data is created and initialized only once. As in the concept of static data, all
objects of the class in static functions share the variables. This applies to all objects of
the class.

A non-static member function can be called only after instantiating the class as an
object. This is not the case with static member functions. A static member function

can be called, even when a class is not instantiated.

A static member function cannot have access to the 'this' pointer of the class.

1.9.2 Inline member Function


We may either define a member function inside its class definition, or you may define
it outside if you have already declared (but not defined) the member function in the class
definition.
A member function that is defined inside its class member list is called an inline
member function. Member functions containing a few lines of code are usually declared
inline. In the above example, add() is an inline member function. If you define a member
function outside of its class definition, it must appear in a namespace scope enclosing the
class definition. You must also qualify the member function name using the scope resolution
(::) operator.
An equivalent way to declare an inline member function is to either declare it in the
class with the inline keyword (or define the function outside of its class) or to define it
outside of the class declaration using the inline keyword.

1.10 POINTERS:
Every storage location of memory has an associated address. The address is a number
that grows sequentially. For every program placed in memory, each variable or function in
the program has an associated address.
23
www.cseitquestions.in

The address of operator:


The address of operator or Reference operator is denoted by the notation &. When the
user wants to get the address of a variable, then the reference operator & can be used. The
operator & is used to find the address associated with a variable.
The syntax of the reference operator is as follows:
&variablename - This means that the address of the variable name is achieved.

For Example
#include <iostream>
using namespace std;
void main()
{
int exf=200;
int test=300;

cout << endl << &exf << endl << &test;


}

The output of the above program could be one of the following, and at each run it
differs slightly:

The &exf has the address associated with the integer variable exf and the &test has
the address associated with the integer variable test which are displayed using the cout
statement.
Using the understanding of address of operators, the discussion turns to the concept of
pointers.
exforsys = 100;
test = exforsys;
x = &exforsys;
Using the above information, the assignment takes place as below:
24
www.cseitquestions.in

exforsys is an integer variable having the value of 100 stored in memory address location
3501.
When the variable exforsys is assigned to the variable test in the second statement:
test = exforsys;
The value of the variable exforsys 100 is copied to the variable test.
In the third statement, the address of the variable exforsys is denoted by reference operator
&exforsys is assigned to the variable x as:
x = &exforsys;

The address of the variable 3501 and not the contents of the variable exforsys is
copied into the variable x. The pointers concept fits in this statement. Pointers are the
variables that store the reference to another variable. Pointers are variables that store the
address of the variable that it is pointed by. Variable x is referred to as the pointer in the
above example.
The programmer must note that the address operator placed before a variable is not
the same as operator & placed after the variable. For example, &x is not same as x&.
Variable &x refers to address operator whereas x& refer to reference operator&. Pointer is a
variable that holds the address, also called pointer variable.

Defining Pointer Variables or Pointer:


To define pointer variable is as follows:
datatype_of_ variable_pointedto* pointer_varaible;
For example:
char* ch;
This defines that ch is a pointer variable which points to char data
type. int* i;
This defines that i is a pointer variable which points to int data
type. float* f;
This defines that f is a pointer variable which points to float data type.
25
www.cseitquestions.in

1.11 REFERENCES:
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.

C++ References vs Pointers:


1. References are often confused with pointers but three major differences between
references and pointers are:
2. You cannot have NULL references. You must always be able to assume that a
reference is connected to a legitimate piece of storage.
3. Once a reference is initialized to an object, it cannot be changed to refer to another
object. Pointers can be pointed to another object at any time.
4. A reference must be initialized when it is created. Pointers can be initialized at any
time.

Creating References in C++:


Think of a variable name as a label attached to the variable's location in memory. You
can then think of a reference as a second label attached to that memory location. Therefore,
you can access the contents of the variable through either the original variable name or the
reference.
For example, suppose we have the following example:
int i = 17;
We can declare reference variables for i as
follows.

int& r = i;

Read the & in these declarations as reference. Thus, read the first declaration as "r is
an integer reference initialized to i" and read the second declaration as "s is a double
reference initialized to d.". Following example makes use of references on int and double:

#include <iostream.h>
int main ()

{
// declare simple variables
int i;
26
www.cseitquestions.in

double d;
// declare reference variables
int& r = i;
double& s = d;
i = 5;
cout << "Value of i : " << i << endl;
cout << "Value of i reference : " << r << endl;
d = 11.7;
cout << "Value of d : " << d << endl;
cout << "Value of d reference : " << s << endl;
return 0;
}

When the above code is compiled together and executed, it produces the following result:
Value of i : 5
Value of i reference : 5
Value of d : 11.7
Value of d reference : 11.7

References are usually used for function argument lists and function return values. So
following are two important subjects related to C++ references which should be clear to a
C++ programmer: we can implement call by reference concept using pointers.

Here is another example of call by reference which makes use of C++


reference: #include <iostream.h>
// function declaration
void swap(int& x, int&
y); int main ()
{
// local variable
declaration: int a = 100;
int b = 200;
cout << "Before swap, value of a :" << a << endl;
cout << "Before swap, value of b :" << b << endl;

27
www.cseitquestions.in

/* calling a function to swap the values.*/


swap(a, b);
cout << "After swap, value of a :" << a << endl;
cout << "After swap, value of b :" << b << endl;

return 0;
}

// function definition to swap the


values. void swap(int& x, int& y)
{
int temp;
temp = x; /* save the value at address x
*/ x = y; /* put y into x */
y = temp; /* put x into y */

return;
}

When the above code is compiled and executed, it produces the following
result: Before swap, value of a :100
Before swap, value of b :200
After swap, value of a :200
After swap, value of b :100

1.12 ROLE OF this POINTER:


Every object in C++ has access to its own address through an important pointer called
this pointer. The this pointer is an implicit parameter to all member functions. Therefore,
inside a member function, this may be used to refer to the invoking object.
Friend functions do not have a this pointer, because friends are not members of a
class. Only member functions have a this pointer.

Example:
#include <iostream.h>
28
www.cseitquestions.in

class Box
{
public:
// Constructor definition
Box(double l=2.0, double b=2.0, double h=2.0)
{
cout <<"Constructor called." << endl;
length = l;
breadth = b;
height = h;

}
double Volume()
{
return length * breadth * height;
}
int compare(Box box)
{
return this->Volume() > box.Volume();
}
private:
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
};
int main(void)
{
Box Box1(3.3, 1.2, 1.5); // Declare box1
Box Box2(8.5, 6.0, 2.0); // Declare box2
if(Box1.compare(Box2))
{
cout << "Box2 is smaller than Box1" <<endl;
}
else
{
29
www.cseitquestions.in

cout << "Box2 is equal to or larger than Box1" <<endl;


}
return 0;
}

When the above code is compiled and executed, it produces the following
result: Constructor called.
Constructor called.
Box2 is equal to or larger than Box1

1.13 STORAGE CLASS:


Storage class defined for a variable determines the accessibility and longevity of the
variable. The accessibility of the variable relates to the portion of the program that has access
to the variable. The longevity of the variable refers to the length of time the variable exists
within the program.

Types of Storage Class Variables in C++:


1. Automatic
2. External
3. Static

Automatic:
Variables defined within the function body are called automatic variables. Auto is the
keyword used to declare automatic variables. By default and without the use of a keyword,
the variables defined inside a function are automatic variables.

For instance:
void exforsys( )
{
auto int x;
auto float y;
...
}
is the same as
30
www.cseitquestions.in

void exforsys( )
{
int x;
float y;

//Automatic Variables

...
}
In the above function, the variable x and y are created only when the function
exforsys( ) is called. An automatic variable is created only when the function is called. When
the function exforsys( ) is called, the variables x and y are allocated memory automatically.

External:
External variables are also called global variables. External variables are defined
outside any function, memory is set aside once it has been declared and remains until the end
of the program. These variables are accessible by any function. This is mainly utilized when a
programmer wants to make use of a variable and access the variable among different function
calls.

Static:
The static automatic variables, as with local variables, are accessible only within the
function in which it is defined. Static automatic variables exist until the program ends in the
same manner as external variables. In order to maintain value between function calls, the
static variable takes its presence.

For example:
#include <iostream.h>
using namespace std;
int exforsys(int);
int exforsys2(int);
void main( )

{
int in;
int out;
while(1)

{
31
www.cseitquestions.in

cout << "nEnter input


value:"; cin>>in;
if (in == 0)
break;
out=exforsys(in);
cout << "nResult : " <<
out; out=exforsys2(in);
cout << "nResult2: " << out;
}
cout << "n End of Program " ;
}
int exforsys(int x)
{
static int
a=0; a++;
return(a);
}
int exforsys2(int x)
{
int b=0;
b++;
return(b);
}
In the above program, the static variables a is initialized only once in the beginning of
the program. Then the value of the variable is maintained between function calls.

1.14 FUNCTION AS ARGUMENTS:


A function pointer (or subroutine pointer or procedure pointer) is a type of pointer
supported by third-generation programming languages Instead of referring to data values, a
function pointer points to executable code within memory. When dereferenced, a function
pointer can be used to invoke the function it points to and pass it arguments just like a normal
function call. Such an invocation is also known as an "indirect" call, because the function is
being invoked indirectly through a variable instead of directly through a fixed name or

32
www.cseitquestions.in

address. Function pointers can be used to simplify code by providing a simple way to select a
function to execute based on run-time values.

#include <iostream.h>
int add(int first, int second)
{
return first + second;
}
int subtract(int first, int second)
{
return first - second;
}
int operation(int first, int second, int (*functocall)(int, int))
{
return (*functocall)(first, second);
}

void main()
{
int a, b;
int (*plus)(int, int) = add;
int (*minus)(int, int) = subtract;
a = operation(7, 5, plus);

b = operation(20, a, minus);
cout << "a = " << a << " and b = " << b <<
endl; }

33
www.cseitquestions.in

UNIT II
OBJECT ORIENTED PROGRAMMING CONCEPTS

String Handling Copy Constructor - Polymorphism compile time and run time
polymorphisms function overloading operators overloading dynamic memory
allocation - Nested classes - Inheritance virtual functions.

2.1 STRING HANDLING:


C++ provides following two types of string representations:

The C-style character string.

The string class type introduced with Standard C++.

2.1.1 The C-Style Character String:


The C-style character string originated within the C language and continues to be
supported within C++. This string is actually a one-dimensional array of characters which is
terminated by a null character '\0'. Thus a null-terminated string contains the characters that
comprise the string followed by a null.
The following declaration and initialization create a string consisting of the word
"Hello". To hold the null character at the end of the array, the size of the character array
containing the string is one more than the number of characters in the word "Hello."
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
If you follow the rule of array initialization, then you can write the above statement as
follows:
char greeting[] = "Hello";
Following is the memory presentation of above defined string in C/C++:

34
www.cseitquestions.in

Actually, you do not place the null character at the end of a string constant. The C++
compiler automatically places the '\0' at the end of the string when it initializes the array.

#include <iostream.h>
int main ()

{
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};

cout << "Greeting message:


"; cout << greeting << endl;
return 0;
}

When the above code is compiled and executed, it produces result something as follows:
Greeting message: Hello

C++ supports a wide range of functions that manipulate null-terminated strings:

strcpy(s1,s2);

Copies string s2 into string s1.


strcat(s1,s2);

Concatenates string s2 onto the end of string s1.


strlen(s1);

Returns the length of string s1.


strcmp(s1,s2);

Returns 0 if s1 and s2 are the same; less than 0 if s1<s2; greater than 0 if s1>s2.
strchr(s1,ch);

Returns a pointer to the first occurrence of character ch in string s1.


strstr(s1,s2);

Returns a pointer to the first occurrence of string s2 in string s1.

Following example makes use of few of the above-mentioned functions:


#include <iostream.h>
#include <cstring.h>
int main ()
35
www.cseitquestions.in

{
char str1[10] = "Hello";
char

str2[10]

"World"; char str3[10];


int len ;
// copy str1 into str3
strcpy( str3, str1);
cout << "strcpy( str3, str1) : " << str3 << endl;
// concatenates str1 and str2
strcat( str1, str2);
cout << "strcat( str1, str2): " << str1 <<
endl; // total lenghth of str1 after
concatenation len = strlen(str1);
cout << "strlen(str1) : " << len << endl;
return 0;
}

When the above code is compiled and executed, it produces result something as follows:
strcpy( str3, str1) : Hello
strcat( str1, str2): HelloWorld
strlen(str1) : 10

2.1.2 The String Class in C++:


The standard C++ library provides a string class type that supports all the operations
mentioned above, additionally much more functionality.
#include <iostream.h>
#include <string.h> int
main ()

{
string str1 = "Hello";
string str2 = "World";
string str3;
int len ;
// copy str1 into str3
36
www.cseitquestions.in

str3 = str1;
cout << "str3 : " << str3 << endl;
// concatenates str1 and
str2 str3 = str1 + str2;
cout << "str1 + str2 : " << str3 << endl;
// total lenghth of str3 after concatenation
len = str3.size();
cout << "str3.size() : " << len << endl;
return 0;
}

When the above code is compiled and executed, it produces result something as follows:
str3 : Hello
str1 + str2 : HelloWorld
str3.size() : 10

2.2 COPY CONSTRUCTOR:


This constructor takes one argument, also called one argument constructor. The main
use of copy constructor is to initialize the objects while in creation, also used to copy an
object. The copy constructor allows the programmer to create a new object from an existing
one by initialization.
For example to invoke a copy constructor the programmer writes:
Exforsys e3(e2);
or
Exforsys e3=e2;
Both the above formats can be sued to invoke a copy constructor.
For Example:
#include <iostream.h>
using namespace std;
class Exforsys
{
private:
37
www.cseitquestions.in

int a;
public:

Exforsys()
{}
Exforsys(int w)
{
a=w;
}
Exforsys(Exforsys& e)
{
a=e.a;
cout << " Example of Copy Constructor";
}
void result()
{
cout<< a;
}
};
void main()
{
Exforsys e1(50);
Exforsys e3(e1);
cout<< "ne3=";
e3.result();

2.3 POLYMORPHISM:
Polymorphism is one of the most important features of Object Oriented Programming.
Polymorphic variables can take up objects or values of different types as values and
polymorphic functions and procedures can be used as objects or values of different types. It
refers to exhibiting different behaviour by an instance in different situations.

Polymorphism is implemented through,


38
www.cseitquestions.in

1. Function overloading
2. Operator overloading.

2.4 COMPILE TIME AND RUNTIME


POLYMORPHISM: Compile time Polymorphism:

Compile time Polymorphism also known as method overloading.

Method overloading means having two or more methods with the same name
but with different signatures.

Run time Polymorphism:

Run time Polymorphism also known as method overriding.

Method overriding means having two or more methods with the same name,
same signature but with different implementation.

Overloading is a form of polymorphism. In case of function overloading, the


information regarding which function is to be invoked corresponding to a function call is
available at compile time. This is referred to as static binding or compile time polymorphism,
as the object is bound with its function call at compile time.

Run time polymorphism is achieved through virtual functions. The function to be


invoked by the instance of a class is known during runtime. The functions are linked with the
class during runtime and not during compile time. When a base class pointer points to a sub
class instance, instead of invoking subclass function (a function having name similar to that
of function of a base class), it always invokes base class version. If the function in the base
class is defined as virtual, then it is known during runtime only, which version of the function
will be invoked, corresponding to a function call. Since the function is linked after
compilation process, it is termed as late binding or dynamic binding or run-time
polymorphism.

2.5 FUNCTION OVERLOADING:


It is also referred to as functional polymorphism. The same function can perform a
wide variety of tasks. The same function can handle different data types. When many
functions with the same name but different argument lists are defined, then the function to be
invoked corresponding to a function call is known during compile time.
39
www.cseitquestions.in

When the source code is compiled, the functions to be invoked are bound to the
compiler during compile time, as to invoke which function depending upon the type and
number of arguments. Such a phenomenon is referred to early binding, static linking or
compile time polymorphism.

For example:
#include <iostream.h>
//function prototype

int multiply(int num1, int num2);


float multiply(float num1, float num2);
void main()
{
//function call statements
int ans1=multiply(4,3);
// first prototype is invoked as arguments
// are of type int
float ans2 = multiply(2.5, 4.5);
//second prototype is
invoked as arguments are of type float
}

The compiler checks for the correct function to be invoked by matching the type of
arguments and the number of arguments including the return type. The errors, if any, are
reported at compile time, hence referred to as compile time polymorphism.

2.6 OPERATOR OVERLOADING:


Operator overloading is a very important feature of Object Oriented Programming.
Curious to know why!!? It is because by using this facility programmer would be able to
create new definitions to existing operators. In other words a single operator can take up
several functions as desired by programmers depending on the argument taken by the
operator by using the operator overloading facility.

Broadly classifying operators are of two types namely:

Unary Operators
Binary Operators

40
www.cseitquestions.in

Unary Operators:
As the name implies, it operates on only one operand. Some unary operators are
named ++ also called the Increment operator, -- also called the Decrement Operator, ! , ~ are
called unary minus.

Binary Operators:
It operates on two operands. Some binary operators are arithmetic operators,
comparison operators, and arithmetic assignment operators.
2.6.1 Operator Overloading - Unary operators
Operator overloading helps the programmer to define a new functionality for the
existing operator. This is done by using the keyword operator.
The general syntax for defining an operator overloading is as follows:
return_type classname :: operator operator_symbol(argument)
{
.
Statements;
}
Operator overloading is defined as a member function by making use of the keyword
operator.
In the above:

return_type - is the data type returned by the function

class name - is the name of the class


operator - is the keyword

operator symbol - is the symbol


of the operator which is being overloaded or
defined for new functionality
:: - is the scope resolution operator which is used to use the function definition
outside the class. The usage of this is clearly defined in our earlier section of How

to define class members.

For example
Suppose we have a class say Exforsys and if the programmer wants to define a
operator overloading for unary operator say ++, the function is defined as,

41
www.cseitquestions.in

Inside the class Exforsys the data type that is returned by the overloaded operator is
defined as,
class Exforsys
{
private:
..
public:
void operator ++();
.
};

The important steps involved in defining an operator overloading in case of unary


operators are:
Inside the class the operator overloaded member function is defined with the return
data type as member function or a friend function. The concept of friend function we will
define in later sections. If in this case of unary operator overloading if the function is a
member function then the number of arguments taken by the operator member function is
none as seen in the below example. In case if the function defined for the operator
overloading is a friend function which we will discuss in later section then it takes one
argument.
The operator overloading is defined as member function outside the class using the
scope resolution operator with the keyword operator.

#include <iostream.h>
using namespace std;
42
www.cseitquestions.in

class Exforsys
{
private:
int x;

public:
Exforsys( ) { x=0; } //Constructor
void display();
void operator ++( );

};

void Exforsys :: display()


{
cout << "nValue of x is: " << x;

void Exforsys :: operator ++( ) //Operator Overloading for operator ++ defined


{
++x;
}

void main( )
{
Exforsys e1,e2; //Object e1 and e2 created
cout << "Before Increment";
cout << "nObject e1: "; e1.display();
cout << "nObject e2: "; e2.display();
++e1; //Operator overloading applied
++e2;
cout << "n After Increment";

cout << "nObject e1: "; e1.display();


cout << "nObject e2: "; e2.display();
}

43
www.cseitquestions.in

In the above example we have created 2 objects e1 and e2 f class Exforsys. The
operator ++ is overloaded and the function is defined outside the class Exforsys.

When the program starts the constructor Exforsys of the class Exforsys initialize the
values as zero and so when the values are displayed for the objects e1 and e2 it is displayed
as zero. When the object ++e1 and ++e2 is called the operator overloading function gets
applied and thus value of x gets incremented for each object separately. So now when the
values are displayed for objects e1 and e2 it is incremented once each and gets printed as one
for each object e1 and e2.

2.6.2 Operator Overloading - Binary Operators


Binary operators, when overloaded, are given new functionality. The function defined
for binary operator overloading, as with unary operator overloading, can be member function
or friend function.
The difference is in the number of arguments used by the function. In the case of
binary operator overloading, when the function is a member function then the number of
arguments used by the operator member function is one (see below example). When the
function defined for the binary operator overloading is a friend function, then it uses two
arguments.
Binary operator overloading, as in unary operator overloading, is performed using a
keyword operator.

Binary operator overloading example:


Sample Code
#include <iostream>
using namespace std;
class Exforsys
{
private:
int x;
int y;

public:

44
www.cseitquestions.in

Exforsys()

//Constructor

{ x=0; y=0; }

void getvalue( )

//Member Function for Inputting Values

{
cout << "n Enter value for x: ";
cin >> x;
cout << "n Enter value for y: ";
cin>> y;
}

void displayvalue( )

//Member Function for Outputting Values

{
cout << "value of x is: " << x << "; value of y is: " << y;

Exforsys operator +(Exforsys);


};
Exforsys Exforsys :: operator + (Exforsys e2)
{
Exforsys rez; //declaring an Exforsys object to retain the final values
int x1 = x+ e2.x;
int y1 = y+e2.y;
rez.x=x1;
rez.y=y1;
return rez;

}
void main( )
{
Exforsys e1,e2,e3;

//Objects e1, e2, e3 created

cout << "nEnter value for Object e1:";


e1.getvalue( );

45
www.cseitquestions.in

cout << "nEnter value for Object e2:";


e2.getvalue( );
e3= e1+ e2; //Binary Overloaded operator used cout <<
"nValue of e1 is: "; e1.displayvalue();
cout << "nValue of e2 is: " ; e2.displayvalue();
cout << "nValue of e3 is: "; e3.displayvalue();

In the above example, the class Exforsys has created three objects e1, e2, e3. The
values are entered for objects e1 and e2. The binary operator overloading for the operator '+'
is declared as a member function inside the class Exforsys. The definition is performed
outside the class Exforsys by using the scope resolution operator and the keyword operator.

e3= e1 + e2; The binary overloaded operator '+' is used. In this statement, the
argument on the left side of the operator '+', e1, is the object of the class Exforsys in which
the binary overloaded operator '+' is a member function. The right side of the operator '+' is
e2. This is passed as an argument to the operator '+' . Since the object e2 is passed as
argument to the operator '+' inside the function defined for binary operator overloading, the
values are accessed as e2.x and e2.y. This is added with e1.x and e1.y, which are accessed
directly as x and y. The return value is of type class Exforsys as defined by the above
example.

There are important things to consider in operator overloading with C++ programming
language. Operator overloading adds new functionality to its existing operators. The
programmer must add proper comments concerning the new functionality of the overloaded
operator. The program will be efficient and readable only if operator overloading is used only
when necessary.

Some Operators that cannot be downloaded:

scope resolution operator denoted by ::

Member access operator or the dot operator denoted by .


The conditional operator denoted by ?:

And pointer to member operator denoted by .*

46
www.cseitquestions.in

2.7 DYNAMIC MEMORY ALLOCATION:


Memory in C++ program is divided into two parts:

The stack:
All variables declared inside the function will take up memory from
the stack.
The heap: This is unused memory of the program
and can be used to allocate the

memory dynamically when program runs.

1. Many times, we are not aware in advance how much memory you will need to store
particular information in a defined variable and the size of required memory can be
determined at run time.
2. We can allocate memory at run time within the heap for the variable of a given type
using a special operator in C++ which returns the address of the space allocated. This
operator is called new operator.

If we are not in need of dynamically allocated memory anymore, you can use delete
operator, which de-allocates memory previously allocated by new operator.

The new and delete operators:


There is following generic syntax to use new operator to allocate memory
dynamically for any data-type.
new data-type;
Here, data-type could be any built-in data type including an array or any user defined
data types include class or structure. Let us start with built-in data types. For example we can
define a pointer to type double and then request that the memory be allocated at execution

time.
We can do this using the new operator with the following
statements: double* pvalue = NULL; // Pointer initialized with null
pvalue = new double; // Request memory for the variable

The memory may not have been allocated successfully, if the free store had been used
up. So it is good practice to check if new operator is returning NULL pointer and take
appropriate action as below:

double* pvalue = NULL;


47
www.cseitquestions.in

if( !(pvalue = new double ))


{
cout << "Error: out of memory."
<<endl; exit(1); }
Example:
#include <iostream.h>
int main ()

{
double* pvalue = NULL; // Pointer initialized with null
pvalue = new double; // Request memory for the variable
*pvalue = 29494.99; // Store value at allocated address
cout << "Value of pvalue : " << *pvalue << endl;
delete pvalue;

// free up the memory.

return 0;
}

If we compile and run above code, this would produce the following result:
Value of pvalue : 29495

Dynamic Memory Allocation for Arrays:


Consider if we want to allocate memory for an array of characters, i.e., string of 20
characters. Using the same syntax what we have used above we can allocate memory
dynamically as shown below.

char* pvalue = NULL; // Pointer initialized with null


pvalue = new char[20]; // Request memory for the variable
To remove the array that we have just created the statement would look like this:
delete [] pvalue; // Delete array pointed to by pvalue

Following the similar generic syntax of new operator, you can allocat for a multidimensional array as follows:

double** pvalue = NULL; // Pointer initialized with null


pvalue = new double [3][4]; // Allocate memory for a 3x4 array
48
www.cseitquestions.in

However, the syntax to release the memory for multi-dimensional array will still
remain same as above:

delete [] pvalue;

// Delete array pointed to by pvalue

Dynamic Memory Allocation for Objects:


Objects are no different from simple data types. For example, consider the following
code where we are going to use an array of objects to clarify the concept:
#include <iostream.h>
class Box

{
public:
Box() {
cout << "Constructor called!" <<endl;
}
~Box() {
cout << "Destructor called!" <<endl;
}
};
int main( )
{
Box* myBoxArray = new Box[4];
delete [] myBoxArray; // Delete array
return 0;
}
If we were to allocate an array of four Box objects, the Simple constructor would be
called four times and similarly while deleting these objects, destructor will also be called
same number of times.

If we compile and run above code, this would produce the following result:

Constructor called!
Constructor called!
49
www.cseitquestions.in

Constructor called!
Constructor called!
Destructor called!
Destructor called!
Destructor called!
Destructor called!

2.8 NESTED CLASSES:

A class that contains the definition of another class called nesting class and the class
inside the nesting class called nested class.
The nesting class can access the data member and function member of a nested class.

Nested classes can directly use names, type names, names of static members, and

enumerators only from the enclosing class. To use names of other class members, you

must use pointers, references, or object names.


The nesting of classes enables building of powerful data structures.

Syntax
class Nesting_Class
{
Public:
Data Members of Nesting Class;
class Nested_Class
{
public:
Data Member of Nested Class
Function Members of Nested
Class }; };
void main()
{
Nesting_class::Nested_class Object;
object.Nested_class Datamember=value;
object.Nested_class Functionmember();

}
50
www.cseitquestions.in

Example:
#include<iostream.h>
#include<conio.h>
class fxclg //Nesting Class
{
public:
class cse

//Nested Class

{
public:
char name[10],dept[5];
int age;
void get()
{
cout<<"Enter Details Name Age Dept:\n";
cin>>name;
cin>>age;
cin>>dept;
cout<<"\n";
}
void put()
{
cout<<"name\t"<<name<<"age:\t"<<age<<"dept:\t"<<dept;
}
};
};
void main()
{
clrscr();
fxclg::cse cs1; //Declaring Object for Nested Class
cs1.get();
cs1.put();
getch();
}

51
www.cseitquestions.in

Output:
Enter Details Name Age Dept:
kumar
24
CSE
name kumar age:

24 dept: CSE

In this example, the class cse (nested class) is defined within the class fxclg(nesting
class),To declare the objects of a nested class we have to follow the procedure, fxclg::cse c1;
Using this object it access the data and function member of nested class cse

2.9 INHERITANCE:
One of the most important concepts in object-oriented programming is that of
inheritance. Inheritance allows us to define a class in terms of another class, which makes it
easier to create and maintain an application. This also provides an opportunity to reuse the
code functionality and fast implementation time.
When creating a class, instead of writing completely new data members and member
functions, the programmer can designate that the new class should inherit the members of an
existing class. This existing class is called the base class, and the new class is referred to as
the derived class.
The idea of inheritance implements the is a relationship. For example, mammal IS-A
animal, dog IS-A mammal hence dog IS-A animal as well and so on.

Base & Derived Classes:


A class can be derived from more than one classes, which means it can inherit data
and functions from multiple base classes. To define a derived class, we use a class derivation
list to specify the base class(es). A class derivation list names one or more base classes and
has the form:
class derived-class: access-specifier base-class
Where access-specifier is one of public, protected, or private, and base-class is the
name of a previously defined class. If the access-specifier is not used, then it is private by
default.
52
www.cseitquestions.in

Type of Inheritance:

Single Inheritance

Multiple Inheritance

Multilevel Inheritance

Hybrid Inheritance

Hierarchical Inheritance

2.9.1 Single Inheritance:

Example:
#include<iostream.h>
#include<conio.h>
class student

{
public:
char name[10],collname[10],dept[5];
void getfun()
{
cout<<"Enter Name,College,Department\n";
cin>>name>>collname>>dept;

}
};

class cse:public student


{
public:
53
www.cseitquestions.in

char sub1[5],sub2[5],sub3[5];
void getdet()
{
getfun();
cout<<"Enter subject 1,2,3";
cin>>sub1>>sub2>>sub3;

}
void putdet()
{
cout<<"Name\t"<<name<<"College name\n"<<collname<<"Department\t"<<dept
<<"Subject 1,2,3\t"<<sub1<<sub2<<sub3;

}
};

void main()
{
clrscr();
cse c1;
c1.getdet();
c1.putdet();
getch();
}

Output:
Enter Name,College,Department
paul
fx
cse

Enter subject 1,2,3


maths
pds
evs
Name paul College name fx Department cse subject 1,2,3 maths pds evs

54
www.cseitquestions.in

2.9.2 Multiple Inheritance

A derived class with several base classes is called multiple inheritance.

Example:
#include<iostream.h>
#include<conio.h>
class student

{
public:
char name[10],collname[10],dept[5];
void getfun()
{
cout<<"Enter name,college name,department\n";
cin>>name>>collname>>dept;

}
};
class internal
{
public:
char sub1[5],sub2[5],sub3[5];
int im1,im2,im3;
void getdet()
{
cout<<"Enter subject 1,2,3\n";
cin>>sub1>>sub2>>sub3;
cout<<"Enter internal marks for subject1,2,3\n";
55
www.cseitquestions.in

cin>>im1>>im2>>im3;
}
};

class cse:public internal,public student


{
public:
int ex1,ex2,ex3,t1,t2,t3;
void calc()

{
getfun();
getdet();
cout<<"Enter external marks for
subject1,2,3\n"; cin>>ex1>>ex2>>ex3;
t1=ex1+im1;
t2=ex2+im2;
t3=ex3+im3;
}
void putdet()
{
cout<<"\nname\t"<<name<<"collname\t"<<collname<<"dept\t"<<dept<<"\n"
<<"sub1 Total\t"<<t1<<"sub2\t"<<t2<<"sub3\t"<<t3<<"\n";
}
};

void main()
{
clrscr();
cse c1;
c1.calc();
c1.putdet();
getch();
}

56
www.cseitquestions.in

Output:
Enter name,college name,department
paul
fx
cse
Enter subject 1,2,3
maths
pds
dbms
Enter internal marks for subject1,2,3
50
50
50
Enter external marks for subject1,2,3
50
50
50
name paul
sub1

Total

collname
100

fx
sub2 100

dept cse
sub3 100

2.9.3 Multilevel Inheritance

The mechanism of deriving a class from another derived class is known as multilevel
inheritance.

57
www.cseitquestions.in

Example:

STUDENT

TEST

RESULT

#include<iostream.h>
#include<conio.h>
#include<iomanip.h>
class student

{
public:
char name[10],clgname[10];
int age,year;
void get()

{
cout<<"Enter the Name,College Name,Age,
Year:\n"; cin>>name>>clgname>>age>>year;
}
void put()
{
cout<<"Name:\t"<<"College
Name:\t"<<"Age:\t" <<"Year:\t"<<"\n";
cout<<name<<"\t"<<clgname<<"\t"<<age<<"\t"<<year<<"\n";
}
};
class test:public student
{
public:
int m1,m2,m3;
void getmarks()

58
www.cseitquestions.in

{
cout<<"Enter mark1,2,3";
cin>>m1>>m2>>m3;
}
void putmarks()
{
cout<<"Mark1:\t"<<"Mark2\t"<<"Mark3\t"<<"\n";
cout<<m1<<"\t"<<m2<<"\t"<<m3<<"\n";
}
};
class result:public test
{
public:
int i1,i2,i3,t1,t2,t3;

void getinternal()
{
cout<<"Enter the internal
marks:"; cin>>i1>>i2>>i3;
}
void finalmark()
{
t1=i1+m1;
t2=i2+m2;
t3=i3+m3;
cout<<"Result M1,M2,M3:";
cout<<"\t"<<t1<<"\t"<<t2<<"\t"<<t3<<"\n";

}
};
void main()
{
clrscr();
result r1;
r1.get();

59
www.cseitquestions.in

r1.getmarks();
r1.getinternal();
r1.put();
r1.putmarks();
r1.finalmark();
getch();
}
In this example the student class is derived into test class and then the test class
further derived into result class. So the result class inherits the properties of both student and
test class.
2.9.4 Hierarchical Inheritance
Hierarchical Inheritance is a method of inheritance where one or more derived classes
are derived from common base class.

Example:
#include <iostream.h>
class Side

{
public:
int l;

void set_values (int x)


{
l=x;
}
};
class Square: public Side
60
www.cseitquestions.in

{
public:
int sq()

{
return (l *l);
}
};
class Cube:public Side
{
public:
int cub()

{
return (l *l*l);
}
};
int main ()
{
Square s;
s.set_values (10);
cout << "The square value is::" << s.sq() <<
endl; Cube c;
c.set_values (20);
cout << "The cube value is::" << c.cub() << endl;
return 0;
}

Output:
The square value is:: 100
The cube value is::8000

In the above example the two derived classes "Square", "Cube" uses a single base
class "Side". Thus two classes are inherited from a single class. This is the hierarchical
inheritance OOP's concept in C++.
61
www.cseitquestions.in

2.9.5 Hybrid Inheritance


Hybrid inheritance is combination of two or more inheritances such as single,
multiple, multilevel.

Example:
#include <iostream.h>
class mm

{
protected:
int rollno;
public:
void get_num(int a)
{
rollno = a;
}
void put_num()
{
cout << "Roll Number Is:"<< rollno << "\n";
}
};
class marks : public mm
{
protected:
int sub1;
int sub2;
public:
void get_marks(int x,int y)

62
www.cseitquestions.in

{
sub1 = x;
sub2 = y;
}
void put_marks(void)
{
cout << "Subject 1:";
cout<< sub1 ;
cout<< "\n";
cout << "Subject 2:";
cout << sub2;
cout << "\n";
}
};
class extra
{
protected:
float e;
public:
void get_extra(float s)
{
e=s;
}
void put_extra(void)
{
cout << "Extra Score::" <<
e; cout<< "\n";
}
};
class res : public marks, public extra
{
protected:
float tot;

63
www.cseitquestions.in

public:
void disp(void)
{
tot = sub1+sub2+e;
put_num();
put_marks();
put_extra();
cout << "Total:"<< tot;
}
};
int main()
{
res std1;
std1.get_num(10);
std1.get_marks(10,20);
std1.get_extra(33.12);
std1.disp();

return 0;
}

Output:
Roll Number Is: 10
Subject 1: 10
Subject 2: 20
Extra score:33.12
Total: 63.12

2.10 VIRTUAL FUNCTIONS:


If there are member functions with same name in base class and derived class, virtual
functions gives programmer capability to call member function of different class by a same
function call depending upon different context. This feature in C++ programming is known
as polymorphism which is one of the important features of OOP.

64
www.cseitquestions.in

If a base class and derived class has same function and if you write code to access that
function using pointer of base class then, the function in the base class is executed even if, the
object of derived class is referenced with that pointer variable.

Example:
#include <iostream.h>
class CPolygon

{
public:
int width, height;
void set_values (int a, int b)
{
width=a; height=b;
}
virtual int area ( )
{
Cout<<Base Class Area of CPolygon;
};
class CRectangle: public CPolygon
{
public:
int area (void)
{
return (width * height);
}
};
class CTriangle: public CPolygon
{
public:
int area ( )
{
return (width * height / 2);
}
65
www.cseitquestions.in

};

void main ()
{
CRectangle rect;
CTriangle trgl;
CPolygon * ppoly1 = &rect;
CPolygon * ppoly2 = &trgl;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
cout << ppoly1->area( ) << endl;
cout << ppoly2->area( ) << endl;
}

Output:
20
10
In this example class CPolygon includes a virtual function area( ). In this function we
included the cout statement. When the base class pointer have derived class object and if the
pointer points the function area() then the base class area() function is overloaded with the
derived class function area().

66
www.cseitquestions.in

UNIT III
C++ PROGRAMMING ADVANCED FEATURES

Abstract class Exception handling - Standard libraries - Generic Programming templates class template - function template STL containers iterators function
adaptors allocators -Parameterizing the class - File handling concepts.

3.1 ABSTRACT CLASS


The purpose of an abstract class (often referred to as an ABC) is to provide an
appropriate base class from which other classes can inherit. Abstract classes cannot be used
to instantiate objects and serves only as an interface. Attempting to instantiate an object of an
abstract class causes a compilation error. Thus, if a subclass of an ABC needs to be
instantiated, it has to implement each of the virtual functions, which means that it supports
the interface declared by the ABC. Failure to override a pure virtual function in a derived
class, then attempting to instantiate objects of that class, is a compilation error. Classes that
can be used to instantiate objects are called concrete classes.

3.2 EXCEPTION HANDLING


An exception is any unusual event, either erroneous or not, detectable by either
hardware or software, that may require special processing.

WITHOUT EXCEPTION HANDLING

WITH EXCEPTION HANDLING

When an exception occurs, control goes to the

operating system, where typically

Programs are allowed to trap


exceptions.

an error message is displayed


the program is terminated

There is a possibility to fix the


problem and continuing execution

Exception handling mechanism


To detect and report error, The error handling code performs the following task
1. Find the problem (Hit the exception)
2. Inform that an error has occurred. (Throw the exception)
3. Receive the error information. (Catch the exception)

67
www.cseitquestions.in

4. Take corrective actions. (Handle the exception).


Keywords in Exception Handling

try

throw

catch

TRY BLOCK -The keyword try is used to preface a block of statements


(surrounded by braces) which may generate exceptions.
->When an exception is detected, it is thrown using a throw statement in the try block.
CATCH BLOCK - defined by the keyword catch catches the exception thrown
by the throw statement in the try block, and handles it appropriately.

Exception Handling Syntax:


try

//try block

{
.
throw exception;

// Block of statements which detects and throws an exception

68
www.cseitquestions.in

}
catch(type arg) // Catches exception
{
.
.. // Block of statements that handles the exception
}

Example:
#include <iostream>
int main()
cout << start;
try
{

// start

a try block cout << Inside try


block\n;
throw 100;

// throw an error

cout << This will not execute;


}
catch (int i)
{

// catch an error

cout << caught an exception


; cout << i ; cout << End;
return 0;
}
}

Exception Types
Synchronous Exception:

Out of range

Over flow

Asynchronous Exception

Error that are caused beyond the control of the program

Keyboard interrupts
69
www.cseitquestions.in

In C++ only synchronous exception can be handled.

Factors determining Exception

Division by zero

Access to an array outside of its bounds

Running out of memory

Running out of disk space

Need for Exception Handling


Dividing the error handling

Unconditional termination & programmer preferred termination

Separating error reporting and error handling

Object destroy problem

#include<iostream.h>

catch( int a)

int main()

{ // catch an error

cout << "The Number Caught is : ";


int i,j;

cout << a << "\n";

cout << "Starts here\n"; i=10;

j=0;

cout << "Ends here";

try

return 0;

// start a try block


cout << "Inside try block\n";
if(j==0)
{
throw j; // throw an error
cout << "This will not be printed \n"; }
cout<<RESULT IS <<i/j;
}

When the program enters the try block it is said to be in the guarded section.

In this program when the value of j is zero an exception is created and thrown.
70
www.cseitquestions.in

Note that the statement after throw statement in try block is not executed.

Once the exception is thrown the catch block catches the value (here zero) and
handles it.

After that the program continues its normal execution.

Functions Generating Exceptions


C++ allows functions to generate exceptions. These functions cannot be called as an ordinary
function. Enclose the function call with a try catch block.
Syntax:
try
{ function(arg);
}
catch(type arg)
{
-----}

#include<iostream.h>

void main()

void compute(int a,int b)

int x,y;
cout<<ENTERTWONUMBERS;

int c; if(b==0)
{

cin>>x>y;
throw b;

try

else

c=a/b;

compute(x/y); // fun generating exception

cout<<RESULT OF THE DIVISION<<c;

catch(int k)

{
cout<<Divide By Zero exception;
}
}

71
www.cseitquestions.in

Throwing Mechanisms:

An exception is thrown by using the throw keyword from inside the try block.

A throw expression accepts one parameter, which is passed as an argument to the


exception handler.
Eg. throw b;
The throw statement will have the following.
Example:

throw (exception)

throw exception

throw

Catching Mechanisms

If the data type specified by a catch, matches that of the exception, then catch
statement is executed.

When an exception is caught, arg will receive its value

Multiple Catch Statements

A try can have multiple


catches

If there are multiple catches for a try, only one of the matching catch is selected and
that corresponding catch block is executed.

Syntax:
try
{
any statements
if (some condition) throw
value1; else if (some other
condition) throw value2;
else if (some last
condition) throw valueN;
}
catch (type1 name)
72
www.cseitquestions.in

{
any statements
}
catch (type2 name)
{
any statements
}
catch (typeN name)
{
any statements
}

Example:
#include<iostream.h>
void multiple_catch(int value)
{
try
{
if (value==0) //throw an int value
throw 1;
else if (value==1) //throw a char
throw a;
else //throw float
throw 1.1;
}
catch(char c)
{
cout<<Character value is thrown <<c;
}
catch(int i)
{
cout<<Integer value is thrown<<i;
}
catch(float f)
73
www.cseitquestions.in

{
cout<<Float value is thrown<<f;
}
}
void main()
{
cout<<Main Program<<endl;
multiple_catch(0);
multiple_catch(1);
multiple_catch(5);

Rethrowing Exceptions
Syntax:
try
{
.
throw a;

}
catch (char c)
{
throw;

//rethrow same exception in catch block in main()

Example:
#include <iostream.h>
class sam
{
int erno;
public:
sam (int errno)
{
exno=errno;
}
74
www.cseitquestions.in

void shoex()
{
cout<<error no:<<exno;
}
};
void ergen()
{
try
{
sam
s1(20); int
c; cin>>c;
switch (c)
{
case 1:
throw 10;
case 2:
throw a;
case 3:
throw s1;
case 4:

throw welcome;
}
catch (int ie)
{
cout<<ie<<ie;
throw; //rethrowing

}
catch (char ce)
{
cout <<ce<<ce;
throw; //rethrowing

}
}
75
www.cseitquestions.in

void main ()
{
try
{
ergen();
throw 10;

}
catch (int)
{
cout <<caught integer;
}
catch(char)
{
cout<<caught char;
}
catch (sam s2)
{
s2.show x();
}

Terminate Function
Terminate () is the function which calls abort() to exit the program in the event of run time
error related to exceptions. The user can provide his or her own terminate function instead of
built-in terminate.
Use:
Used to close all open files & deallocate resources before quitting the program.
Syntax: set_terminate (myterminate);

Unexpected Function

If a function throws an exception which is not allowed, a function unexpected


() is called, which in turn calls abort.

We can use set_unexpected in a similar to set_terminate Syntax:


set_unexcepted(my unexcepted);

76
www.cseitquestions.in

Example:
#include <iostream.h>
void myunexpected ()

{
cout << "unexpected called\n";
throw 0; // throws int (in exception-specification)
}
void myfunction
() throw (int)

{
throw 'x'; // throws char (not in exception-specification)
}
int main (void)
{
set_unexpected (myunexpected);
try
{
myfunction();
}
catch (int)
{
cout << "caught int\n";
}
catch (...)
{
cout << "caught some other exception type\n";
}
return 0;
}

Uncaught Exception()

This function returns true if an exception has been thrown but not yet caught.

Once caught, the function returns false.

77
www.cseitquestions.in

Syntax:
bool
uncaught_exceptions.
if
(uncaught_exception(

))
{
//Do not call the function which might throw an exception
}
Otherwise
{
Follow the natural sequence of the destructor Algorithm
}

3.3 STANDARD LIBRARIES:


Streams and Formatted I/O :

A stream is a sequence of bytes (or) conceptually pipe like constructs used for
providing I/O.

Streams provide consistent interface for providing independence from having different
operations for different IO devices.

The source stream that provides data to the program is called the input stream.

The destination stream that receives output from the program is called the output
stream.

C++ STREAM CLASSES:


ios :

It is the base class for istream and ostream.

It is declared as the virtual base class.

It provides the basic support for formatted and unformatted I/O operations.

istream:

Provides facilities for formatted and unformatted input operations.

Functions such as getc(),getline(),read() are declared.

Overloaded extraction operator (>>)


78
www.cseitquestions.in

ostream:

Provides the facilities for formatted and unformatted output operations.

Putc() and write() functions are declared.

Overloaded insertion operator (<<)

streambuf:

It is used to access streams using lower level functions.

Provides an interface to physical devices through buffers.

Acts as a base class for filebuf class.

iostream:

Provides facilities for handling both input and output streams.

Inherits the properties of ios, istream and ostream through multiple inheritance.

UNFORMATTED I/O OPERATIONS:


Overloaded operators >> and << :

The >> operator is overloaded in the istream.

The << operator is overloaded in the ostream.


cin>>variable 1>>.>>variable n ;

The input data are separated by white spaces and should match the type of variable in
cin. cout<<variable 1<<.<<variable n;
This statement is used for displaying data on the screen.
putc() and getc() functions :

getc() and putc() are used for reading and writing to the streams.

The getc() function has two different versions


: 1. void get(char) 2. char get(void)

The put() function is used to display the data.

Get() reads a character at a time from the input stream and put() writes a character at a
time to the output stream.

getline, read and write functions :

These functions are used for reading and writing strings.

The prototypes for these three functions are :

cin.getline(string variable , int size);


cin.read(string variable, int size);
cin.write(string variable,int size);

79
www.cseitquestions.in

The difference between getline() and read() is that : getline() terminates when a new
line is entered but read() does not stop when a new line is encountered.

read() stops only when end of file (ctrl + z ) is encountered.

The getline() also stops reading from input if end of file is specified.

FORMATTED I/O OPERATIONS:


1. width() :

it specifies the width for display.


it is used in aligning vertical columns.

2. precision() :

it specifies
the precision of the floating point
number.
default precision is six digits after the decimal

point.
3. fill() :

specifies
the character for filling up the unused portion of
field.
it is used with width().

4. setf() :

The function specifies format flags that control output display like
left (or) right or right
justification, padding, scientific notation, displaying base number.

5. unsetf():

It provides undo operation for the above mentioned operations.

MANIPULATORS:

Manipulators are special functions for formatting.

The choice between manipulators and ios functions to solve formatting problems
sometimes depends on the preference of the user.

Manipulators:

setw()

setprecison()
setfill()

setiosflags()

80
www.cseitquestions.in

resetiosflags()
Characteristics of manipulators:

Writing our own manipulators is possible.

Manipulators are
easy to write and produce more readable codes and make the
program short.
They need iostream.h and iomanip.h files.

When a manipulator
does not take any arguments , it is passed without the ()

parenthesis.
Some manipulators are needed in pairs to produce the toggle effect.

They are non-member-functions.


Characteristics of ios functions:

They are single and cannot be combined to have multiple effects.


They need iostream.h file

ios functions are member functions.


The functions do not return the previous status.

3.4 GENERIC PROGRAMMING:


Generic programming means that you are not writing source code that is compiled as-is but that yo
collection of other objects. But there's much more to generic programming. In the context of
C++ .it means to write programs that are evaluated at compile time.

A basic example of generic programming are templates of containers: In a statically


typed language like C++ you would have to declare separate containers that hold integers,
floats, and other types or deal with pointers to void and therefore losing all type information.

Templates which are the C++ way of generic programming leverage this constraint by
letting you define classes where one or more parameters are unspecified at the time you define
the class. When you instance the template later you tell the compiler which type it should use
to create the class out of the template.

Example: template<typename
T> class MyContainer
{
// Container that deals with an arbitrary type T
81
www.cseitquestions.in

};
void main()
{
// Make MyContainer take just ints.
MyContainer<int> intContainer;

3.5 TEMPLATES:

A significant benefit of object oriented programming is reusability of code which


eliminates redundant coding.

An important feature of oops called Templates makes this benefit stronger and
provides the greater flexibility to the languages.

A template allows the construction of family of functions and classes to perform the
same operation on different types.

This provides the generic programming which allows developing the reusable software
component such as classes and function.

There are two types of templates.

Function templates
Class templates

Terms which means use the same function or class for different purpose without
changing their basic meaning where the function or class should be defined only once.

Templates are used to achieve reusability which eliminates redundant code.

3.6 CLASS TEMPLATES:


Class templates are used to create generic class witch support different data types.

Syntax:
template <class T>
class <class_name>

{
Member;
Member function;
};
82
www.cseitquestions.in

Example:
#include<iostream.h>
#include<conio.h>
template

<class

T> class complex


{
T real, image;
public:

void getdata()
{
cout<<"\n Enter the complex
values"; cin>>real>>image;
}
void putdata()
{
if(image>0)
cout<<real<<"+"<<image<<"i";PLUS.
else cout<<real<<image<"i";

}
;
void main()
{
clrscr();
complex <int> obj1;
obj1.getdata();
obj1.putdata();
complex <float>
obj2; obj2.getdata();
obj2.putdata();
getch();
}

83
www.cseitquestions.in

3.7 FUNCTION TEMPLATES:


The template declared for function is function template. Function templates are generic
function, which work for any data that is passed to them. The data type is not specified while
declaring the function. It performs appropriate operation depending on the data type we
passed to them.

Syntax:
Template<typename T ,.>
Return Type Function-name(argument)
{
Function body
}

Example:
Template < class T>
void generic Bubblesort(T Temp GenericArray[]) // template function
1{
for( int i=0;i<5; i++)
{
for( int j=i+1;j<5;j++)
{
if(TempGenericArray[i]<TempGenericArray[j])
{
int temp=TempGenericArray[i];
TempGenericArray[i]=TempGenericArray[j];
TempGenericArray[j]=temp;
}
}
Template <class T>
void Generic Display(T TempGenericArray[]) // template function2
{
cout<<\n;
for(int i=0;i<5;i++)
{
84
www.cseitquestions.in

cout<<TempGenericArray[i]<<\t;
}
}
void main()
{
int Array1[]={1,4,6,2,6};
GenericBubbleSort(Array 1);

//calling function template 1

GenericDisplay(Array2);

// calling function template 2

Char Array2[]=sdfla;
GenaricBubbleSort(Array2)

//calling function template 1

Generic Display(Array 2);


Foat Array3[]={ 7.0,9.4,5.2,2.5,0.5);
GenericBubble Sort (Array 3);
GenericBubbleSort( Array3 );

// calling function template 1


// calling function template 2

Sample output:
6

9.4

5.2

2.5

0.5

FUNCTION TEMPLATES WITH MULTIPLE ARGUMENTS:


Function templates can have different data type to represent the parameters.
Syntax:
template <class T1, class T2>
return_type function_name(arguments)

{
<function body>
}

Example:
#include<iostream.h>
#include<conio.h>
template <class T1, class T2>
85
www.cseitquestions.in

void display(T1 a, T2 b)
{
cout<<a<<"\n"<<b<<"\n";
}
void main()
{
clrscr();
void display(T1,T2);
display("sample","program");
display(10,20); display(7.5,2);
display(10.75,10.256); getch()

3.8 STANDARD TEMPLATE LIBRARY:


STL is collection C++ libraries that allow you to use several well known kinds of data
structures without having to program them. They are designed so that the code runs
efficiently.
The compiler does most of the work of generating the efficient implementations. The
libraries include a large number of possibilities.

The STL contains three components.

Containers

o A Container is an object that stores other objects (its elements), and that has
methods for accessing its elements.
Algorithms

o An algorithm is a procedure that is used to process the data contained in the


containers. The STL includes many different kinds of algorithms to provide
support to tasks such as initializing, searching, copying, and sorting and
merging

Iterators

o Iterators are a generalization of pointers: they are objects that point to other
objects.
86
www.cseitquestions.in

3.9 CONTAINERS:
A Container is an object that stores other objects (its elements), and that has methods
for accessing its elements. It is a way data is organized in memory. The STL containers are
implemented by template classes and therefore can be easily customized to hold different
types of data.

The STL contains three types of containers

Sequence containers

Associative containers

Derived containers

Sequence Containers:
Sequence containers store elements in a linear sequence, like a line. Each element is
related to other elements by its position along the line. They all expand themselves to allow
insertion of elements and all of them support a number of operations on them.

The following are the types of sequence containers.


Vector
List

deque

Element0

Element1

Element2

Last Element

Associative Containers:
Associative containers are designed to support direct access to elements using keys.

The following are the types of associative containers.

Set

Multiset
Map

Multimap

87
www.cseitquestions.in

Derived Containers:
The derived containers do not support iterators and therefore we cannot use them for
data manipulation. They support two member functions pop() and push() for implementing
deleting and inserting operations.

The following are the types of associative containers.

Stack
Queue

Priority_queue

3.10 ITERATORS:
An iterator is an object that points to an element in a container. We can use iterators
to move through the contents of containers. Iterators are handled just like pointers.
Iterators are classified into five categories depending on the functionality they
implement:

Input
Output
Forward
Bidirectional
Random Access

Input and output:


Input and Output iterators are the most limited types of iterators: they can perform
sequential single-pass input or output operations.
Forward:
Forward iterators have all the functionality of input iterators and if they are not
constant iterators also the functionality of output iterators, although they are limited to one
direction in which to iterate through a range (forward). All standard containers support at
least forward iterator types.
Bidirectional:
Bidirectional iterators are like forward iterators but can also be iterated through
backwards.
88
www.cseitquestions.in

Random Access:
Random-access iterators implement all the functionality of bidirectional iterators, and
also have the ability to access ranges non-sequentially: distant elements can be accessed
directly by applying an offset value to an iterator without iterating through all the elements in
between. These iterators have a similar functionality to standard pointers (pointers are
iterators of this category).

3.11 FUNCTION ADAPTORS:


In the context of the C++ programming language, functional refers to a header file
that is part of the C++ Standard Library and provides a number of predefined class templates
for function objects, including arithmetic operations, comparisons, and logical operations.
Instances of these class templates are C++ classes that define a function call operator, and the
instances of these classes can be called as if they were functions. It is possible to perform
very sophisticated operations without actually writing a new function object, simply by
combining predefined function objects and function object adaptors.
Negators:
The negators not1 and not2 are functions which take a unary and a binary predicate,
respectively, and return their complements.
template <class Predicate>
unary_negate<Predicate> not1(const Predicate& pred)
{
return unary_negate<Predicate>(pred);
}
template <class Predicate>
binary_negate<Predicate> not2(const Predicate& pred)
{
return binary_negate<Predicate>(pred);
}

The classes unary_negate and binary_negate only work with function object classes
which

have

argument

types

and

result

type

defined.

That

means,

Predicate::argument_type and Predicate::result_type for unary function objects and

89
www.cseitquestions.in

that

Predicate::first_argument_type, Predicate::second_argument_type and Predicate::result_type


for binary function objects must be accessible to instantiate the negator classes.

vector<int> v;
// fill v with 1 2 3 4
sort (v.begin(), v.end(), not2 (less_equal<int>()) );
Output: 4 3 2 1

Binders:
"The binders bind1st and bind2nd take a function object f of two arguments and a
value x and return a function object of one argument constructed out of f with the first or
second argument correspondingly bound to x.", Imagine that there is a container and you
want to replace all elements less than a certain bound with this bound.

vector<int> v;
// fill v with 4 6 10 3 13 2
int bound = 5;
replace_if (v.begin(), v.end(), bind2nd (less<int>(), bound), bound);
// v: 5 6 10 5 13 5

bind2nd returns a unary function object less that takes only one argument, because the
second argument has previously been bound to the value bound. When the function object is
applied to a dereferenced iterator i, the comparison *i < bound is done by the function-call
operator of less.

Adaptors for pointers to functions:


The STL algorithms and adaptors are designed to take function objects as arguments.
If a usual C++ function shall be used, it has to be wrapped in a function object.
The function ptr_fun takes a unary or a binary function and returns the corresponding
function object. The function-call operator of these function objects simply calls the function
with the arguments provided.
For example, if a vector of character pointers is to be sorted lexicographically with
respect to the character arrays pointed to, the binary C++ function strcmp can be transformed
into a comparison object and can so be used for sorting.
90
www.cseitquestions.in

vector<char*> v;
char* c1 = new char[20]; strcpy (c1, "Tim");
char* c2 = new char[20]; strcpy (c2, "Charles");
char* c3 = new char[20]; strcpy (c3, "Aaron");

v.push_back (c1); v.push_back (c2); v.push_back (c3);


sort (v.begin(), v.end(), ptr_fun (strcmp) );
copy (v.begin(), v.end(), ostream_iterator<char*> (cout, " ") );

3.12 ALLOCATORS:
In C++ computer programming, allocators are an important component of the C++
Standard Library. The standard library provides several data structures, such as list and set,
commonly referred to as containers. A common trait among these containers is their ability to
change size during the execution of the program. It encapsulates a memory allocation and
deallocation strategy.

Every standard library component that may need to allocate or release storage, from
std::string, std::vector, and every container except std::array, to std::shared_ptr and
std::function, does so through an Allocator: an object of a class type that satisfies the
following requirements.
Requirements

A, an Allocator type for type T

a, an object of type A

B, the corresponding Allocator type for type U (as obtained by rebinding A)

ptr, a value of type allocator_traits<A>::pointer, obtained by


calling allocator_traits<A>::allocate()

cptr, a value of type allocator_traits<A>::const_pointer, obtained by conversion


from ptr

vptr, a value of type allocator_traits<A>::void_pointer, obtained by conversion from


ptr

cvptr, a value of type allocator_traits<A>::const_void_pointer, obtained by


conversion from cptr or from vptr
91
www.cseitquestions.in

xptr, a dereferencable pointer to some type X

Some requirements are optional: the template std::allocator_traits supplies the default
implementations for all optional requirements, and all standard library containers and other
allocator-aware classes access the allocator through
, not directly.
std::allocator_traits

3.13 PARAMETERIZING THE CLASSES:


A template can be used as a family of classes or functions. It can be considered as a
macro. When an object of a specific type is defined for actual use, the template definition for
that class is substituted with the required data type. Since a template is defined with a
parameter that would be replaced by a specified data type at the time of actual use of the class
or function, the templates are sometimes called parameterized classes or functions.
We can use more than one generic data type in a class template. They are declared
as a comma separated list within the template specification.
Syntax:
template<class T1, class
T2,..> class classname
{
.
..
(Body of the class)

};

3.14 FILE HANDLING CONCEPTS:


OS is the primary interface between the user and the computer. Device driver is a
small program that comes with every device IO operations are performed with the help of
the OS and the device driver. A C++ program does not directly request to the OS. It invokes
a function from a standard library that comes with a C++ compiler, when it is installed.

Text and Binary Files:


Text stream:

deals with information which is in ASCII form.

if <enter> key is pressed, Carriage return and Line Feed characters are inserted. This

92
www.cseitquestions.in

is known as conversion. The text stream files can be opened by any editor. Text files
are more general.

Binary streams:

binary values are inserted


no conversion takes place.

The binary stream files are restricted to the application that creates the file. Binary files are
not flexible.
Dealing With Text Files:

ifstream < filename> - read only file

ofstream <filename>

- output /write only file

fstream <file name > - both input/read and output /write file.

Manipulating Files Opening Files:


Files can be opened using two methods
(i) using constructors (ii)
using open functions

File Modes:
When a file is opened, it must be specified how it is to be opened. This means
whether to create it from new or overwrite it and whether it's text or binary, read or write and
if the content is to be appended to it.
In order to open a file with a stream object open() member function is used.
open (filename, mode);
ios::ate
Write all output to the end of file (even if file position pointer is moved with seekp)
ios::app
Open a file for output and move to the end of the existing data (normally used to
append data to a file, but data can be written anywhere in the file
ios::in
The original file (if it exists) will not be truncated
ios::out
Open a file for output (default for ofstream objects)
93
www.cseitquestions.in

ios::trunc
Discard the file's contents if it exists (this is also the default action for ios::out, if
ios::ate, ios::app, or ios::in are not specified)
ios::binary
Opens the file in binary mode (the default is text mode)
ios::nocreate
Open fails if the file does not exist
ios::noreplace
Open files if the file already exists.

Inserting data somewhere in a sequential file would require that the entire file be
rewritten. It is possible, however, to add data to the end of a file without rewriting the file.
Adding data to the end of an existing file is called appending.
fout.open("filename.dat", ios::app) //open file for appending

Program to append to the contents of a file


#include <iostream.h>
#include <fstream.h>
int main(void)

{
string name, dummy;
int number, i, age;
ofstream fout;

cout<<"How many names do you want to


add?"; cin>>number;
getline (cin,dummy);
fout.open ("name_age.dat",ios::app); // open file for appending
assert (!fout.fail( ));
for(i=1, i<=number; i++)
{
cout<<"Enter the name: ";
getline(cin,name);
cout<<"Enter age: ";
cin>>age;
94
www.cseitquestions.in

getline(cin,age);
fout<<name<<endl; //send to file
fout<<age<<endl;
}
fout.close( ); //close file
assert(!fout.fail( ));
return 0;
}

Random Access:

In C++ , there are two types of file pointers to access a file in a random manner.
For a file in the read mode seekg (pointer for reading or getting)
For a file in the write mode seekp(pointer for wrioting or putting)

Using these, it is possible to search any record of any file by skipping the other
records inbetween.

seekg() and seekp():

seekg() to move get or read pointer of file.


It takes two arguments ,

number of bytes to skip


from where to skip

seekp() to move put and write pointers.

tellg() and tellp():


These pointers tell us where the read and write pointers of a file are pointing to.

tellg() tells us where the get pointer is pointing to.


tellp() tells us where the put pointer is pointing to.

Example:
#include"stdafx.h"
#include<iostream>
#include<fstream>
struct record
{
95
www.cseitquestions.in

char code[6];
char name[20];
int i;
}r;
int main()
{
std::fstream file("Temp.dat",std::ios::trunc|std::ios::in|std::ios::out|std::ios::binary);
if(!file)
{
std::cout<<"unable to open
file"; exit(0);
}
std::cout<<"enter character code, name and an
int\n"; std::cin.getline(r.code,6);
std::cin.getline(r.name,20);
std::cin>>r.i;
file.write((char *)&r,sizeof(r));
std::cout<<"\n\n"<<file.tellg()<<'\n'<<file.tellp();
file.seekg(3);
std::cout<<"\n\n"<<file.tellg()<<'\n'<<file.tellp();
file.seekp(5);
std::cout<<"\n\n"<<file.tellg()<<'\n'<<file.tellp();
}

96
www.cseitquestions.in

UNIT IV
ADVANCED NON-LINEAR DATA STRUCTURES

AVL trees B-Trees Red-Black trees Splay trees - Binomial Heaps Fibonacci
Heaps Disjoint Sets Amortized Analysis accounting method potential method
aggregate analysis.

TREE INTRODUCTION
Tree
A tree is a collection of nodes. The collection can be empty; otherwise a tree consists
of a specially designed node called root, and one or more non empty sub trees T1, T2, ,
Tk, each of whose roots are connected by a directed edge from root.

Fig: Generic tree

Fig: A tree
Root
The root is the first and top most nodes in the hierarchical arrangement of data items.
A node which does not have a parent node is called root node. In the above tree, the root is
A.
Node
Each data item present in the tree is called a node. It is the basic data structures that
specifies the data information and have links to other data items. Example node A, B, ..,,
Q.
Leaf
A node which doesnt have children is called leaf or Terminal node. In the above
tree B, C, H, I, K, L, M, N, P, Q are leaf node.
97
www.cseitquestions.in

Siblings
Children of the same parents are said to be siblings. In the above tree B, C, D, E, F ,G
are siblings, I,J are siblings, K, L, M are siblings, P, Q are siblings.
Path
A path from node n1 to nk is defined as a sequence of nodes n1, n2, . . . , nk such that
ni is the parent of ni+1 for 1 <= i <= k.
There is exactly only one path from the root to each node. In the above tree the path
from A to P is A, E, J, P. Where A is the parent for E, E is the parent of J, and J is the parent
of P.
Length
The length is defined as the number of edges on the path. The length for the path A to
P is 3.
Degree
i. Degree of a node
The number of sub trees of a node is called its degree. In the above tree, degree of A
is 6, degree of F is 3, and degree of B is 0.
ii. Degree of a tree
The degree of the tree is the maximum degree of any node in the tree. In the above
tree, the degree of the tree is 6.
Level
The level of a node is defined by initially letting the root be at level one. If a node is
at level L then its children are at level L+1.
In the previous tree, the level of A is 1, level of B, C, D, E, F, G is 2, level of H, I, J,
K, L, M, N is 3, and the level of P, Q is 4.
Depth
For any node n, the depth of n is the length of the unique path from root to n. For
example, the depth of root A is 0, depth of c is 1, depth of H is 2, and the depth of P is 3
Height
For any node n, the heig ht of the node n is the length of the longest path from n to the
leaf. The height of the leaf is zero. For example, the height of node F is 1, and the height of
E is 2.
Note

The height of the tree is equal to the height of the root.


Depth of the tree is equal to the height of the tree.

98
www.cseitquestions.in

Terminal node
A node with degree zero is called a terminal node. Leaf is called the terminal node
because it has the degree 0. In the previous tree node B, C, H, I, K, L, M, N, P, Q are
terminal nodes.
Non Terminal Node
Any node whose degree is non zero is called Non Terminal node. In the previous
tree node A, D, E, F, G, J are non terminal nodes.
Edge
An edge is a condition line which connects two adjacent node of a tree. The line
drawn from one node to another node is called edge. If a tree has N nodes, then there are N1 edges. For example, the previous tree has 13 nodes and 12 edges.
Interior node
A node is said to be an interior node only if it is between root and leaves. All non
terminal nodes except the root is called interior node. For example, D, E, F, G, J are interior
nodes.
Ancestor node
A node is said to be an ancestor of another node only if it is the parent of that node or
the parent of same ancestor of that node. For example, the ancestor of node H are A and D,
and the ancestor of node F is A.
Descendent node
A node is said to be a descendent of another node if it is the child of that node or the
child of some other descendent of that node. For example, the descendent of F are K, L, M,
and the descendent of E are I, J, P, Q.
Forest
A forest is a set of disjoint trees. If the root is removed, then each node becomes a
separate tree to become a forest.

Implementation of Trees
One way to implement a tree would be to have in each node, besides its data, a pointer
to each child of the node. However, since the number of children per node can vary so greatly
and is not known in advance, it might be infeasible to make the children direct links in the
data structure, because there would be too much wasted space. The solution is simple: Keep
the children of each node in a linked list of tree nodes.
typedef struct tree_node *tree_ptr;
99
www.cseitquestions.in

struct tree_node
{
element_type element;
tree_ptr first_child;
tree_ptr next_sibling;
};

Figure: First child/next sibling representation of the tree


In the above fig, arrows that point downward are first_child pointers. Arrows that go left
to right are next_sibling pointers.

Tree Traversals
Tree traversal is a method for visiting all the nodes in the tree exactly once. There are
three types of tree traversal techniques, they are
i.

Inorder Traversal

ii.

Preorder Traversal

iii.

Postorder Traversal

Inorder Traversal

The inorder traversal of a binary tree is performed as


Traverse the left subtree in inorder
Visit the root

Traverse the right subtree in inorder.

Recursive routine for inorder traversal


void inorder(Tree T)
{
if(T!=NULL)
{
inorder(T->left);
printElement(T->Element);
100
www.cseitquestions.in

inorder(T->right);
}
}
Preorder Traversal

The preorder traversal of a binary tree is performed as


Visit the root

The left subtree in preorder

Traverse the right subtree in preorder.

Recursive routine for preorder traversal


void preorder(Tree T)
{
if(T!=NULL)
{
printElement(T>Element); preorder(T>left); preorder(T->right);
}
}
Postorder Traversal

The postorder traversal of a binary tree is performed as


Traverse the left subtree in postorder
Traverse the right subtree in postorder.
Visit the root

Recursive routine for postorder traversal


void postorder(Tree T)
{
if(T!=NULL)
{
postorder(T->left);
postorder(T->right);
printElement(T->Element);
}
}

101
www.cseitquestions.in

Example

Inorder :

Preorder:

Postorder:

Binary Tree ADT


A binary tree is a tree in which no node can have more than two children. The
maximum degree of any node is two. This means the degree of a binary tree is either zero or
one or two.

In the above fig., the binary tree consists of a root and two sub trees Tl & Tr. All
nodes to the left of the binary tree are referred as left subtrees and all nodes to the right of a
binary tree are referred to as right subtrees.
Implementation
A binary tree has at most two children; we can keep direct pointers to them. The
declaration of tree nodes is similar in structure to that for doubly linked lists, in that a node is
a structure consisting of the key information plus two pointers (left and right) to other nodes.
Binary Tree node declaration
typedef struct tree_node
*tree_ptr; struct tree_node
{
element_type element;
102
www.cseitquestions.in

tree_ptr left;
tree_ptr
right; };
typedef tree_ptr TREE;
Types of Binary Tree
i.

Strictly binary tree


Strictly binary tree is a binary tree where all the nodes will have either zero or
two children. It does not have one child in any node.

ii.

Skew tree
A skew tree is a binary tree in which every node except the leaf has only one
child node. There are two types of skew tree, they are left skewed binary tree and
right skewed binary tree.
Left skewed binary tree
A left skew tree has node with only the left child. It is a binary tree with only
left subtrees.
Right skewed binary tree
A right skew tree has node with only the right child. It is a binary tree with
only right subtrees.
A
A
B

B
C

Fig: Left skew tree

Fig: Right skew tree


103
www.cseitquestions.in

iii.

Full binary tree or proper binary tree


A binary tree is a full binary tree if all leaves are at the same level and every
non leaf node has exactly two children and it should contain maximum possible
h+1

number of nodes in all levels. A full binary tree of height h has 2

1 nodes.

A
B
C

iv.

Complete binary tree


Every non leaf node has exactly two children but all leaves are not necessary
at the same level. A complete binary tree is one where all levels have the maximum
number of nodes except the last level. The last level elements should be filled from
A

left to right.
B

v.

C
F

Almost complete binary tree


An almost complete binary tree is a tree in which each node that has a right
child also has a left child. Having a left child does not require a node to have a right
child.
A
B

C
E

104
www.cseitquestions.in

Comparison between General Tree and Binary Tree


Sl. No
1.

2.

General Tree

Binary Tree

General tree has any number of children.

A binary tree has not more than

two

children

Evaluating any expression is difficult in

Evaluation of expression is easy

general trees.

binary tree.

in

Application of trees
i.

Manipulation of arithmetic expression

ii.

Symbol table construction

iii.

Syntax Analysis

iv.

Grammar

v.

Expression Tree

Binary search tree ADT


Binary search tree is a binary tree in which every node X in the tree, the values of all
the keys in its left sub tree are smaller than the key value in X, and the values of all the keys
in its right sub tree are larger than the key vale in X.

Comparison between binary tree and binary search tree


Binary tree
A tree is said to be a binary

Binary search tree


tree if it

has

atmost two children. It does not have any


order.

A binary search tree is a binary tree in which


the key values in the left node is less than the
root and the key values in the right node is
greater than the root.

105
www.cseitquestions.in

Declaration Routine for binary search tree


struct TreeNode;
typedef struct Treenode *SearchTree;
SearchTree Insert (int X, SearchTree T);
SearchTree Delete (int X, SearchTree
T); int Find (int X, SearchTree T);
int FindMin(SearchTree T);
int FindMax(SearchTree T);
SearchTree MakeEmpty(SearchTree
T); struct TreeNode
{
int Element;
SearchTree Left;
SearchTree Right;
};

MakeEmpty
This operation is mainly for initialization when the programmer prefer to initialize the
first element as a one node tree.
Routine to make an empty tree
SearchTree MakeEmpty(SearchTree T)
{
if (T!=NULL)
{

MakeEmpty(T->Left);
MakeEmpty(T>Right); free(T);
}
return NULL;
}
Find
This operation requires returning a pointer to the node in tree T that has key X or
NULL if there is no such node.
The find operation as follows.
106
www.cseitquestions.in

Check whether the root is NULL if so then return NULL.

Otherwise, check the value X with the root node value (ie. T->Element)

If X is equal to T->Element, return T

If X is less than T->Element, traverse the left of T recursively.

If X is greater than T->Element, traverse the right of T recursively.

Routine for Find operation


Position Find( ElementType X, SearchTree T )
{
if( T == NULL ) return
NULL;

if(X < T->element )


return( Find( X, T->left ) );
else
if( X > T->element )
return( Find( X, T->right ) );
else
return T;
}

Example:
To find an element 4 (X = 4) in the below tree

In the first
fig, the element 4 is checked with root 6. 4 is less than 6. So goto the left
subtree.

the second
fig, element 4 is checked with node 2. 4 is greater than 2. So goto the right
In
subtree.

In the third fig, the element 4 is checked with node 4. The element is equal. So return 4.
107
www.cseitquestions.in

FindMin
This operation returns the position of the smallest element in the tree. To find the
minimum element, start at the root and go left as long as there is a left child. The stopping
point is the smallest element.
Recursive routine for FindMin

Non Recursive routine for FindMin

Position FindMin( SearchTree T )

Position FindMin( SearchTree T )

{
if( T != NULL )

if( T = = NULL ) return

NULL;

else

while(T->Left!=NULL)

if( T->Left = = NULL )

{
T = T->Left;

return T;

else

}}
return FindMin ( T->Left ) ; }

return T; }

FindMax
This operation returns the position of the largest element in the tree. To find the
maximum element, start at the root and go right as long as there is a right child. The stopping
point is the largest element.
Recursive routine for FindMax

Non Recursive routine for FindMax

Position FindMax( SearchTree T )

Position FindMax( SearchTree T )

{
if( T != NULL )

if( T = = NULL ) return


NULL;

{
while(T-

else
>Right!=NULL)

if( T->Right = = NULL )

T = T->Right;

return T;

else

}}
return FindMax ( T->Right ) ;

return T;
}

Insert

To insert the element X in to the tree, check with the root node T.
108
www.cseitquestions.in


If it is less than the root, traverse the left sub tree
recursively until it reaches the T->Left
equals to NULL. Then X is placed in T->Left.

If it is greater than the root, traverse the right sub tree


recursively until it reaches the T>Right equals to NULL. Then X is placed in T->Right.

If X is found in the tree, do nothing.

Recursive routine to insert an element into a binary search tree


SearchTree Insert( ElementType X, SearchTree T )
{
if( T = = NULL )
{ /* Create and return a one-node tree */ T
= malloc ( sizeof (struct TreeNode) );
if( T != NULL )
{
T-Element = X;
T->Left = T->Right = NULL;
}
}
else
{
if( X < T->Element )
T->Left = Insert( X, T->Left
); else
if( X > T->Element )
T->Right = Insert( X, T->Right );
/* else X is in the tree already. We'll do nothing
*/ return T;
}
Example: To insert 8, 4, 1, 6, 5, 7, 10
8

i. First insert element 8 which is considered as root.


ii.

Next insert element 4, 4 is less than 8, traverse towards left.

iii.

Next insert element 1, 1<8 traverse towards left. 1<4 traverse towards left.

iv.

To insert element 6, 6<8 traverse towards left. 6>4, place it as right child of 4.

v.

To insert element 5, 5<8 traverse towards left. 5>4, traverse towards right. 5<6,
place it as left child of 6.
109
www.cseitquestions.in

4
6

5
5

To insert element 7, 7<8 traverse towards left. 7>4, traverse towards right. 7>6, place
it as right child of 6.

vii.

To insert element 10, 10>8, place it as a right child of 8.

Delete
While deleting a node from a tree, the memory is to be released. Deletion operation
is the complex operation in the binary search tree. To delete a node from the tree consider the
following three possibilities.
Case 1: Node to be deleted is a leaf node
Case 2: Node with one child.
Case 3: Node with two children.
Case 1: Deleting the leaf node

Search the parent of the leaf node.

Make the parent link of the leaf node as NULL.


Release Memory.

Example: Deletion of node 6


8

4
1

4
6

Before deletion

After Deletion

Case 2: Deleting the node with only one child.

Search the parent of the node to be deleted.

Assign the parent link to the child node of the node to be deleted.
Release the memory of the deleted node.

If a node has one child, it can be deleted by adjusting its parent pointer to point to
its child node.
110
www.cseitquestions.in

10
6

vi.

Eg: Deletion of a node with one child, before and after

Case 3: Deleting a node with two children.


The general strategy is to replace the data of the node to be deleted with its smallest
data of the right sub tree (or) largest data of the left sub tree and recursively delete the data or
node.
Inorder to delete a node with two children, it can be replaced by a node whose key
is larger than any node in Ps right sub tree to preserve the Binary Search Tree property. The
possible nodes that could replace node P are
Rule 1: The node with the largest value in Ps left sub tree.
Rule 2: The node with the smallest value in Ps right sub tree.
Eg: Deletion of a node 4 with two children, before and after
8

4
1

5
1

Deletion routine for binary search tree


SearchTree Delete( ElementType X, SearchTree T )
{
Position TmpCell;
if( T = = NULL )

Error("Element not
found"); else
if( X < T->Element ) /* Go left */ T>Left = Delete( X, T->Left );

111
www.cseitquestions.in

else
if( X > T->Element ) /* Go right */
T->Right = Delete( X, T->Right );
else

/* Found element to be deleted */

if( T->Left && T->Right ) /* Two children */


{ /* Replace with smallest in right subtree */
TmpCell = FindMin( T->Right );
T->Element = TmpCell->Element;
T->Right = Delete( T->Element, T->Right );
}
else

/* One or zero child */

{
TmpCell = T;
if( T->Left = = NULL )

/* Only a right child */

T = T->Right;
if( T->Right = = NULL )

/* Only a left child */

T = T->Left;
free(TmpCell );
}
return T;
}

4.1 AVL TREES:


An AVL (Adelson Velskii and Landis) tree is a binary search tree with a balance
condition. A balance factor is the height of the left sub tree minus height of the right sub tree.
The height of the empty tree is defined to be -1. For an AVL tree all balance factor should be
+1, 0, or -1.
If the balance factor of any node in an AVL tree becomes less than -1 or greater than
1, the tree has to be balanced by making a simple modifications in the tree called rotation.
An AVL tree causes imbalance, when any one of the following conditions occur.
is the node must be rebalanced.
Case 1: An insertion from the left sub tree of the left child of node .
Case 2: An insertion into the right sub tree of the left child of .
112
www.cseitquestions.in

Case 3: An insertion into the left sub tree of the right child of .
Case 4: An insertion into the right sub tree of the right child of .
These imbalances can be overcome by
i.

Single Rotation

ii.

Double Rotation

Case 1 and Case 4 imbalance (left left or right right) is fixed by a single rotation
of the tree. Case 2 and Case 3 imbalance (left right or right left) is fixed by double
rotation.
Single Rotation
Single rotation with left
The following fig. shows the single rotation that fixes case 1.
General Representation

The before picture is on the left, and the after is on the right. Node K2 violates the
AVL property because its left sub tree is two levels deeper than its right sub tree. Sub tree X
has grown to an extra level, causing it to be exactly two levels deeper than Z. To ideally
rebalance the tree, we would like to move X up a level and Z down a level. To do this we
rearrange nodes into an equivalent tree as shown in the second part of the above fig.
Eg: If we insert the value 1 in the left sub tree of the following tree it causes imblance

8
5
3

5
3

1
7

The above fig. shows that after the insertion of 1 into the original AVL tree on the
left, node 8 becomes unbalanced. Thus we do a single rotation between 5 and 8, obtaining
tree on the right.
Routine to perform single rotation with left
113
www.cseitquestions.in

static Position SingleRotateWithLeft ( Position K2 )


{
Position K1;
K1 = K2->Left;
K2->Left = K1->Right;
K1->Right = K2;
K2->Height = Max ( Height (K2 ->Left), Height(K2->Right))+1;
K1->Height = Max ( Height (K1 ->Left), Height(K1->Right))+1;
return K1;
}
Single rotation with right
General Representation

Routine to perform single rotation with right


static Position SingleRotateWithRight ( Position K1 )
{
Position K2;
K2 = K1->Right;
K1->Right = K2->Left;
K2->Left = K1;
K2->Height = Max ( Height (K2 ->Left), Height(K2->Right))+1;
K1->Height = Max ( Height (K1 ->Left), Height(K1->Right))+1;
return K2;
}
Example
Suppose we start with an initially empty AVL tree and insert the keys 1 through 7 in
sequential order. The first problem occurs when it is time to insert key 3, because the AVL
property is violated at the root. We perform a single rotation between the root and its right
114
www.cseitquestions.in

child to fix the problem. The tree is shown in the following figure, before and after the
rotation:

Next, we insert the key 4, which causes no problems, but the insertion of 5 creates a
violation at node 3, which is fixed by a single rotation. Besides the local change caused by the
rotation, the programmer must remember that the rest of the tree must be informed of this
change. Here, this means that 2's right child must be reset to point to 4 instead of 3.

Next, we insert 6. This causes a balance problem for the root, since its left subtree is
of height 0, and its right subtree would be height 2. Therefore, we perform a single rotation at
the root between 2 and 4.

115
www.cseitquestions.in

The rotation is performed by making 2 a child of 4 and making 4's original left sub
tree the new right sub tree of 2. Every key in this sub tree must be positioned between 2 and
4, so this transformation makes sense. The next key we insert is 7, which causes another
rotation.

Double Rotation
Double Rotation with left
Double rotation with left is used to perform case 2. An insertion into the right sub tree
of the left child of node .
Double Rotation with left is performed by first performing single rotation with right,
and then performing single rotation with left.
Routine to perform double rotation with left
static Position DoubleRotateWithLeft( Position K3)
{
/* Rotate between K1 and K2 */
K3 -> Left = SingleRotateWithRight(K3 ->Left);
/* Rotate between K3 and K2 */
return SingleRotateWithLeft (K3);
}
Double Rotation with Right
Double rotation with right is used to perform case 4. An insertion into the left sub tree
of the right child of node .
Double Rotation with right is performed by first performing single rotation with left,
and then performing single rotation with right.
Routine to perform double rotation with right
static Position DoubleRotateWithRight( Position K1)
{
116
www.cseitquestions.in

K1 -> Right = SingleRotateWithLeft(K1 >Right); return SingleRotateWithRight (K1);


}
In our example, the double rotation is a right-left double rotation and involves 7, 15,
and 14. Here, k3 is the node with key 7, k1 is the node with key 15, and k2 is the node with
key 14.

Next we insert 13, which require a double rotation. Here the double rotation is again a rightleft double rotation that will involve 6, 14, and 7 and will restore the tree. In this case, k3 is
the node with key 6, k1 is the node with key 14, and k2 is the node with key 7.

If 12 is now inserted, there is an imbalance at the root. Since 12 is not between 4 and
7, we know that the single rotation will work.

117
www.cseitquestions.in

Insertion of 11 will require a single rotation:

To insert 10, a single rotation needs to be performed, and the same is true for the subsequent
insertion of 9. We insert 8 without a rotation, creating the almost perfectly balanced tree that
follows.

Node declaration for AVL trees


#ifndef _AvlTree_H
struct AvlNode;
typedef struct AvlNode *Position;
typedef struct AvlNode *AvlTree;
AvlTree MakeEmpty(AvlTree T);

Position Find( ElementType X, AvlTree T);


Position FindMin( AvlTree T);
Position FindMax( AvlTree T);
AvlTree Insert( ElementType X, AvlTree T);
AvlTree Delete( ElementType X, AvlTree T);
118
www.cseitquestions.in

ElementType Retrieve( Position


P); #endif
struct AvlNode
{
ElementType Element;
AvlTree Left;
AvlTree Right;
int Height;
};
Function to compute height of an Avl node
static int Height( Position P)
{
if( P = = NULL)
return -1;

else
return P -> Height;
}
Insertion into an Avl tree
AvlTree Insert( ElementType X, AvlTree T)
{
if( T = = NULL)
{
T = malloc( sizeof( struct
AvlNode)); if( T = = NULL)
FatalError( Out of Space);
else
{
T -> Element = X;
T -> Height = 0;
T -> Left = T -> Right = NULL;
}
}
else if( X < T -> Element)
{
119
www.cseitquestions.in

T -> Left = Insert(X, T-> Left);


if( Height( T -> Left) Height( T -> Right) = = 2)
if( X < T -> Left -> Element)
T = SingleRotateWithLeft( T );
else
T = DoubleRotateWithLeft(T);
}
else if( X > T -> Element)
{
T -> Right = Insert(X, T-> Right);
if( Height( T -> Right) Height( T -> Left) = = 2)
if( X > T -> Right -> Element)
T = SingleRotateWithRight( T );
else
T = DoubleRotateWithRight(T);
}
/* Else X is in the tree already; we will do nothing */
T -> Height = Max( Height( T-> Left), Height( T -> Right)) + 1;
return T;
}

4.2 B-TREES:
A B-tree is a tree data structure that keeps data sorted and allows searches, insertions,
and deletions in logarithmic amortized time. Unlike self-balancing binary search trees, it is
optimized for systems that read and write large blocks of data. It is most commonly used in
database and file systems.

The B-Tree Rules


Important properties of a B-tree:

B-tree nodes have many more than two children.

A B-tree node may contain more than just a single element.

The set formulation of the B-tree rules: Every B-tree depends on a positive constant integer
called MINIMUM, which is used to determine how many elements are held in a single node.

120
www.cseitquestions.in

Rule 1: The root can have as few as one element (or even no elements if it also has no
children); every other node has at least MINIMUM elements.

Rule 2: The maximum number of elements in a node is twice the value of


MINIMUM.

Rule 3: The elements of each B-tree node are stored in a partially filled array, sorted

from the smallest element (at index 0) to the largest element (at the final used position

of the array).

Rule 4: The number of subtrees below a nonleaf node is always one more than the
number of elements in the node.
o

Subtree 0, subtree 1, ...

Rule 5: For any nonleaf node:


1.
An element at index i is greater than all the elements in subtree number
i of the node, and
2.

An element at index i is less than all the elements in subtree number i +

1 of the node.
Rule 6: Every leaf in a B-tree has the same depth. Thus it ensures that a B-tree avoids
the problem of a unbalanced tree.

The Set Class Implementation with B-Trees


"Every child of a node is also the root of a smaller B-tree".
public class IntBalancedSet implements Cloneable
{
private static final int MINIMUM = 200;
private static final int MAXIMUM = 2*MINIMUM;
int dataCount;
int[] data = new int[MAXIMUM +
1]; int childCount;
121
www.cseitquestions.in

IntBalancedSet[] subset = new IntBalancedSet[MAXIMUM + 2];


// Constructor: initialize an empty
set public IntBalancedSet()
// add: add a new element to this set, if the element was already in the set, then there is no
change.
public void add(int element)
// clone: generate a copy of this set.
public IntBalancedSet clone()
// contains: determine whether a particular element is in this set
pubic boolean contains(int target)
// remove: remove a specified element from this
set public boolean remove(int target)
}

Searching for a Target in a Set


The psuedocode:
1. Make a local variable, i, equal to the first index such that data[i] >= target. If there is
no such index, then set i equal to dataCount, indicating that none of the elements is
greater than or equal to the target.
2. if (we found the target at
data[i]) return true;
else if (the root has
children) return false;

no

else return subset[i].contains(target);


Example, try to search for 10.

We can implement a private method:

private int firstGE(int target), which returns the first location in the root such that
data[x] >= target. If there's no such location, then return value is dataCount.
122
www.cseitquestions.in

Adding an Element to a B-Tree


It is easier to add a new element to a B-tree if we relax one of the B-tree rules.
Loose addition allows the root node of the B-tree to have MAXIMUM = 1 elements. For
example, suppose we want to add 18 to the tree:

The above result is an illegal B-tree. Our plan is to perform a loose addition first, and then fix

the root's problem.


The Loose Addition Operation for a B-Tree:
private void looseAdd(int element)
{
i = firstGE(element) // find the first index such that data[i] >= element
if (we found the new element at data[i]) return; // since there's already a copy in the
set else if (the root has no children)
Add the new element to the root at data[i]. (shift array)
else {
subset[i].looseAdd(element);

if the root of subset[i] now has an excess element, then fix that problem
before returning.
}
}

private void fixExcess(int i)


// precondition: (i < childCount) and the entire B-tree is valid except that subset[i]
has MAXIMUM + 1 elements.
// postcondition: the tree is rearranged to satisfy the loose addition rule
123
www.cseitquestions.in

Fixing a Child with an Excess Element:

To fix a child with MAXIMIM + 1 elements, the child node is split into two nodes
that each contain MINIMUM elements. This leaves one extra element, which is

passed up to the parent.

It is always the middle element of the split node that moves upward.

The parent of the split node gains one additional child and one additional element.

The children of the split node have been equally distributed between the two smaller
nodes.

Fixing the Root with an Excess Element:

Create a new root.

fixExcess(0).

Removing an Element from a B-Tree


Loose removal rule: Loose removal allows to leave a root that has one element too few.
public boolean remove(int target)
{
answer = looseRemove(target);
if ((dataCount == 0) && (childCount == 1))
Fix the root of the entire tree so that it no longer has zero elements;
124
www.cseitquestions.in

return answer;
}
private boolean looseRemove(int target)
{
1. i = firstGE(target)
2. Deal with one of these four possibilities:
2a. if (root has no children and target not found) return false.
2b. if( root has no children but target found) {
remove the target
return true
}
2c. if (root has children and target not found)
{ answer = subset[i].looseRemove(target)
if (subset[i].dataCount < MINIMUM)
fixShortage(i)
return true

}
2d. if (root has children and target found)
{ data[i] = subset[i].removeBiggest()
if (subset[i].dataCount <
MINIMUM) fixShortage(i)
return true
}
}

private void fixShortage(int i)


// Precondition: (i < childCount) and the entire B-tree is valid except that subset[i] has
MINIMUM - 1 elements.
// Postcondition: problem fixed based on the looseRemoval rule.
private int removeBiggest()
// Precondition: (dataCount > 0) and this entire B-tree is valid
// Postcondition: the largest element in this set has been removed and returned. The entire Btree is still valid based on the looseRemoval rule.

125
www.cseitquestions.in

Fixing Shortage in a Child:


When fixShortage(i) is activated, we know that subset[i] has MINIMUM - 1 elements.
There are four cases that we need to consider:

Case 1: Transfer an extra element from subset[i-1]. Suppose subset[i-1] has more than
the MINIMUM number of elements.
a. Transfer data[i-1] down to the front of subset[i].data.
b. Transfer the final element of subset[i-1].data up to replace data[i-1].
c. If subset[i-1] has children, transfer the final child of subset[i-1] over to the front of
subset[i].

Case 2: Transfer an extra element from subset[i+1]. Suppose subset[i+1] has more than the
MINIMUM number of elements.
Case 3: Combine subset[i] with subset[i-1]. Suppose subset[i-1] has only
MINIMUM elements
a. Transfer data[i-1] down to the end of subset[i-1].data.
126
www.cseitquestions.in

b. Transfer all the elements and children from subset[i] to the end of subset[i-1].
c. Disconnect the node subset[i] from the B-tree by shifting subset[i+1], subset[i+2] and
so on leftward.

Case 4: Combine subset[i] with subset[i+1]. Suppose subset[i+1] has only MINIMUM
elements. We may need to continue activating fixShortage() until the B-Tree rules are
satisfied.

Removing the Biggest Element from a B-Tree:


private int removeBiggest()
{
if (root has no children)
remove and return the last
element else {
answer = subset[childCount-1].removeBiggest() if
(subset[childCount-1].dataCount < MINIMUM)

fixShortage(childCount1) return answer


}
}

127
www.cseitquestions.in

A more concrete example for node deletion:

128
www.cseitquestions.in

4.3 RED-BLACK TREES


A redblack tree is a data

structure

which is a type of self-balancing

binary search tree.

Balance is preserved by painting each node of the tree with one of two colors (typically called
'red' and 'black') in a way that satisfies certain properties, which collectively constrain how
unbalanced the tree can become in the worst case. When the tree is modified, the new tree is
subsequently rearranged and repainted to restore the coloring properties. The properties are
designed in such a way that this rearranging and recoloring can be performed efficiently.

A binary search tree is a red-black tree


if: 1. Every node is either red or black
2. Every leaf (nil) is black
3. If a node is red, then both its children are black
4. Every simple path from a node to a descendant leaf contains the same number of black
nodes
Black-height of a node x, bh(x), is the number of black nodes on any path from x to a
leaf, not counting x

Inserting in Red-Black Tree

Color the node Red

Insert as in a regular BST

If have parent is red

Case 1

x is node of interest, x's uncle is Red

129
www.cseitquestions.in

Decrease x's black height by one


Case 2

x's uncle is Black, x is a Right child

Transform to case 3

Case 3

x's uncle is Black, x is a Left child

Terminal case, tree is Red-Black tree


130
www.cseitquestions.in

Insertion takes O(lg(n)) time

Requires at most two rotations

Example:

Deleting in a Red-Black Tree

Find node to delete

Delete node as in a regular BST

Node to be deleted will have at most one child

If we delete a Red node tree still is a Red-Black tree

Assume we delete a black node

Let x be the child of deleted node

If x is red, color it black and stop

If x is black mark it double black and apply the following:

131
www.cseitquestions.in

Case 1

x's sibling is red

x stays at same black height. Transforms to case 2b then terminates.

Case 2a

x's sibling is black

x's parent is black

Decreases x black height by one

Case 2b

x's sibling is black

x's parent is red

Terminal case, tree is Red-Black tree

132
www.cseitquestions.in

Case 3

x's sibling is black

x's parent is either

x's sibling's left child is red

x's sibling's right child is black

x stays at same black height

Transforms to case 4

Case 4

x's sibling is black

x's parent is either

x's sibling's left child is either

x's sibling's right child is red

Terminal case, tree is Red-Black tree.

Delete time is O(lg(n)).

At most three rotations are done.

133
www.cseitquestions.in

4.4 SPLAY TREES:


Splay trees are another variation of the binary search tree.
Novel characteristics:

Does not require any accounting information (color, level, height, etc.)

O(N) worst case for any single operation, but O(log N) average case

Frequently-accessed keys are moved up so that they are near the root.

Splay Operation:
Fundamental operation is the splay: this operation re-arranges the tree to make a
specified node the root. A side-effect of the splay is that imbalances in the tree are corrected.
The simplest approach to splaying is the bottom-up approach, which is similar to the
rebalancing operations we have seen for AVL, Red-Black, and AA-trees. On some path from
a selected node back to the root, rotations are performed.
There are three cases for splaying. (Note that only the "left" cases are shown: there are
symmetric "right" cases.)
Zig

Zig-Zig

Zig-Zag

Zig Step:
This step is done when p is the root. The tree is rotated on the edge between x and p.
Zig steps exist to deal with the parity issue and will be done only as the last step in a splay
operation and only when x has odd depth at the beginning of the operation.

134
www.cseitquestions.in

Zig-zig Step:
This step is done when p is not the root and x and p is either both right children or are
both left children. The picture below shows the case where x and p are both left children. The
tree is rotated on the edge joining p with its parent g, then rotated on the edge joining x with
p.

Zig-zag Step:
This step is done when p is not the root and x is a right child and p is a left child or
vice versa. The tree is rotated on the edge between p and x, and then rotated on the resulting
edge between x and g.

Overall splaying algorithm (bottom-up): splaying continues until the node X is the
root of the overall tree.
A splay operation is performed after each access. We recursively apply the splaying
strategy until the node of our interest reaches the root.

Example: Result of splaying at node 1 (after 1 is accessed).

135
www.cseitquestions.in

Insertion: X is the newly inserted node (and will become the root after splaying).
Search:
o

If X is in the tree, X is the node found (and will become the root after
splaying).

If X is not in the tree, the last node accessed prior to reaching the NULL
pointer is splayed.

Deletion:
o

First, X is the node to be deleted. Splay it to the root (and delete it).

Then for the two subtrees L and R (left and right), we find the largest element
in L. Splay it to the root of L. At this point, L's (new) root has no right child.

Finally connect R to the root of L as its right child.

Example: Delete 6

136
www.cseitquestions.in

4.5 BINOMIAL HEAPS


A binomial heap is a collection of binomial trees, so this section starts by defining
binomial trees and proving some key properties. We then define binomial heaps and show
how they can be represented.

Binomial trees
The binomial tree Bk is an ordered tree defined recursively. As shown in figure(a),
the binomial tree B0 consists of a single node. The binomial tree Bk consists of two binomial
trees Bk-1 that are linked together: the root of one is the leftmost child of the root of the
other. Figure (b) shows the binomial trees B0 through B4.

Figure (a) The recursive definition of the binomial tree B k. Triangles represent rooted
subtrees. (b) The binomial trees Bo through B4. Node depths in B4 are shown. (c)
Another way of looking at the binomial tree Bk.
Some properties of binomial trees are as follows.
For the binomial tree Bk,
k

1. There are 2 nodes,

137
www.cseitquestions.in

2. The height of the tree is k,


3. There are exactly

nodes at depth i for i = 0, 1, . . . , k, and

4. The root has degree k, which is greater than that of any other node; moreover if the
children of the root are numbered from left to right by k - 1, k - 2, . . . , 0, childi is the root of
a subtree Bi.
Definition:
A binomial heap H is a set of binomial trees that satisfies the following binomial-heap
properties.

Each binomial tree in H is heap-ordered: the key of a node is greater than or equal to
the key of its parent.

There is at most one binomial tree in H whose root has a given degree.

Figure. A binomial heap H with n = 13 nodes. (a) The heap consists of binomial trees B 0,
B2, and B3, which have 1, 4, and 8 nodes respectively, totaling n = 13 nodes. Since each
binomial tree is heap-ordered, the key of any node is no less than the key of its parent.
Also shown is the root list, which is a linked list of roots in order of increasing degree.
138
www.cseitquestions.in

(b) A more detailed representation of binomial heap H. Each binomial tree is stored in
the left-child, right-sibling representation, and each node stores its degree.

Figure (a) shows a binomial heap H with 13 nodes. The binary representation of 13 is 1101
, and H consists of heap-ordered binomial trees B3, B2, and B0, having 8, 4, and 1 nodes
respectively, for a total of 13 nodes.

Representing binomial heaps


As shown in Figure (b), each binomial tree within a binomial heap is stored in the leftchild, right-sibling representation of Section 11.4. Each node has a key field and any other
satellite information required by the application. In addition, each node x contains pointers
p[x] to its parent, child [x] to its leftmost child, and sibling[x] to the sibling of x immediately
to its right. If node x is a root, then p[x] = NIL. If node x has no children, then child[x] = NIL,
and if x is the rightmost child of its parent, then sibling[x] = NIL. Each node x also contains
the field degree[x], which is the number of children of x.

Figure: The binomial tree B4 with nodes labeled in binary by a postorder walk.

Above figure also shows, the roots of the binomial trees within a binomial heap are
organized in a linked list, which we refer to as the root list. The degrees of the roots strictly
increase as we traverse the root list. By the second binomial-heap property, in an n-node
binomial heap the degrees of the roots are a subset of {0, 1, . . . , 1g n }. The sibling field
has a different meaning for roots than for nonroots. If x is a root, then sibling[x] points to the
next root in the root list. (As usual,sibling[x] = NIL if x is the last root in the root list.)

A given binomial heap H is accessed by the field head[H], which is simply a pointer
to the first root in the root list of H. If binomial heap H has no elements, thenhead[H] = NIL.

139
www.cseitquestions.in

Operations on binomial heaps


Creating a new binomial heap
To make an empty binomial heap, the MAKE-BINOMIAL-HEAP procedure simply
allocates and returns an object H, where head[H] = NIL. The running time is (1).

Finding the minimum key


The procedure BINOMIAL-HEAP-MINIMUM returns a pointer to the node with the
minimum key in an n-node binomial heap H. This implementation assumes that there are no
keys with value

BINOMIAL-HEAP-MINIMUM(H)
1 y

NIL

2 x

head[H]

3 min
4 while x
5

do if key[x] < min


6

then min key[x]

7
8

NIL

y x
x

sibling[x]

9 return y

Since a binomial heap is heap-ordered, the minimum key must reside in a root node. The
BINOMIAL-HEAP-MINIMUM procedure checks all roots, which number at most lg n

+ 1, saving the current minimum in min and a pointer to the current minimum in y. When
called on the binomial heap of Figure 20.3, BINOMIAL-HEAP-MINIMUM returns a pointer
to the node with key 1.
Because there are at most lg n + 1 roots to check, the running time of BINOMIALHEAP-MINIMUM is O(lg n).

Uniting two binomial heaps


The operation of uniting two binomial heaps is used as a subroutine by most of the
remaining operations. The BINOMIAL-HEAP-UNION procedure repeatedly links binomial
trees whose roots have the same degree. The following procedure links the Bk-1 tree rooted at

140
www.cseitquestions.in

node y to the Bk-1 tree rooted at node z; that is, it makes zthe parent of y. Node z thus
becomes the root of a Bk tree.
BINOMIAL-LINK(y,z)
1 p[y]

2 sibling[y]

child[z]

3 child[z]

4 degree[z]

degree[z]+1

The BINOMIAL-LINK procedure makes node y the new head of the linked list of
node z's children in O(1) time. It works because the left-child, right-sibling representation of
each binomial tree matches the ordering property of the tree: in a Bk tree, the leftmost child of
the root is the root of a Bk-1 tree.
The following procedure unites binomial heaps H1 and H2, returning the resulting
heap. It destroys the representations of H1 and H2 in the process. Besides BINOMIAL-LINK,
the procedure uses an auxiliary procedure BINOMIAL-HEAP-MERGE that merges the root
lists of H1 and H2 into a single linked list that is sorted by degree into monotonically
increasing order.

141
www.cseitquestions.in

Case 1:
Case 1, shown in Figure (a), occurs when degree[x] degree[next-x], that is, when x
is the root of a Bk-tree and next-x is the root of a Bl-tree for some l >k.
Lines 11-12 handle this case. We don't link x and next-x, so we simply march the
pointers one position further down the list. Updating next-x to point to the node following the
new node x is handled in line 21, which is common to every case.

Case 2:
Case 2, shown in Figure (b), occurs when x is the first of three roots of equal degree,
that is, when degree[x] = degree[next-x] = degree[sibling[next-x]].
We handle this case in the same manner as case 1: we just march the pointers one
position further down the list. Line 10 tests for both cases 1 and 2, and lines 11-12 handle
both cases.

Cases 3 and 4:
Cases 3 and 4 occur when x is the first of two roots of equal degree, that is, when
degree[x] = degree[next-x] degree[sibling[next-x]].
These cases may occur on the next iteration after any case, but one of them always
occurs immediately following case 2. In cases 3 and 4, we link x and next-x. The two cases
are distinguished by whether x or next-x has the smaller key, which determines the node that
will be the root after the two are linked.
In case 3, shown in Figure (c), key[x] key[next-x], so next-x is linked to x. Line 14
removes next-x from the root list, and line 15 makes next-x the leftmost child of x.

142
www.cseitquestions.in

Figure: The execution of BINOMIAL-HEAP-UNION.(a) Binomial heaps H1 and H2. (b)


Binomial heap H is the output of BINOMIAL-HEAP-MERGE(H1,H2). Initially, x is the
first root on the root list of H. Because both x and next-x have degree 0 and key[x] <
key[next-x], case 3 applies. (c) After the link occurs, x is the first of three roots with the
same degree, so case 2 applies. (d) After all the pointers move down one position in the
root list, case 4 applies, since x is the first of two roots of equal degree. (e) After the link
occurs, case 3 applies. (f) After another link, case 1 applies, because x has degree 3 and
next-x has degree 4. This iteration of the while loop is the last, because after the pointers
move down one position in the root list, next-x = NIL.

143
www.cseitquestions.in

In case 4, shown in Figure (d), next-x has the smaller key, so x is linked to next-x.
Lines 16-18 remove x from the root list, which has two cases depending on whether x is the
first root on the list (line 17) or is not (line 18). Line 19 then makes x the leftmost child of
next-x, and line 20 updates x for the next iteration.
Following either case 3 or case 4, the setup for the next iteration of the while loop is
the same. We have just linked two Bk-trees to form a Bk+l-tree, which x now points to. There
were already zero, one, or two other Bk+1-trees on the root list from the output of
BINOMIAL-HEAP-MERGE, so x is now the first of either one, two, or three Bk+l-trees on
the root list. If x is the only one, then we enter case 1 in the next iteration: degree [x]
degree[next-x]. If x is the first of two, then we enter either case 3 or case 4 in the next
iteration. It is when x is the first of three that we enter case 2 in the next iteration.

144
www.cseitquestions.in

Figure: The four cases that occur in BINOMIAL-HEAP-UNION. Labels a, b, c, and d


serve only to identify the roots involved; they do not indicate the degrees or keys of
these roots. In each case, x is the root of a Bk-tree and l > k. (a) Case 1: degree[x]
degree[next-x]. The pointers move one position further down the root list. (b) Case 2:
degree[x] = degree[next-x] = degree[sibling[next-x]]. Again, the pointers move one
position further down the list, and the next iteration executes either case 3 or case 4. (c)
Case 3: degree[x] = degree[next-x] degree[sibling[next-x] and key[x] key[next-x]. We
remove next-x from the root list and link it to x, creating a B k+1-tree. (d) Case 4:
degree[x] = degree[next-x]
degree[sibling[next-x]] and key[next-x]
key[x]. We
remove x from the root list and link it to next-x, again creating a B k+1-tree.

Inserting a node
The following procedure inserts node x into binomial heap H, assuming of course that
node x has already been allocated and key[x] has already been filled in.

BINOMIAL-HEAP-INSERT(H,x)
1 H'
2 p[x]

MAKE-BINOMIAL-HEAP()
NIL

3 child[x]

NIL

4 sibling[x]

NIL

5 degree[x]

6 head[H']
7 H

BINOMIAL-HEAP-UNION(H,H')

Extracting the node with minimum key


The following procedure extracts the node with the minimum key from binomial heap
H and returns a pointer to the extracted node.
BINOMIAL-HEAP-EXTRACT-MIN(H)
145
www.cseitquestions.in

1 find the root x with the minimum key in the root list of H,
and remove x from the root list of H
2 H'

MAKE-BINOMIAL-HEAP()

3 reverse the order of the linked list of x's children, and


set head[H'] to point to the head of the resulting list
4 H

BINOMIAL-HEAP-UNION(H,H')

5 return x

Figure: The action of BINOMIAL-HEAP-EXTRACT-MIN. (a) A binomial heap H. (b)


The root x with minimum key is removed from the root list of H. (c) The linked list of
x's children is reversed, giving another binomial heap H'. (d) The result of uniting H
and H'.

146
www.cseitquestions.in

Since each of lines 1-4 takes O(lg n) time if H has n nodes, BINOMIAL-HEAPEXTRACT-MIN runs in O(lg n) time.

Decreasing a key
The following procedure decreases the key of a node x in a binomial heap H to a new
value k. It signals an error if k is greater than x's current key.

BINOMIAL-HEAP-DECREASE-KEY (H,x,k)
1 if k > key[x]
2

then error "new key is greater than current key"

3 key[x]

4 y

5 z

p[y]

6 while z
7

NIL and key[y] < key[z]

do exchange key[y]

key[z]

If y and z have satellite fields, exchange them, too.

10

p[y]

Deleting a key
It is easy to delete a node x's key and satellite information from binomial heap H in O(lg n)
time. The following implementation assumes that no node currently in the binomial heap has
a key of -

As shown in below figure, this procedure decreases a key in the same manner as in a
binary heap: by "bubbling up" the key in the heap. After ensuring that the new key is in fact
no greater than the current key and then assigning the new key to x, the procedure goes up the
tree, with y initially pointing to node x. In each iteration of the while loop
10, key[y] is checked against the key of y's parent z. If y is the root or key[y]

of lines 6key[z], the

binomial tree is now heap-ordered. Otherwise, node y violates heap ordering, so its key is
exchanged with the key of its parent z, along with any other satellite information. The
procedure then sets y toz, going up one level in the tree, and continues with the next iteration.
The BINOMIAL-HEAP-DECREASE-KEY procedure takes O(lg n) time. By
property 2 of Lemma 20.1, the maximum depth of x is lg n , so the while loop of lines 6-10
iterates at most lg n times.
147
www.cseitquestions.in

Figure: The action of BINOMIAL-HEAP-DECREASE-KEY. (a) The situation just


before line 5 of the first iteration of the while loop. Node y has had its key decreased to
7, which is less than the key of y's parent z. (b) The keys of the two nodes are
exchanged, and the situation just before line 5 of the second iteration is shown. Pointers
y and z have moved up one level in the tree, but heap order is still violated. (c) After
another exchange and moving pointers y and z up one more level, we finally find that
heap order is satisfied, so the while loop terminates.

BINOMIAL-HEAP-DELETE(H,x)
1 BINOMIAL-HEAP-DECREASE-KEY(H,x,-

2 BINOMIAL-HEAP-EXTRACT-MIN(H)

The BINOMIAL-HEAP-DELETE procedure makes node x have the unique minimum


key in the entire binomial heap by giving it a key of -

. It then bubbles this key and the

associated satellite information up to a root by calling BINOMIAL-HEAP-DECREASEKEY. This root is then removed from H by a call of BINOMIAL-HEAP-EXTRACT-MIN.
The BINOMIAL-HEAP-DELETE procedure takes O(lg n) time.

148
www.cseitquestions.in

4.6 FIBONACCI HEAPS:


Binomial Tree:
A binomial tree of order 0 is a single node. A binomial tree of order k has a root of
degree k and its children are roots of binomial trees of orders k-1, k-2, ..., 2, 1, 0 (in order). A
k

binomial tree of order k has 2 nodes.

Data Structures:

Heap ordered Trees

Rooted, but unordered

Children of a node are linked together in a Circular, doubly linked List, E.g node 52

Min [H]

3 23

7
17

18

24

52

38

39

41

30

26

35

149
www.cseitquestions.in

46

Node Pointers
- left [x]
- right [x]
- degree [x]
- number of children in the child list of x
- mark [x]

Properties:

Collection of unordered Binomial Trees.

Support Mergeable heap operations such as Insert, Minimum, Extract Min, and Union
in constant time O(1)

Desirable when the number of Extract Min and Delete operations is small relative to
the number of other operations.

Most asymptotically fastest algorithms for computing minimum spanning trees and
finding single source shortest paths make use of the Fibonacci heaps.

Fibonacci Heap Operations:


Make Fibonacci Heap

Assign N[H] = 0, min[H] = nil

Amortized cost is O(1)

Find Min

Access Min[H] in O(1) time

Uniting 2 Fibonacci Heaps

Concatenate the root lists of Heap1 and Heap2

Set the minimum node of the new Heap

Free the 2 heap objects

Amortized cost is equal to actual cost of O(1)

Insert

Amortized cost is O(1)

Initialize the structural fields of node x, add it to the root list of H

Update the pointer to the minimum node of H, min[H]

Increment the total number of nodes in the Heap, n[H]

150
www.cseitquestions.in

Example:
Min [H]

3
23

17

18

52

38

39

24

30

26

41

46

35

Node 21 has been inserted

Red Nodes are marked nodes they will become relevant only in the delete operation.
Min [H]

3
23

21

17

18

52

39

38

24

30

41

26

46

35

Extract Minimum Node

Amortized cost is O(D(n))

Make a root out of each of the minimum nodes children.

Remove the minimum node from the root list, min ptr to right(x)

Consolidate the root list by linking roots of equal degree and key[x] <= key[y], until
every root in the root list has a distinct degree value. (uses auxiliary array)
151
www.cseitquestions.in

21

24

17

18

38

52

39

23

41

26

46

30

35

Root Nodes are stored in the auxiliary array in the index corresponding to their
degree.

Hence node 7 is stored in index 3 and node 21 is stored in index 0.

21

24

26

46

17

23

w,x

18

39

52

38

41

30

35

152
www.cseitquestions.in

Further, node 18 is stored in index 1


There are no root nodes of index 2, so that array entry remains empty
Now the algorithm iterates through the auxiliary array and links roots of equal degree
such that key[x] <= key[y],
0

A
w,x
21

24

26

17

46

18

38

52

39

23

41

30

35

Nodes 21 and 52 are linked so that node 21 has degree 1, and it is then linked to node
18
0

A
w,x
18

24

26

46

17

30

23

21

38

39

41

52

35

153
www.cseitquestions.in

The pointers of the auxiliary array are updated.


But there are now no more remaining root nodes of duplicate degrees.

w,x
18

24

26

46

17

23

38

21

30

41

39

52

35

Extract-Min is now done.

The pointer min[H] is finally updated to the new minimum.

min [H]

18

24

26

46

17

30

23

21

38

39

41

52

35

154
www.cseitquestions.in

A node is marked if:

At some point it was a root then it was linked to anther node and 1 child of it has been
cut.

Newly created nodes are always unmarked

A node becomes unmarked whenever it becomes the child of another node.

Decrease-Key

Amortized cost is O(1).

Check that new key is not greater than current key, then assign new key to x

If x is a root or if heap property is maintained, no structural changes

Else
o

Cut x: make x a root, remove link from parent y, clear marked field of x

o Perform a Cascading cut on xs parent y (relevant if parent is marked):

if unmarked: mark y, return

if marked: Cut y, recurse on node ys parent

if y is a root, return

The Cascading cut procedure recurses its way up the tree until a root, or an unmarked
node is found.

Update min[H] if necessary.

Example:

Suppose we want to decrease the keys of node 46 to 15.


min [H]

18

24

26

46

17

30

23

21

38

39

41

52

35

155
www.cseitquestions.in

Since the new key of node 46 is 15 it violates the min-heap property, so it is cut
and put on the root.

Suppose now we want to decrease the key of node 35 to 5.


min [H]

15

24

18

17

23

30

21

38

39

41

52

26

35

So node 5 is cut and place on the root list because again the heap property is violated.
But the parent of node 35, which is node 26, is marked, so we have to perform a
cascading cut.

min [H]

15

24

17

26

30

18

23

21

38

39

41

52

The cascading cut involves cutting the marked node, 26, unmarking it, and putting it
on the root list.

156
www.cseitquestions.in

We now repeat this procedure (recurse) on the marked nodes parent until we hit a
node on the root list.

min [H]

15

26

24

18

17

23

21

30

38

39

41

52

Since the next node encountered in the cascading cut procedure is a root node node
7 the procedure terminates.

Now the min heap pointer is updated.

min [H]

15

26

24

17

18

23

21

30

38

39

41

52

Delete-Key

Amortized cost is O(D(n))

Call Decease-Key on the node x that needs to be deleted in H, assigning negative


infinity to it.

Call Extract-Min on H.
157
www.cseitquestions.in

4.7 DISJOINT SETS:


A disjoint sets data structure represents a collection of sets that are disjoint: that is, no
item is found in more than one set. The collection of disjoint sets is called a partition, because
the items are partitioned among the sets. A disjoint-set data structure, also called a unionfind
data structure or mergefind set, is a data structure that keeps track of a set of elements
partitioned into a number of disjoint (non overlapping) subsets.

The Disjoint Set data structure solves a specific problem that is interesting both
theoretically and practically. The problem is as follows:
You have a collection of n items, which you number from 0 to n-1. These items will
be partitioned into some number of sets. The sets are "disjoint" which means that no item
belongs to more than one set. All items belong to some set though (hence the use of the word
"partition.").

There are two operations that you can perform:

int Find(i): This takes the number of an item and returns its "set id." This is a number
between zero and n-1. You don't really care what the number is; however, if i and j
belong to the same disjoint set, then Find(i) will equal Find(j).

int Disjoint::Find(int element)


{
while (links[element] != -1) element =
links[element]; return element;
}

int Union(id1, id2): This takes the set id's of two different sets, and performs the
union operation on them, coalescing them into one set. It returns the set id of this new
set. Now, when you call Find() on any item that was previously in either of these sets,

it will return this new set id.


int Disjoint::Union(int s1, int s2)
{
int p, c;
if (links[s1] != -1 || links[s2] != -1) {
cerr << "Must call union on a set, and not just an element.\n";
158
www.cseitquestions.in

exit(1);
}
if (ranks[s1] > ranks[s2])
{
p = s1;
c = s2;

}
else
{
p = s2;
c = s1;
}
links[c] = p;
ranks[p] += ranks[c]; /* HERE */
return p;
}

Abstract implementation
In the abstract, we implement disjoint sets with circles and arrows, which we'll call
"nodes" and links. Each element will be in its own node, and each element has one link. That
link is either to another node, or to NULL. In the beginning, when you first set up an instance
of disjoint sets, all nodes will have NULL links.
When a node has a NULL link, we call it the "root" of a set. If you call Find() on a
node with a NULL link, it will return the node's item number, and that is the set id of the
node. Therefore, when you first start, every node is the root of its own set, and when you call
Find(i), it will return i.
When you call Union(i, j), remember that i and j must be set id's. Therefore, they must
be nodes with NULL links. What you do is have one of those nodes set its link to the other
node.

Example:
We initialize an instance of disjoint sets with 10 items. Each item is a node with a
number from 0 to 9. Each node has a NULL link, which we depict by not drawing any arrows
from the node:
159
www.cseitquestions.in

Again, each node is in its own set, and each node's set id is its number. Suppose we
call Union(0, 1), Union(2, 3) and Union(4, 5). These will each set one of the node's link to
the other node. We'll talk about how that gets done later. However, suppose this is the result:

Node 0's link has been set to 1. Both of these nodes' set ids are now 1, which means
Find(0) equals Find(1) equals one. Similarly, Find(2) equalsFind(3) equals three. This gives
you a clue about implementing Find(). When you call Find(n), what you do is keep setting n
to n's link, until n's link is NULL. At that point, you are at the root of the set, and you return
n.
Union is pretty simple, too, but you have some choices about how to determine which
node sets its link field to the other. We use three methods to do this:

1. Union by size: Make the node whose set size is smaller point to the node whose set
size is bigger. Break ties arbitrarily.

2. Union by height: The height of a set is the longest number of links that it takes to get
from one of its items to the root. With union by height, you make the node whose
height is smaller point to the node whose height is bigger.

3. Union by rank with path compression: This works exactly like union by height,
except you don't really know the height of the set. Instead, you use the set's rank,
which is what its height would be, were you using union by height. The reason that
you don't know the height is that when you call Find(i) on an element, you perform
"path compression."

160
www.cseitquestions.in

There are two sets, with set id's 5 and 9. Now, suppose you call Find(0). It will return
five, but along the way to the root node of its set, it encounters nodes 1 and 3. Before

returning five, it sets the links to 0, 1 and 3 to five:

Running Time:
We assume the number of items in the instance of disjoint sets is n:

Initializing an instance of disjoint sets: O(n)

Performing Union() in any of the implementations: O(1)

Performing Find() in Union by size or height: O(log(n))

Performing Find() in Union by rank with path compression: O((n))

4.8 AMORTIZED ANALYSIS:


Amortized analysis is a method of analyzing algorithms that considers the entire
sequence of operations of the program. It allows for the establishment of a worst-case bound
for the performance of an algorithm irrespective of the inputs by looking at all of the
operations.

Not just consider one operation, but a sequence of operations on a given data
structure.

Average cost over a sequence of operations.

Probabilistic analysis:
161
www.cseitquestions.in

Average case running time: average over all possible inputs for one algorithm
(operation).
If using probability, called expected running time.

Amortized analysis:
No involvement of probability
Average performance on a sequence of operations, even some operation is
expensive.
Guarantee average performance of each operation among the sequence in worst
case.

Three Methods of Amortized Analysis:

Aggregate analysis:
Total cost of n operations/n,

Accounting method:
Assign each type of operation an (different) amortized cost overcharge some
operations, store the overcharge as credit on specific objects, then use the
credit for compensation for some later operations.

Potential method:
Same as accounting method.
But store the credit as potential energy and as a whole.

Example for amortized analysis:

Stack operations:
PUSH(S,x), O(1)
POP(S), O(1)
MULTIPOP(S,k), min(s,k)
while not STACK-EMPTY(S) and
k>0 do POP(S)
k=k-1

Let us consider a sequence of n PUSH, POP, MULTIPOP.


The worst case cost for MULTIPOP in the sequence is O(n), since the stack size
is at most n.
2

Thus the cost of the sequence is O(n ). Correct, but not tight.
162
www.cseitquestions.in

4.9 ACCOUNTING METHOD:

Idea:
Assign differing charges to different operations.
The amount of the charge is called amortized cost.
Amortized cost is more or less than actual cost.
When amortized cost > actual cost, the difference is saved in specific objects as
credits.
The credits can be used by later operations whose amortized cost < actual cost.

As a comparison, in aggregate analysis, all operations have same amortized costs.

Conditions:
Suppose actual cost is ci for the ith operation in the sequence, and amortized
cost is ci',

i=1 ci' i=1 ci should hold.

Since we want to show the average cost per operation is small using
amortized cost, we need the total amortized cost is an upper bound of
total actual cost.

Holds for all sequences of operations.


n

Total credits is i=1 ci' - i=1 ci , which should be nonnegative,

Moreover, i=1 ci' - i=1 ci 0 for any t>0.

Accounting Method: Stack Operations

Actual costs:
PUSH :1, POP :1, MULTIPOP: min(s,k).

Let assign the following amortized costs:


PUSH:2, POP: 0, MULTIPOP: 0.

Similar to a stack of plates in a cafeteria.


Suppose $1 represents a unit cost.
When pushing a plate, use one dollar to pay the actual cost of the push and leave
one dollar on the plate as credit.
Whenever POPing a plate, the one dollar on the plate is used to pay the actual
cost of the POP. (Same for MULTIPOP).
By charging PUSH a little more, do not charge POP or MULTIPOP.

163
www.cseitquestions.in

The total amortized cost for n PUSH, POP, MULTIPOP is O(n), thus O(1) for
average amortized cost for each operation.

Conditions hold: total amortized cost total actual cost, and amount of credits never
becomes negative.

Accounting method: binary counter

Let $1 represent each unit of cost (i.e., the flip of one bit).

Charge an amortized cost of $2 to set a bit to 1.

Whenever a bit is set, use $1 to pay the actual cost, and store another $1 on the bit as
credit.

When a bit is reset, the stored $1 pays the cost.

At any point, a 1 in the counter stores $1, the number of 1s is never negative, and so
is the total credit.

At most one bit is set in each operation, so the amortized cost of an operation is at
most $2.

Thus, total amortized cost of n operations is O(n), and average is O(1).

4.10 THE POTENTIAL METHOD:

Same as accounting method: something prepaid is used later.

Different from accounting method


The prepaid work not as credit, but as potential energy, or potential.

The potential is associated with the data structure as a whole rather than with specific
objects within the data structure.

Initial data structure D0, n operations, resulting in D0, D1,, Dn with costs c1, c2,,
cn.

A potential function : {Di}


R (real numbers)
(Di) is called the potential of Di.

Amortized cost ci' of the ith operation is:


ci' = ci + (Di) - (Di-1). (actual cost + potential change)
n

i=1 ci' = i=1 (ci + (Di) - (Di-1))


n

= i=1 ci + (Dn) - (D0)

If (Dn) (D0), then total amortized cost is an upper bound of total actual cost.

But we do not know how many operations, so (Di) (D0) is required for any i.
164
www.cseitquestions.in

It is convenient to define (D0)=0,and so (Di) 0, for all i.

If the potential change is positive (i.e., (Di) - (Di-1)>0), then ci' is an overcharge
(so store the increase as potential), otherwise, undercharge (discharge the potential to
pay the actual cost).

Potential method: stack operation

Potential for a stack is the number of objects in the stack.

So (D0)=0, and (Di) 0

Amortized cost of stack operations:


PUSH:

Potential change: (Di)- (Di-1) =(s+1)-s =1.

Amortized cost: ci' = ci + (Di) - (Di-1)=1+1=2.

POP:

Potential change: (Di)- (Di-1) =(s-1) s= -1.

Amortized cost: ci' = ci + (Di) - (Di-1)=1+(-1)=0.

MULTIPOP(S,k): k'=min(s,k)

Potential change: (Di)- (Di-1) = k'.

Amortized cost: ci' = ci + (Di) - (Di-1)=k'+(-k')=0.

So amortized cost of each operation is O(1), and total amortized cost of n operations
is O(n).

Since total amortized cost is an upper bound of actual cost, the worse case cost of n
operations is O(n).

Potential method: binary counter

Define the potential of the counter after the ith INCREMENT is (Di) =bi, the
number of 1s. clearly, (Di)0.

Let us compute amortized cost of an operation


Suppose the ith operation resets ti bits.
Actual cost ci of the operation is at most ti +1.
If bi=0, then the ith operation resets all k bits, so bi-1=ti=k.
If bi>0, then bi=bi-1-ti+1
In either case, bibi-1-ti+1.
So potential change is (Di) - (Di-1) bi-1-ti+1-bi-1=1-ti.
165
www.cseitquestions.in

So amortized cost is: ci' = ci + (Di) - (Di-1) ti +1+1-ti=2.

The total amortized cost of n operations is O(n).

Thus worst case cost is O(n).

4.11 AGGREGATE ANALYSIS:

In fact, a sequence of n operations on an initially empty stack cost at most O(n).

Each object can be POP only once (including in MULTIPOP) for each time it is
PUSHed. #POPs is at most #PUSHs, which is at most n.

Thus the average cost of an operation is O(n)/n = O(1).

Amortized cost in aggregate analysis is defined to be average cost.

Example: Increasing a binary counter


Binary counter of length k, A[0..k-1] of bit array.
INCREMENT(A)

1. i 0
2. while i<k and A[i]=1
3.

do A[i]

4.
5. if i<k

6. then A[i]

(flip, reset)

i+1

(flip, set)

Amortized (Aggregate) Analysis of INCREMENT (A)


The running time determined by #flips but not all bits flip each time INCREMENT is
called.
A[0] flips every time, total n times.
A[1] flips every other time, n/2 times.
A[2] flips every forth time, n/4 times.
.
i

for i=0,1,,k-1, A[i] flips n/2 times.


k-1

Thus total #flips is


<

i
n/2 i=0

ni=0 1/2

=2n.

166
www.cseitquestions.in

Thus the worst case running time is O(n) for a sequence of n INCREMENTs.

So the amortized cost per operation is O(1).

167
www.cseitquestions.in

UNIT V
GRAPHS
Representation of Graphs Breadth-first search Depth-first search Topological sort
Minimum Spanning Trees Kruskal and Prim algorithm Shortest path algorithm
Dijkstras algorithm Bellman-Ford algorithm Floyd - Warshall algorithm.

5.1 REPRESENTATION OF GRAPHS:


Graph
A graph G = (V, E) consists of a set of vertices, V, and a set of edges, E. Vertices are
referred to as nodes. The arcs between the nodes are referred to as edges. Each edge is a pair
(v,w), where v,w V. Edges are sometimes referred to as arcs.
V1

V2

V4

V3

In the above graph V1, V2, V3, V4 are the vertices and (V1, V2), (V2, V3), (V3, V4),
(V4, V1), (V1, V3), (V2, V4) are the edges.
Directed Graph (or) Digraph
Directed graph is a graph, which consists of directed edges, where each edge in E is
unidirectional. In directed graph, the edges are directed or one way. it is also called as
digraphs. If (v,w) is a directed edge, then (v,w) (w,v).
V1

V2

(V1, V2) (V2 , V1)


V3

Undirected Graph
An undirected graph is a graph, which consists of undirected edges. In undirected
graph, the edges are undirected or two way. If (v,w) is a undirected edge, then (v,w) = (w,v).

V1

V2

(V1, V2) = (V2 , V1)

V3

168
www.cseitquestions.in

Weighted Graph
A graph is said to be weighted graph if every edge in the graph is assigned a weight or
value. It can be directed or undirected.
2

V1

V2

V1

6
V3

V2

7
V3

Subgraph
A subgraph of a graph G = (V,E) is a graph G` = (V`, E) such that V` V and E E.

Symmetric digraph
A symmetric digraph is a directed graph such that for every edge vw there is also a
reverse edge wv.

Symmetric undirected graph


Every undirected graph is a symmetric digraph where each undirected edge is
considered as a pair of directed edges in opposite direction.

Complete Graph
A complete graph is a graph in which there is an edge between every pair of vertices.
A complete graph with n vertices will have n(n-1)/2.
V1

V2

Number of vertices is 4
Number of edges is 6

V4

V3

There is a path from every vertex to every other vertex.

A complete graph is a strongly connected graph.

Strongly connected Graph


If there is a path from every vertex to every other vertex in a directed graph then it is
said to be strongly connected graph. Otherwise, it is said to be weakly connected graph.

Path
A path in a graph is defined as a sequence of verices w1, w2, w3, . . . , wn such that
169
www.cseitquestions.in

(w1, w2, w3, . . .) E. Where E is the number of edges in a


graph. Path from A to D is {A, B, C, D} or {A, C, D}
Path from A to C is {A, B, C} or {A, C}

Length
The length of a path in a graph is the number of edges on the path, which is equal to
N1. Where N is the number of vertices.
Length of the path from A to B is {A, B} = 1
Length of the path from A to C is {A, C} = 1 & {A, B, C} = 2.
If there is a path from a vertex to itself with no edges then the path length is 0.
Length of the path from A->A & B -> B is 0.
Loop
A loop in a graph is defined as the path from a vertex to itself. If the graph contains an
edge (v,v) from a vertex to itself, then the path v, v is sometimes referred to as a loop.

Simple Path
A simple path is a path such that all vertices are distinct (different), except that the
first and last vertexes are same.
Simple path for the above graph {A, B, C, D, A}. First and Last vertex are the same ie. A

Cycle
A cycle in a graph is a path in which the first and the last vertex are the same.

Cyclic Graph
A graph which has cycles is referred to as cyclic graph. A graph is said to be cyclic, if
the edges in the graph should form a cycle.

Acyclic Graph
A graph is said to be acyclic, if the edges in the graph does not form a cycle.

Directed Acyclic Graph (DAG)


A directed graph is acyclic if it has no cycles, and such types of graph is called as
Directed Acyclic Graph.
170
www.cseitquestions.in

Degree
The number of edges incident on a vertex determines its degree. The degree of the
vertex V is written as degree (V).
Indegree : The indegree of the vertex V, is the number of edges entering into the vertex V.
Outdegree: The outdegree of the vertex V, is the number of edges exiting from the vertex V.
Indegree of vertex V1 = 2
V1

V2

Outdegree of vertex V1 = 1
Indegree of vertex V2 = 1

V4

Outdegree of vertex V2 = 2

V3

Representation of Graph
A Graph can be represented in two ways.
i.

Adjacency Matrix

ii.

Adjacency List

Adjacency Matrix Representation


i.

Adjacency matrix for directed graph

ii.

Adjacency matrix for undirected graph

iii.

Adjacency matrix for weighted graph

Adjacency matrix for directed graph


One simple way to represent a graph is Adjacency matrix. The adjacency matrix A for
a graph G = (V, E) with n vertices is an n x n matrix, such that
Aij = 1, if there is an edge Vi to
Vj Aij = 0, if there is no edge
V1

V3

V2

V4

Adjacency matrix for undirected graph


V1

V4

V2

V3

171
www.cseitquestions.in

Adjacency matrix for weighted graph


3
V1

V2

V3

V4

8
Here Aij = Cij if there exists an edge from Vi to Vj. (Cij is the weight or
cost). Aij = 0, if there is no edge.
If there is no arc from i to j, C[i,j] = , where i j.
Advantage

Simple to implement.
Disadvantage

Takes O(n2) space to represents the graph.

Takes O(n ) time to solve most of the problem.

Adjacency List Representation


In this representation, we store the graph as a linked structure. We store all vertices in
a list and then for each vertex, we have a linked list of its adjacency vertices.
Adjacency List for directed unweighted graph

172
www.cseitquestions.in

Disadvantage of Adjacency list representation


It takes O(n) time to determine whether there is an arc from vertex i to vertex j, since
there can be O(n) vertices on the adjacency list for vertex i.

5.2 BREADTH FIRST TRAVERSAL:


Breadth-first search starts at a given vertex s, which is at level 0. In the first stage, we
visit all the vertices that are at the distance of one edge away. When we visit there, we paint
as "visited," the vertices adjacent to the start vertex s - these vertices are placed into level 1.
In the second stage, we visit all the new vertices we can reach at the distance of two edges
away from the source vertex s. These new vertices, which are adjacent to level 1 vertices and
not previously assigned to a level, are placed into level 2, and so on. The BFS traversal
terminates when every vertex has been visited.
To keep track of progress, breadth-first-search colors each vertex. Each vertex of the
graph is in one of three states:
1. Undiscovered;
2. Discovered but not fully explored; and
3. Fully explored.

The state of a vertex, u, is stored in a color variable as follows:


1. color[u] = White - for the "undiscovered" state,
2. color [u] = Gray - for the "discovered but not fully explored" state, and
3. color [u] = Black - for the "fully explored" state.

The BFS(G, s) algorithm develops a breadth-first search tree with the source vertex, s,
as its root. The parent or predecessor of any other vertex in the tree is the vertex from which it
was first discovered. For each vertex, v, the parent of v is placed in the variable [v]. Another
variable, d[v], computed by BFS contains the number of tree edges on the path from s to v.
The breadth-first search uses a FIFO queue, Q, to store gray vertices.

Algorithm: Breadth-First Search Traversal


BFS(V, E, s)
1.
2.

for each u in V {s}

for each vertex u in V[G] except s.

do color[u] WHITE

173
www.cseitquestions.in

3.

d[u] infinity

4.

[u] NIL

5.

color[s] GRAY

6.

d[s] 0

initialize

7.

[s] NIL

initialize

8.

Q {}

Source vertex discovered

Clear queue Q

9.

ENQUEUE(Q, s)

10

while Q is non-empty
do u DEQUEUE(Q)

11.
12.

That is, u = head[Q]


for loop for every node along with edge.

for each v adjacent to u


do if color[v] WHITE

13.

if color is white you've never seen it before

then color[v] GRAY

14.
15.

d[v] d[u] + 1

16.

[v] u

17.

ENQUEUE(Q, v)

18.

DEQUEUE(Q)

19.

color[u] BLACK

Example:
The following figure illustrates the progress of breadth-first search on the undirected
sample graph.
a. After initialization (paint every vertex white, set d[u] to infinity for each vertex u, and set
the parent of every vertex to be NIL), the source vertex is discovered in line 5. Lines 8-9
initialize Q to contain just the source vertex s.

b. The algorithm discovers all vertices 1 edge from s i.e., discovered all vertices (w and r) at
level 1.

174
www.cseitquestions.in

c.

d. The algorithm discovers all vertices 2 edges from s i.e., discovered all vertices (t, x, and v)
at level 2.

e.

f.

g. The algorithm discovers all vertices 3 edges from s i.e., discovered all vertices (u and y) at
level 3.

h.

i. The algorithm terminates when every vertex has been fully explored.

175
www.cseitquestions.in

5.3 DEPTH FIRST TRAVERSAL:


Depth First works by selecting one vertex V of G as a start vertex, V is marked
visited. Then each unvisited vertex adjacent to V is searched in turn using depth first search
recursively. This process continues until a deadend i.e., a vertex with no adjacent unvisited
vertices is encountered. At the deadend the algorithm backup one edge to the vertex it came
from and tries to continue visiting unvisited vertices from there.
The algorithm halts after backing up to the starting vertex, with the latter being a
deadend. By then, all the vertices in the same connected component as the starting vertex
have been visited. If unvisited vertices still remain, the depth first search must be restarted at
any one of them.
The two important key points of depth first search are:

If path exists from one node to another node walk across the edge exploring the edge.

If path does not exist from one specific node to any other node, return to the previous

node where we have been before backtracking.


The theme of depth first search is to explore if possible, otherwise backtrack.
To implement the DFS perform the following steps
1. Choose any node in the graph. Designate it as the search node and mark it as visited.
2. Using the adjacency matrix of the graph, find a node adjacent to the search node that
has not been visited yet. Designate this as the new search node and mark it as visited.
3. Repeat step2 using the new search node. If no nodes satisfying (2) can be found, return
to the previous search node and continue from there.
4. When return to the previous search node in (3) is impossible, the search from the
originally chosen search node is complete.
5. If the graph still contains unvisited nodes, choose any node that has not been visited and
repeat step 1 through step 4.
Routine for Depth First Search
void DFS (Vertex V)
{
visited [V] = True;
for each W adjacent to
V if(!visited[W])
DFS(W);
}
.
176
www.cseitquestions.in

Depth First Search Vs Breadth First Search


Depth First Search

Breadth First search

Back tracking is possible from a dead end.

Backtracking is not possible.

Vertices

from

which

exploration

is The vertices to be explored are organized as a

incomplete are processed in a LIFO order.

FIFO order.

Search is done in one particular direction.

The vertices in the same level are maintained


parallelly. (left to right)

5.4 TOPOLOGICAL SORT:


A topological sort is an ordering of vertices in a directed acyclic graph, such that if
there is a path from vi to vj, then vj appears after vi in the linear ordering.
Topological ordering is not possible if the graph has a cycle, since for two vertices v
and w on the cycle, v precedes w and w precedes v.

Steps for implementing the topological sort


Step 1: Find the indegree for every vertex.

Step 2: Place te vertices whose indegree is 0 on the empty queue.


Step 3: Dequeue the vertex V and decrement the indegrees of all its adjacent vertices.
Step 4: Enqueue the vertex on the queue, if its degree falls to zero.
Step 5: Repeat from step 3 until the queue becomes empty.
Step 6: The topological ordering is the order in which the vertices dequeued.

Routine for Topological Sort


void Topsort( Graph G )
{
Queue Q;
int Counter = 0;
Vertex V, W;

Q = CreateQueue( NumVertex );
MakeEmpty( Q );
for each vertex V
if( Indegree[V] = = 0 )
Enqueue( V, Q );

177
www.cseitquestions.in

while( !IsEmpty( Q ) )
{
V = Dequeue( Q );
TopNum[V] = ++Counter; /* assign next number
*/ for each W adjacent to V
if( --Indegree[W] = 0 )
Enqueue( W, Q );
}
/

if( Counter != NumVertex )


Error("Graph has a cycle");
DisposeQueue( Q ); /* free the memory */

Example: Find the topological sort for the following graph.

Adjacency Matrix

178
www.cseitquestions.in

Solution
1. Number of 1s present in each column of adjacency matrix represents the indegree of
the corresponding vertex.
Indegree [V1] = 0

Indegree [V5] = 1

Indegree [V2] = 1

Indegree [V6] = 3

Indegree [V3] = 2

Indegree [V7] = 2

Indegree [V4] = 3
2. Enqueue the vertex, whose indegree is 0 and place it on the queue. Indegree of V1 is
0. So place it in the queue.
3. Dequeue the vertex V1 from the queue and decrement the indegrees of its adjacent
vertex V2 & V3. Indegree [V2] = 0, Indegree [V3] = 1. Now enqueue vertex V2
because its indegree is 0.
4. Dequeue the vertex V2 from the queue and decrement the indegrees of its adjacent
vertex V2 & V3. Indegree [V2] = 0, Indegree [V3] = 1. Now enqueue vertex V2
because its indegree is 0.

Vertex

-------------------------------------------------------------------------------v1

v2

v3

v4

v5

v6

v7

------------------------------------------------------------------------------enqueue v1

v2

v5

v4

v3

v7

v6

--------------------------------------------------------------------------------------------------------------------

dequeue v1v2

v5

v4

v3

v7

v6

Algorithm Analysis
The running time of this algorithm is O(|E| + |V|) where E represents the Edges and
v represents the vertices of the graph.

179
www.cseitquestions.in

5.5 MINIMUM SPANNING TREES:


A Spanning tree of an undirected graph, G is a tree formed from graph edges that
connects all vertices of G.

A Minimum Spanning tree of an undirected graph, G is a tree formed from graph


edges that connects all vertices of G at lowest cost.

A minimum spanning tree exists if and only if G is connected. The number of edges
in the minimum spanning tree is |V| -1.

The minimum spanning tree is a tree because it is acyclic, it is spanning because it


covers every vertex, and it is minimum because it covers with minimum cost.

The minimum spanning tree can be created using two algorithms, that is prims

algorithm and kruskals algorithm.


5.6 KRUSKAL AND PRIMS ALGORITHM:
5.6.1 KRUSKALS ALGORITHM
Kruskals algorithm used for solving minimum spanning tree problem.

Procedure
i.

Initially there are |V| single node trees. Each vertex is initially in its own set.

ii.

Select the edges (u,v) in the order of smallest weight and accepted if it does not cause
the cycle.

iii.

Adding an edge merges 2 trees into one.

iv.

Repeat step 2 until the tree contains all the vertices.

The strategy
i.

The edges are built into a minheap structure and each vertex is considered as a sigle
node tree.

ii.

The deletemin operation is used to find the minimum cost edge (u,v).

iii.

The vertices u and v are searched in the spanning tree set S and if the returned sets are
not same then (u,v) is added to the set s with the constraint that adding (u,v) will not
create a cycle in spanning tree set S.

iv.

Repeat step (ii) and (iii) until a spanning tree is constructed with |V| - 1 edges.

Example: Find the minimum spanning tree for the following graph.
180
www.cseitquestions.in

i.

Initially all the vertices are single node trees.

ii.

Select the smallest edge v1 to v4, both the nodes are different sets, it does not form
cycle.

iii.

Select the next smallest edge v6 to v7. These two vertices are different sets; it does
not form a cycle, so it is included in the MST.

iv.

Select the next smallest edge v1 to v2. These two vertices are different sets; it does
not form a cycle, so it is included in the MST.

v.

Select the next smallest edge v3 to v4. These two vertices are different sets; it does
not form a cycle, so it is included in the MST.

vi.

Select the next smallest edge v2 to v4 both v2 and v4 are same set, it forms cycle so
v2 v4 edge is rejected.

vii.

Select the next smallest edge v1 to v3, it forms cycle so v1 v3 edge is rejected.

viii.

Select the next smallest edge v4 to v7, it does not form a cycle so it is included in the
tree.

ix.

Select the next smallest edge v3 to v6, it forms a cycle so v3 v6 edge is rejected.

x.

Select the next smallest edge v5 to v7, it does not form a cycle so it is included in the
tree.
Edge

Weight Action

---------------------------(v1,v4)

Accepted

(v6,v7)

Accepted

(v1,v2)

Accepted

(v3,v4)

Accepted

(v2,v4)

Rejected

(v1,v3)

Rejected

(v4,v7)

Accepted
181
www.cseitquestions.in

(v3,v6)

Rejected

(v5,v7)

Accepted

Figure: Action of Kruskal's algorithm on G


All the nodes are included. The cost of minimum spanning tree = 16 (2 + 1+ 2 + 4 + 1 + 6).

Routine for kruskals algorithm


void kruskal( graph G )
{
int EdgesAccepted;
DisjSet S;
PriorityQueue H;
vertex u, v; SetType
uset, vset; Edge e;

Initialize( S );

// form a single node tree

ReadGraphIntoHeapArray( G, H );
BuildHeap( H );

182
www.cseitquestions.in

EdgesAccepted = 0;
while( EdgesAccepted < NumVertex-1 )
{
e = DeleteMin( H );

// Selection of minimum edge

uset = Find( u, S );
vset = Find( v, S );
if( uset != vset )
{
/* accept the edge */
EdgesAccepted++;
SetUnion( S, uset, vset );

}
}
}
5.6.2 PRIMS ALGORITHM
In this method, minimum spanning tree is constructed in successive stages. One node
is picked as a root and an edge is added (i.e) an associated vertex is added to the tree, until
all the vertices are present in the tree with |V| - 1 edges.

The Strategy
i.

One node is picked as a root node (u) from the given connected graph.

ii.

At each stage choose a new vertex v from u, by considering an edge (u,v) with
minimum cost among all edges from u, where u is already in the tree ad v is not in
the tree.

iii.

The prims algorithm table is constructed with three parameters. They are

iv.

known known vertex i.e.,


processed vertex is indicated by 1. Unknown
vertex is indicated by zero.
dv - Weight of the shortest arc connecting v to the known vertex.
pv - It contains last vertex (i.e.,) current vertex to cause a change in d v.

After selecting the vertex v, the update rule is applied for each unknown w adjacent
to v. The rule is dw = min (dw , Cw,v), that is more than one path exist between v to
w then dw is updated with minimum cost.

183
www.cseitquestions.in

Example:

i.

v1 is selected as initial node in the spanning tree and construct initial configuration of the
table.

ii.

Known

dv

pv

V1

V2

V3

V4

V5

V6

V7

v1 is declared as known vertex. Then its adjacent vertices v2, v3, v4 are updated.
T[v2].dist = min(T[v2].dist, Cv1,v2) = min ( ,2) = 2
T[v3].dist = min(T[v3].dist, Cv1,v3) = min ( ,4) = 2
T[v4].dist = min(T[v4].dist, Cv1,v4) = min ( ,1) = 2

Known dv

pv

V1

V2

V1

V3

V1

V4

V1

V5

V6

V7

184
www.cseitquestions.in

iii.

Among all adjacent vertices V2, V3, V4. V1 -> V4 distance is small. So V4 is selected and
declared as known vertex. Its adjacent vertices distance are updated.

V1 is not examined because it is known vertex.

No change in V2 , because it has dv = 2 and the edge cost from V4 -> V2 = 3.

T[v3].dist = min(T[v3].dist, Cv4,v3) = min (4 ,2) = 2


T[v5].dist = min(T[v5].dist, Cv4,v5) = min ( ,7) = 7
T[v6].dist = min(T[v6].dist, Cv4,v6 ) = min ( ,8) = 8
T[v7].dist = min(T[v7].dist, Cv4,v7 ) = min ( ,4) = 4

iv.

Known dv

pv

V1

V2

V1

V3

2
1

V4

V4

0
1

V5

V4

V6

V4

V7

V4

V7

V4

V1

Among all either we can select v2, or v3 whose dv = 2, smallest among v5, v6 and v7.

v2 is declared as known vertex.

Its adjacent
vertices are v1, v4 and v5. v1, v4 are known vertex, no change in their
dv value.
T[v5].dist = min(T[v5].dist, Cv2,v5) = min (7 ,10) = 7

Known dv

pv

V1

V2

V1

V3

V4

V4

V1

V5

7
8

V4

V6

0
0

V7

V4

V4

185
www.cseitquestions.in

v.

Among all vertices v3s dv value is lower so v3 is selected. v3s adjacent vertices are v1,
v4 and v6. No changes in v1 and v4.

T[v6].dist = min(T[v6].dist, Cv3,v6) = min (8 ,5) = 5

vi.

Known

dv

pv

V1

V2

V1

V3

V4

V4

V1

V5

V4

V6

V3

V7

V4

Among v5, v6, v7, v7s dv value is lesser, so v7 is selected. Its adjacent vertices are v4,
v4, and v6. No change in v4.
T[v5].dist = min(T[v5].dist, Cv7,v5) = min (7,6) = 6
T[v6].dist = min(T[v6].dist, Cv7,v6) = min (5,1) = 1

Known

dv

pv

V1

V2

V1

V3

V4

V4

V1

V5

V7

V6

V7

V7

V4

186
www.cseitquestions.in

vii.

viii.

Among v5 and v6, v6 is declared as known vertex. v6s adjacent vertices are v3, v4, and
v7, no change in dv value, all are known vertices.
v

Known

dv

pv

V1

V2

V1

V3

V4

V4

V1

V5

V7

V6

V7

V7

V4

Finally v5 is declared as known vertex. Its adjacent vertices are v2, v4, and v7, no change in
dv value, all are known vertices.
v

Known

dv

pv

V1

V2

V1

V3

V4

V4

1
1

1
6

V1

1
1

1
4

V7

V5
V6
V7

V7

V4

The minimum cost of spanning tree is 16.


www.cseitquestions.in

Page 187

Algorithm Analysis
2

The runnig time is O(|V| ) in case of adjacency list and O(|E| log |V|) in case of binary
heap.
Prims Algorithm
i.

Consider any vertex in the graph.

ii.

Process the vertex and add the vertex to the tree.

iii.

Find the smallest edge from the graph connecting the edge of the vertex in the tree,
such that it does not form a cycle.

iv.

Add the vertex to the tree.

v.

Repeat step 3 until the tree contains all the vertices in the graph.

Routine for prims Algorithm


void prims(Table T)
{
vertex v, w;
for( i=1; i<=Numvertex; i++)
{
T[i]. known = False;
T[i] . Dist = Infinity;
T[i]. path = 0;
}
for(;;)
{
//let v be the start vertex with the smallest distance
T[v] . Dist = 0;
T[v]. known = true;
for each w adjacent to v
if(!T[w] . known)
{
T[w] . Dist = Min(T[w]. Dist, Cv,w);
T[w]. path = v;
}
}
}

www.cseitquestions.in

Page 188

5.7 SHORTEST PATH ALGORITHMS:


An algorithm to find the shortest distance path between the source and destination
vertices is called the shortest path algorithm.
Types of shortest path problem
i. Single source shortest path
Given an input graph G = (V,E) and a distinguished vertex S, find the shortest
path from S to every other vertex in G.
Example: Dijkstras algorithm (weighted graph and unweighted graph).
ii. All pairs shortest path problem
Given an input graph G = (V,E). Find the shortest path from each vertex to all
vertices in a graph.
5.8 DIJKSTRAS ALGORITHM:
Unweighted shortest Path
In unweighted shortest path, all the edges are assigned to 1.
Required Information
i.

known Specifies whether the vertex is processed or not. It is set to 1 after it is


processed, otherwise 0. Initially all vertices are unknown, so all entries marked as 0.

ii.

dv it specifies distance form source to vertex. Initially all vertices are unreachable
except for S whose path length is zero.

iii.

pv It is book keeping variable, which allow us to print te actual path. i.e., the vertex
which makes the changes in dv.

Procedure to find the unweighted shortest path


i.

Assign the source node as S and Enqueue S.

ii.

Dequeue the vertex S from queue and assign the value of that vertex to be known and
then find its adjacency vertices.

iii.

If the distance of the adjacent vertices is equal to infinity then change the distance of
that vertex as the distance of its source vertex. Increment by 1 and enqueue the vertex.

iv.

Repeat step ii until the queue becomes empty.

Routine for unweighted shortest path


void unweighted( Table T )
{
Queue Q; Vertex v, w;
Q = CreateQueue( NumVertex );
www.cseitquestions.in

Page 189

MakeEmpty( Q );
Enqueue( S, Q );
while( !IsEmpty( Q ) )
{
v = Dequeue( Q );
T[v].known = True;
for each w adjacent to v
if( T[w].Dist = = INFINITY )
{
T[w].Dist = T[v].Dist + 1;
T[w].path = v;
Enqueue( w, Q );
}}
DisposeQueue( Q ); /* free the memory */
}
Example

i.

v3 is taken as source node and its path length is initialized to 0. v3 is inserted into Q.

www.cseitquestions.in

Known dv

pv

V1

V2

V3

V4

V5

V6

V7

V3

Page 190

ii.

v3 find its adjacent node whose path length is 1. v1, v6 are adjacent nodes to v3 and
inserted in to queue.
V3 Dequeued

iii.

Known

dv

pv

V1

V3

V2

V3

V4

V5

V6

V3

V7

V1 , V6

Find the adjacent node for v1. v2 and v4 are adjacent node for v1, v2 and v4 inserted
into the queue.

V1 Dequeued

iv.

Known

dv

pv

V1

V3

V2

V1

V3

V4

V1

V5

V6

V3

V7

V6 , V2 , V4

No adjacent vertices for v6. No change in path value for all vertices.

www.cseitquestions.in

Page 191

V6 Dequeued

v.

Known

dv

pv

V1

V3

V2

V1

V3

V4

V1

V5

V6

V3

V7

V2 , V4

Find the adjacent vertices for v2. v4 and v5 are adjacent nodes to v2 and inserted into
queue.
V2 Dequeued

vi.

Known

dv

pv

V1

V3

V2

V1

V3

V4

V1

V5

V2

V6

V3

V7

V4 , V5

Find the adjacent vertices for v4. v5, v6 and v7 are adjacent vertices. Minimum path
length for v7 is 3. v7 is inserted into queue.

www.cseitquestions.in

Page 192

V4 Dequeued

vii.

Known

dv

pv

V1

V3

V2

V1

V3

V4

V1

V5

V2

V6

V3

V7

V4

V5 , V7

An adjacent vertex for v5 is v7. Already found the minimum path length from v3 to
v7 is 3. So no change in dv and pv.
V5 Dequeued

viii.

Known

dv

pv

V1

V3

V2

V1

V3

V4

V1

V5

V2

V6

V3

V7

V4

V7

An adjacent vertex for v7 is v6. Already found the minimum path length from v3 to
v6 is 1. So no change in dv and pv.

www.cseitquestions.in

Page 193

V7 Dequeued
v

Known

dv

pv

V1

V3

V2

V1

V3

V4

V1

V5

V2

V6

V3

V7

1
Empty

V4

Algorithm Analysis
Running time is O(|E| + |V|)

Weighted Graph
The general method to solve the single source shortest path problem is known as
Dijkstras algorithm. It applied to weighted graph.
Procedure

It uses greedy technique.

It proceeds in stages.

selects a vertex v, which has the smallest d


v among all the unknown vertices and
Itdeclares
the shortest path from s to v is known.

The remainder consists of updating the value of dw.

We should set dw = dv + Cv, w, if the new value for dw would an improvement.

Example: Find the shortest path for the following graph.

www.cseitquestions.in

Page 194

1. v1 is taken as source.
v

Known dv

pv

V1

V2

V3

V4

V5

V6

0
0

0
0

V7

2. Now v1 is known vertex, marked as 1. Its adjacent vertices are v2, v4, pv and dv values
are updated
T[v2]. dist = Min (T[v2].dist, T[v1].dist + Cv1, v2) = Min ( , 0+2) = 2
T[v4]. dist = Min (T[v4].dist, T[v1].dist + Cv1, v4) = Min ( , 0+1) = 1

Known dv

pv

V1

V2

V1

V3

V4

V1

V5

V6

V7

3. Select the vertex with minimum distance away v2 and v4 . v4 is marked as known
vertex. Its adjacent vertices are v3, v5, v6 and v7 .
T[v3]. dist = Min (T[v3].dist, T[v4].dist + Cv4, v3) = Min ( , 1+2) = 3
T[v5]. dist = Min (T[v5].dist, T[v4].dist + Cv4, v5) = Min ( , 1+2) = 3
T[v6]. dist = Min (T[v6].dist, T[v4].dist + Cv4, v6) = Min ( , 1+8) = 9
T[v7]. dist = Min (T[v7].dist, T[v4].dist + Cv4, v7) = Min ( , 1+4) = 5

www.cseitquestions.in

Page 195

Known dv

pv

V1

V2

V1

V3

V4

V4

V1

V5

V4

V6

V4

V7

V4

4. Select the vertex which is shortest distance from source v1. v2 is smallest one. v2 is
marked as known vertex. Its adjacent vertices are v4 ad v5. The distance from v1 to v4
and v5 through v2 is more comparing with previous value of dv. No change in dv and pv
value.

Known dv

pv

V1

V2

V1

V3

V4

V4

V1

V5

V4

V6

V4

V7

V4

5. Select the next smallest vertex from source. v3 and v5 are smallest one. Adjacent
vertices for v3 is v1 and v6. v1 is source there is no change in dv and pv
T[v6]. dist = Min (T[v6].dist, T[v3].dist + Cv3, v6) = Min (9 , 3+5) = 8
dv and pv values are updated. Adjacent vertices for v5 is v7. No change in dv and pv
value.

www.cseitquestions.in

Page 196

Known dv

pv

V1

V2

V1

V3

V4

V4

V1

V5

V4

V6

V3

V7

V4

6. Next smallest vertex v7. Its adjacent vertex is v6.

T[v6]. dist = Min

(T[v6].dist, T[v7].dist + Cv7, v6) = Min (8 , 5+1) = 6


dv and pv values are updated.
v

Known dv

pv

V1

V2

V1

V3

V4

V4

V1

V5

V4

V6

V7

V7

V4

7. The last vertex v6 is declared as known. No adjacent vertices for v6. No updation in the
table.
v
V1

Known dv
1
0

pv

V2

V1

V3

V4

V4

V1

V5

V4

V6

1
1

6
5

V7

V7

www.cseitquestions.in

V4

Page 197

The shortest distance from source v1 to all


vertices. v1 -> v2 = 2
v1 -> v3 = 3
v1 -> v4 = 1
v1 -> v5 = 3
v1 -> v6 = 6
v1 -> v7 = 5

Algorithm Analysis
Time complexity of this algorithm
2

O(|E| + |V| ) = O(|V| )


Declarations for Dijkstras algorithm
typedef int Vertex;
struct TableEntry
{
List header;

/* Adjacency List*/

int known;
DistType Dist;
Vertex Path
};
/* Vertices are numbered from 0*/
#define NotAVertex (-1)
typedef struct TableEntry Table[NumVertex];
Table Initialization routine
void InitTable(Vertex Start, Graph G, Table T)
{
int i;
ReadGraph(G,T);
for (i=0; i<NumVertex; i++)
{
T[i].known = False;
T[i]. Dist = Infinity;
T[i]. Path = NotAVertex;
}
www.cseitquestions.in

Page 198

T[Start]. Dist = 0;
}
Routine to print the actual shortest path
void Printpath(Vertex V, Table T)
{
if(T[V]. Path != NotAVertex)
{
PrintPath(T[V]. Path, T);
printf(to);
}
printf(%v, V);
/* %v is pseudocode*/
}
Pseudocode for Dijkstras algorithm
void Dijkstra(Table T)
{
Vertex v, w;
for( ; ;)
{
v = smallest unknown distance
vertex; if( v = = NotAVertex)
break;
T[v]. kown = True;
for each w adjacent to v
if(!T[w].known)
if(T[v].Dist + Cvw < T[w]. Dist)
{
/* update w*/
Decrease(T[w]. Dist to T[v].Dist + Cvw);
T[w]. path = v;
}
}
}

www.cseitquestions.in

Page 199

5.9 BELLMAN-FORD ALGORITHM:


Single Source Shortest Path
Problem
Given a directed graph G(V,E) with weighted edges w(u,v), define the path weight of
a path p as

For a given source vertex s, find the minimum weight paths to every vertex reachable
from s denoted

The final solution will satisfy certain caveats:

The graph cannot contain any negative weight cycles (otherwise there would
be no minimum path since we could simply continue to follow the negative

weight cycle producing a path weight of -).

The solution cannot have any positive weight cycles (since the cycle could
simply be removed giving a lower weight path).

The solution can be assumed to have no zero weight cycles (since they would
not affect the minimum value).

Therefore given these caveats, we know the shortest paths must be acyclic (with |V| distinct vertices) |V| - 1 edges in each path.

Generic Algorithm
The single source shortest path algorithms use the same notation as BFS with
predecessor and distance d fields for each vertex. The optimal solution will have v.d =
(s,v) for all v V.

The solutions utilize the concept of edge relaxation which is a test to determine
whether going through edge (u,v) reduces the distance to v and if so update v. and v.d. This
is accomplished using the condition

www.cseitquestions.in

Page 200

Bellman-Ford Algorithm
The Bellman-Ford algorithm uses relaxation to find single source shortest paths on
directed graphs that may contain negative weight edges. The algorithm will also detect if
there are any negative weight cycles (such that there is no solution).

BELLMAN-FORD(G,w,s)
1. INITIALIZE-SINGLE-SOURCE(G,s)
2. for i = 1 to |G.V|-1
3.

4.

for each edge (u,v) G.E

RELAX(u,v,w)

5. for each edge (u,v) G.E

6.
7.

if v.d > u.d + w(u,v)


return FALSE

8. return TRUE

INITIALIZE-SINGLE-SOURCE(G,s)
1. for each vertex v G.V

2.

v.d =

3.

v.pi = NIL

4. s.d = 0

RELAX(u,v,w)
1. if v.d > u.d + w(u,v)
2.

v.d = u.d + w(u,v)

3.

v.pi = u

Basically the algorithm works as follows:


1.

Initialize d's, 's, and set s.d = 0 O(V)

2.

Loop |V|-1 times through all edges checking the relaxation condition to compute minimum distances (|V|-1) O(E) = O(VE)

3.

Loop through all edges checking for negative weight cycles which occurs if any of the relaxation conditions fail O(E)

The run time of the Bellman-Ford algorithm is O(V + VE + E) = O(VE).


www.cseitquestions.in

Page 201

Note that if the graph is a DAG (and thus is known to not have any cycles), we can
make Bellman-Ford more efficient by first topologically sorting G (O(V+E)), performing the
same initialization (O(V)), and then simply looping through each vertex u in topological
order relaxing only the edges in Adj[u] (O(E)). This method only takes O(V + E) time. This
procedure (with a few slight modifications) is useful for finding critical paths for PERT
charts.

Example:
Given the following directed graph

Using vertex 5 as the source (setting its distance to 0), we initialize all the other distances to
.

Iteration 1: Edges (u5,u2) and (u5,u4) relax updating the distances to 2 and 4

www.cseitquestions.in

Page 202

Iteration 2: Edges (u2,u1), (u4,u2) and (u4,u3) relax updating the distances to 1, 2, and 4
respectively. Note edge (u4,u2) finds a shorter path to vertex 2 by going through vertex 4

Iteration 3: Edge (u2,u1) relaxes (since a shorter path to vertex 2 was found in the previous
iteration) updating the distance to 1

Iteration 4: No edges relax

The final shortest paths from vertex 5 with corresponding distances is

www.cseitquestions.in

Page 203

Negative cycle checks: We now check the relaxation condition one additional time for each
edge. If any of the checks pass then there exists a negative weight cycle in the graph.

v3.d > u1.d + w(1,3) 4 6 + 6 = 12 v4.d > u1.d + w(1,4)

2 6 + 3 = 9 v1.d > u2.d + w(2,1) 6 3 + 3 = 6 v4.d >

u3.d + w(3,4) 2 3 + 2 = 5 v2.d > u4.d + w(4,2) 3 2 +

1 = 3 v3.d > u4.d + w(4,3) 3 2 + 1 = 3 v2.d > u5.d +

w(5,2) 3 0 + 4 = 4 v4.d > u5.d + w(5,4) 2 0 + 2 = 2

Note that for the edges on the shortest paths the relaxation criteria gives equalities.
Additionally, the path to any reachable vertex can be found by starting at the vertex and
following the 's back to the source. For example, starting at vertex 1, u1. = 2, u2. = 4, u4.
= 5 the shortest path to vertex 1 is {5,4,2,1}.

5.10 FLOYD - WARSHALL ALGORITHM:


The Floyd-Warshall algorithm works based on a property of intermediate vertices of a
shortest path. An intermediate vertex for a path p = <v1, v2, ..., vj> is any vertex other than v1
or vj.
If the vertices of a graph G are indexed by {1, 2, ..., n}, then consider a subset of
vertices {1, 2, ..., k}. Assume p is a minimum weight path from vertex i to vertex j whose
intermediate vertices are drawn from the subset {1, 2, ..., k}. If we consider vertex k on the
path then either:

k is not an intermediate vertex of p (i.e. is not used in the minimum weight path)

All intermediate vertices are in {1, 2, ..., k-1}

k is an intermediate vertex of p (i.e. is used in the minimum weight path)

We can divide p at k giving two subpaths p1 and p2 giving vi k vj


Subpaths p1 and p2 are shortest paths with intermediate vertices in {1, 2, ..., k-1}

www.cseitquestions.in

Page 204

(k)
ij as the minimum weight of the path from vertex i to

Thus if we define a quantity d

vertex j with intermediate vertices drawn from the set {1, 2, ..., k} the above properties give
the following recursive solution

Thus we can represent the optimal values (when k = n) in a matrix as

Algorithm
FLOYD-WARSHALL(W)
1. n = W.rows
(0)

2. D

(0)

3.

=W
(0)

ij = NIL if i=j or wij =

= i if ij and wij <


4. for k = 1 to n
(k)

(k)
ij) be a new nxn matrix

5.

let D

6.

for i = 1 to n

7.

= (d

for j = 1 to n

10.

(k-1)
(k-1)
(k-1)
ij, d
ik + d
kj)
(k-1)
(k-1)
(k-1)
if d
ij d
ik + d
kj
(k)
(k-1)
ij =
ij

11.

else

12.

8.
9.

d ij = min(d

(k)
(k-1)
ij =
kj
(n)

13. return D

Basically the algorithm works by repeatedly exploring paths between every pair using
each vertex as an intermediate vertex. Since Floyd-Warshall is simply three (tight) nested
3

loops, the run time is clearly O(V ).


Example:

www.cseitquestions.in

Page 205

Initialization: (k = 0)

Iteration 1: (k = 1) Shorter paths from 2 3 and 2 4 are found through vertex 1

Iteration 2: (k = 2) Shorter paths from 4 1, 5 1, and 5 3 are found through vertex 2

Iteration 3: (k = 3) No shorter paths are found through vertex 3

www.cseitquestions.in

Page 206

Iteration 4: (k = 4) Shorter paths from 1 2, 1 3, 2 3, 3 1, 3 2, 5 1, 5 2, 5 3, and 5 4 are found through vertex 4

Iteration 5: (k = 5) No shorter paths are found through vertex 5

The final shortest paths for all pairs is given by

Transitive Closure
Floyd-Warshall can be used to determine whether or not a graph has transitive closure, i.e.
whether or not there are paths between all vertices.

Assign all edges in the graph to have weight = 1

Run Floyd-Warshall

Check if all dij < n

www.cseitquestions.in

Page 207

Vous aimerez peut-être aussi