207
1 http://www.francisxavier.ac.in FRANCIS XAVIER ENGINEERING COLLEGE TIRUNELVELI 627003. [ISO 9001: 2000 CERTIFIED INSTITUTION] DEPARTMENT OF INFORMATION TECHNOLOGY CS6301 PROGRAMMING AND DATASTRUCTURES II LECTURE NOTES

C++ fundamentals

Embed Size (px)

DESCRIPTION

This gives details of C++ its uasage, graph applications

Citation preview

Page 1: C++ fundamentals

1

http://www.francisxavier.ac.in

FRANCIS XAVIER ENGINEERING COLLEGE

TIRUNELVELI – 627003.

[ISO 9001: 2000 CERTIFIED INSTITUTION]

DEPARTMENT OF INFORMATION

TECHNOLOGY

CS6301 – PROGRAMMING AND

DATASTRUCTURES II

LECTURE NOTES

Page 2: C++ fundamentals

2

http://www.francisxavier.ac.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.

Page 3: C++ fundamentals

3

http://www.francisxavier.ac.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.

Page 4: C++ fundamentals

4

http://www.francisxavier.ac.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:

Page 5: C++ fundamentals

5

http://www.francisxavier.ac.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.

Page 6: C++ fundamentals

6

http://www.francisxavier.ac.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.

Page 7: C++ fundamentals

7

http://www.francisxavier.ac.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);

Page 8: C++ fundamentals

8

http://www.francisxavier.ac.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 member‟s

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.

Page 9: C++ fundamentals

9

http://www.francisxavier.ac.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.

Page 10: C++ fundamentals

10

http://www.francisxavier.ac.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;

}

Page 11: C++ fundamentals

11

http://www.francisxavier.ac.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,s2,s3 are objects(variables) of class Student

s1.rollno=28; 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.

Page 12: C++ fundamentals

12

http://www.francisxavier.ac.in

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

{

Class student

Function Members:

Void getdetail()

Void printdetail()

Object s1:

Data Member Name

Data Member Rollno

Data Member age

Object s2:

Data Member Name

Data Member Rollno

Data Member age

Object s3:

Data Member Name

Data Member Rollno

Data Member age

Page 13: C++ fundamentals

13

http://www.francisxavier.ac.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;

Page 14: C++ fundamentals

14

http://www.francisxavier.ac.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

Page 15: C++ fundamentals

15

http://www.francisxavier.ac.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();

}

Page 16: C++ fundamentals

16

http://www.francisxavier.ac.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()

{

}

}

Page 17: C++ fundamentals

17

http://www.francisxavier.ac.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();

Page 18: C++ fundamentals

18

http://www.francisxavier.ac.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)

{

Page 19: C++ fundamentals

19

http://www.francisxavier.ac.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

}

Page 20: C++ fundamentals

20

http://www.francisxavier.ac.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();

}

Page 21: C++ fundamentals

21

http://www.francisxavier.ac.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();

}

Page 22: C++ fundamentals

22

http://www.francisxavier.ac.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 non-

static member function can access all of the above including the static data member.

Page 23: C++ fundamentals

23

http://www.francisxavier.ac.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.

Page 24: C++ fundamentals

24

http://www.francisxavier.ac.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:

Page 25: C++ fundamentals

25

http://www.francisxavier.ac.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.

Page 26: C++ fundamentals

26

http://www.francisxavier.ac.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;

Page 27: C++ fundamentals

27

http://www.francisxavier.ac.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;

Page 28: C++ fundamentals

28

http://www.francisxavier.ac.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>

Page 29: C++ fundamentals

29

http://www.francisxavier.ac.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

{

Page 30: C++ fundamentals

30

http://www.francisxavier.ac.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

Page 31: C++ fundamentals

31

http://www.francisxavier.ac.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)

{

Page 32: C++ fundamentals

32

http://www.francisxavier.ac.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

Page 33: C++ fundamentals

33

http://www.francisxavier.ac.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;

}

Page 34: C++ fundamentals

34

http://www.francisxavier.ac.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++:

Page 35: C++ fundamentals

35

http://www.francisxavier.ac.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 ()

Page 36: C++ fundamentals

36

http://www.francisxavier.ac.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

Page 37: C++ fundamentals

37

http://www.francisxavier.ac.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:

Page 38: C++ fundamentals

38

http://www.francisxavier.ac.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,

Page 39: C++ fundamentals

39

http://www.francisxavier.ac.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.

Page 40: C++ fundamentals

40

http://www.francisxavier.ac.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

Page 41: C++ fundamentals

41

http://www.francisxavier.ac.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,

Page 42: C++ fundamentals

42

http://www.francisxavier.ac.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;

Page 43: C++ fundamentals

43

http://www.francisxavier.ac.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();

}

Page 44: C++ fundamentals

44

http://www.francisxavier.ac.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:

Page 45: C++ fundamentals

45

http://www.francisxavier.ac.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( );

Page 46: C++ fundamentals

46

http://www.francisxavier.ac.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 .*

Page 47: C++ fundamentals

47

http://www.francisxavier.ac.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;

Page 48: C++ fundamentals

48

http://www.francisxavier.ac.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 multi-

dimensional array as follows:

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

pvalue = new double [3][4]; // Allocate memory for a 3x4 array

Page 49: C++ fundamentals

49

http://www.francisxavier.ac.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!

Page 50: C++ fundamentals

50

http://www.francisxavier.ac.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();

}

Page 51: C++ fundamentals

51

http://www.francisxavier.ac.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();

}

Page 52: C++ fundamentals

52

http://www.francisxavier.ac.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.

Page 53: C++ fundamentals

53

http://www.francisxavier.ac.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:

Page 54: C++ fundamentals

54

http://www.francisxavier.ac.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

Page 55: C++ fundamentals

55

http://www.francisxavier.ac.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";

Page 56: C++ fundamentals

56

http://www.francisxavier.ac.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();

}

Page 57: C++ fundamentals

57

http://www.francisxavier.ac.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 collname fx dept cse

sub1 Total 100 sub2 100 sub3 100

2.9.3 Multilevel Inheritance

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

inheritance.

Page 58: C++ fundamentals

58

http://www.francisxavier.ac.in

Example:

#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()

STUDENT

TEST

RESULT

Page 59: C++ fundamentals

59

http://www.francisxavier.ac.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();

Page 60: C++ fundamentals

60

http://www.francisxavier.ac.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

Page 61: C++ fundamentals

61

http://www.francisxavier.ac.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++.

Page 62: C++ fundamentals

62

http://www.francisxavier.ac.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)

Page 63: C++ fundamentals

63

http://www.francisxavier.ac.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;

Page 64: C++ fundamentals

64

http://www.francisxavier.ac.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.

Page 65: C++ fundamentals

65

http://www.francisxavier.ac.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);

}

Page 66: C++ fundamentals

66

http://www.francisxavier.ac.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().

Page 67: C++ fundamentals

67

http://www.francisxavier.ac.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

an error message is displayed

the program is terminated

Programs are allowed to trap

exceptions.

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)

Page 68: C++ fundamentals

68

http://www.francisxavier.ac.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

Page 69: C++ fundamentals

69

http://www.francisxavier.ac.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

Page 70: C++ fundamentals

70

http://www.francisxavier.ac.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>

int main()

{

int i,j;

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

j=0;

try

{

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

}

catch( int a)

{ // catch an error

cout << "The Number Caught is : ";

cout << a << "\n";

}

cout << "Ends here";

return 0;

}

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.

Page 71: C++ fundamentals

71

http://www.francisxavier.ac.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 compute(int a,int b)

{

int c; if(b==0)

{

throw b;

else

c=a/b;

}

cout<<”RESULT OF THE DIVISION”<<c;

}

void main()

{

int x,y;

cout<<”ENTER TWO NUMBERS”;

cin>>x>y;

try

{

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

}

catch(int k)

{

cout<<”Divide By Zero exception”;

}

}

Page 72: C++ fundamentals

72

http://www.francisxavier.ac.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)IPLUS.COM

Page 73: C++ fundamentals

73

http://www.francisxavier.ac.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)

Page 74: C++ fundamentals

74

http://www.francisxavier.ac.in

{

cout<<”Float value is thrown”<<f;

}

}

void main()

{

cout<<”Main Program”<<endl;

multiple_catch(0);

multiple_catch(1);

multiple_catch(5);

}

Rethrowing ExceptionsTHIPLUS.COM

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;

}

Page 75: C++ fundamentals

75

http://www.francisxavier.ac.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

}

}

Page 76: C++ fundamentals

76

http://www.francisxavier.ac.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);

Page 77: C++ fundamentals

77

http://www.francisxavier.ac.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.

Page 78: C++ fundamentals

78

http://www.francisxavier.ac.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:THIPLUS.COM

Provides facilities for formatted and unformatted input operations.

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

Overloaded extraction operator (>>)

Page 79: C++ fundamentals

79

http://www.francisxavier.ac.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);

Page 80: C++ fundamentals

80

http://www.francisxavier.ac.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()

Page 81: C++ fundamentals

81

http://www.francisxavier.ac.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..VIDYARTHIPLUS.COM

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 you write "templates" of source codes that the compiler in the process of compilation transforms into source codes. The simplest example for generic programming is container classes like arrays, lists or maps that contain a

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

Page 82: C++ fundamentals

82

http://www.francisxavier.ac.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;

};

Page 83: C++ fundamentals

83

http://www.francisxavier.ac.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.COM

else cout<<real<<image<"i";

}

}

;

void main()

{

clrscr();

complex <int> obj1;

obj1.getdata();

obj1.putdata();

complex <float> obj2;

obj2.getdata();

obj2.putdata();

getch();

}

Page 84: C++ fundamentals

84

http://www.francisxavier.ac.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])

{S.COM

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++)

{

Page 85: C++ fundamentals

85

http://www.francisxavier.ac.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); // calling function template 1

GenericBubbleSort( Array3 ); // calling function template 2

}

Sample output:

6 6 4 2 1

s k f d a

9.4 7 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>

Page 86: C++ fundamentals

86

http://www.francisxavier.ac.in

void display(T1 a, T2 b)

{

cout<<a<<"\n"<<b<<"\n";

}DYARTHIPLUS.COM

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.

Page 87: C++ fundamentals

87

http://www.francisxavier.ac.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

Page 88: C++ fundamentals

88

http://www.francisxavier.ac.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.

Page 89: C++ fundamentals

89

http://www.francisxavier.ac.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, that

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

Page 90: C++ fundamentals

90

http://www.francisxavier.ac.in

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.

Page 91: C++ fundamentals

91

http://www.francisxavier.ac.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

Page 92: C++ fundamentals

92

http://www.francisxavier.ac.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 std::allocator_traits, not directly.

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

Page 93: C++ fundamentals

93

http://www.francisxavier.ac.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)

Page 94: C++ fundamentals

94

http://www.francisxavier.ac.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;

Page 95: C++ fundamentals

95

http://www.francisxavier.ac.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

{

Page 96: C++ fundamentals

96

http://www.francisxavier.ac.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();

}

Page 97: C++ fundamentals

97

http://www.francisxavier.ac.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 doesn‟t 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.

Page 98: C++ fundamentals

98

http://www.francisxavier.ac.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.

Page 99: C++ fundamentals

99

http://www.francisxavier.ac.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 N-

1 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;

Page 100: C++ fundamentals

100

http://www.francisxavier.ac.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);

Page 101: C++ fundamentals

101

http://www.francisxavier.ac.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);

}

}

Page 102: C++ fundamentals

102

http://www.francisxavier.ac.in

Example

Inorder : 1 2 3 4 5 6 7

Preorder: 4 2 1 3 6 5 7

Postorder: 1 3 2 5 7 6 4

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;

Page 103: C++ fundamentals

103

http://www.francisxavier.ac.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.

Fig: Left skew tree Fig: Right skew tree

A

B

C C

B

A

Page 104: C++ fundamentals

104

http://www.francisxavier.ac.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

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

– 1 nodes.

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

left to right.

v. 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.

G F E D

B C

A

G F E D

B C

A

H

G F E D

B C

A

H I

Page 105: C++ fundamentals

105

http://www.francisxavier.ac.in

Comparison between General Tree and Binary Tree

Sl. No General Tree Binary Tree

1. General tree has any number of children. A binary tree has not more than two

children

2. Evaluating any expression is difficult in

general trees.

Evaluation of expression is easy in

binary tree.

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 Binary search tree

A tree is said to be a binary 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.

Page 106: C++ fundamentals

106

http://www.francisxavier.ac.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.

Page 107: C++ fundamentals

107

http://www.francisxavier.ac.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.

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

subtree.

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

Page 108: C++ fundamentals

108

http://www.francisxavier.ac.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 ) {

return T; T = T->Left;

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; {

else while(T-

>Right!=NULL)

if( T->Right = = NULL ) {

return T; T = T->Right;

else }}

return FindMax ( T->Right ) ; return T;

} }

Insert

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

Page 109: C++ fundamentals

109

http://www.francisxavier.ac.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

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.

8 4

8

Page 110: C++ fundamentals

110

http://www.francisxavier.ac.in

vi. 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

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.

4

8

1

4

8

1 6

5

4

8

1 6

7 5

4

8

1 6

10

7 5

4

8

1 6

4

8

1 6

4

8

1

Page 111: C++ fundamentals

111

http://www.francisxavier.ac.in

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 P‟s 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 P‟s left sub tree.

Rule 2: The node with the smallest value in P‟s right sub tree.

Eg: Deletion of a node 4 with two children, before and after

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 );

5

4

8

1 6

5

8

1 6

Page 112: C++ fundamentals

112

http://www.francisxavier.ac.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 α.

Page 113: C++ fundamentals

113

http://www.francisxavier.ac.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

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

1

5

8

3 7

9

7

8 3

5

1 9

Page 114: C++ fundamentals

114

http://www.francisxavier.ac.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

Page 115: C++ fundamentals

115

http://www.francisxavier.ac.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.

Page 116: C++ fundamentals

116

http://www.francisxavier.ac.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)

{

Page 117: C++ fundamentals

117

http://www.francisxavier.ac.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 right-

left 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.

Page 118: C++ fundamentals

118

http://www.francisxavier.ac.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);

Page 119: C++ fundamentals

119

http://www.francisxavier.ac.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)

{

Page 120: C++ fundamentals

120

http://www.francisxavier.ac.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.

Page 121: C++ fundamentals

121

http://www.francisxavier.ac.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;

Page 122: C++ fundamentals

122

http://www.francisxavier.ac.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 no children)

return false;

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.

Page 123: C++ fundamentals

123

http://www.francisxavier.ac.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

Page 124: C++ fundamentals

124

http://www.francisxavier.ac.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;

Page 125: C++ fundamentals

125

http://www.francisxavier.ac.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 B-

tree is still valid based on the looseRemoval rule.

Page 126: C++ fundamentals

126

http://www.francisxavier.ac.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.

Page 127: C++ fundamentals

127

http://www.francisxavier.ac.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(childCount-1)

return answer

}

}

Page 128: C++ fundamentals

128

http://www.francisxavier.ac.in

A more concrete example for node deletion:

Page 129: C++ fundamentals

129

http://www.francisxavier.ac.in

4.3 RED-BLACK TREES

A red–black 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

Page 130: C++ fundamentals

130

http://www.francisxavier.ac.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

Page 131: C++ fundamentals

131

http://www.francisxavier.ac.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:

Page 132: C++ fundamentals

132

http://www.francisxavier.ac.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

Page 133: C++ fundamentals

133

http://www.francisxavier.ac.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.

Page 134: C++ fundamentals

134

http://www.francisxavier.ac.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.

Page 135: C++ fundamentals

135

http://www.francisxavier.ac.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).

Page 136: C++ fundamentals

136

http://www.francisxavier.ac.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).

o 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).

o 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.

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

Example: Delete 6

Page 137: C++ fundamentals

137

http://www.francisxavier.ac.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 Bk. 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,

1. There are 2k nodes,

Page 138: C++ fundamentals

138

http://www.francisxavier.ac.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 B0,

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.

Page 139: C++ fundamentals

139

http://www.francisxavier.ac.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

left-child, 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.

Page 140: C++ fundamentals

140

http://www.francisxavier.ac.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 NIL

5 do if key[x] < min

6 then min key[x]

7 y x

8 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 BINOMIAL-

HEAP-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

Page 141: C++ fundamentals

141

http://www.francisxavier.ac.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] z

2 sibling[y] child[z]

3 child[z] y

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.

Page 142: C++ fundamentals

142

http://www.francisxavier.ac.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.

Page 143: C++ fundamentals

143

http://www.francisxavier.ac.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.

Page 144: C++ fundamentals

144

http://www.francisxavier.ac.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.

Page 145: C++ fundamentals

145

http://www.francisxavier.ac.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 Bk+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' MAKE-BINOMIAL-HEAP()

2 p[x] NIL

3 child[x] NIL

4 sibling[x] NIL

5 degree[x] 0

6 head[H'] x

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)

Page 146: C++ fundamentals

146

http://www.francisxavier.ac.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'.

Page 147: C++ fundamentals

147

http://www.francisxavier.ac.in

Since each of lines 1-4 takes O(lg n) time if H has n nodes, BINOMIAL-HEAP-

EXTRACT-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] k

4 y x

5 z p[y]

6 while z NIL and key[y] < key[z]

7 do exchange key[y] key[z]

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

9 y z

10 z 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 of lines 6-

10, key[y] is checked against the key of y's parent z. If y is the root or key[y] key[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.

Page 148: C++ fundamentals

148

http://www.francisxavier.ac.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-DECREASE-

KEY. 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.

Page 149: C++ fundamentals

149

http://www.francisxavier.ac.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

binomial tree of order k has 2k 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

23 7 3

38 52 30 18

39 41

17

35

46 26

24

Min [H]

Page 150: C++ fundamentals

150

http://www.francisxavier.ac.in

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]

Page 151: C++ fundamentals

151

http://www.francisxavier.ac.in

Example:

Node 21 has been inserted

Red Nodes are marked nodes – they will become relevant only in the delete operation.

Extract Minimum Node

Amortized cost is O(D(n))

Make a root out of each of the minimum node‟s 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)

23 7 3

38 52 30 18

39 41

17

35

46 26

24

Min [H]

23 21 3

38 52 30 18

39 41

17

35

46 26

24

Min [H]

7

Page 152: C++ fundamentals

152

http://www.francisxavier.ac.in

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.

23

21 38 52

30

18

39 41 17

35

46 26

24

7

0 1 2 3 4

X

W

A

23

21 38 52

30

18

39 41 17

35

46 26

24

7

0 1 2 3 4

w,x

Page 153: C++ fundamentals

153

http://www.francisxavier.ac.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],

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

18

A

23

21 38 52

30

18

39 41 17

35

46 26

24

7

0 1 2 3 4

w,x

A

23 21

38

52 30

18

39 41 17

35

46 26

24

7

0 1 2 3 4

w,x

Page 154: C++ fundamentals

154

http://www.francisxavier.ac.in

The pointers of the auxiliary array are updated.

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

Extract-Min is now done.

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

A

23 21

38

52 30

18

39 41 17

35

46 26

24

7

0 1 2 3 4

w,x

23 21

38

52 30

18

39 41 17

35

46 26

24

7

min [H]

Page 155: C++ fundamentals

155

http://www.francisxavier.ac.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 x‟s parent y (relevant if parent is marked):

if unmarked: mark y, return

if marked: Cut y, recurse on node y‟s 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.

23 21

38

52 30

18

39 41 17

35

46 26

24

7

min [H]

Page 156: C++ fundamentals

156

http://www.francisxavier.ac.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.

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.

The cascading cut involves cutting the marked node, 26, unmarking it, and putting it

on the root list.

23 21

38

52 30

18

39 41 17

35

15

26

24

7

min [H]

23 21

38

52 30

18

39 41 17

5 15

26

24

7

min [H]

Page 157: C++ fundamentals

157

http://www.francisxavier.ac.in

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

node on the root list.

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.

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.

23 21

38

52 30

18

39 41 17

5 15 26

24

7

min [H]

23 21

38

52 30

18

39 41 17

5 15 26 24 7

min [H]

Page 158: C++ fundamentals

158

http://www.francisxavier.ac.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

union–find data structure or merge–find 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";

Page 159: C++ fundamentals

159

http://www.francisxavier.ac.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:

Page 160: C++ fundamentals

160

http://www.francisxavier.ac.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."

Page 161: C++ fundamentals

161

http://www.francisxavier.ac.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:

Page 162: C++ fundamentals

162

http://www.francisxavier.ac.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.

– Thus the cost of the sequence is O(n2). Correct, but not tight.

Page 163: C++ fundamentals

163

http://www.francisxavier.ac.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=1n

ci' i=1n 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.

– Total credits is i=1n

ci' - i=1n

ci , which should be nonnegative,

• Moreover, i=1t ci' - i=1

t 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.

Page 164: C++ fundamentals

164

http://www.francisxavier.ac.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 1‟s 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)

i=1n

ci' = i=1

n (ci + (Di) - (Di-1))

= i=1nci + (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.

Page 165: C++ fundamentals

165

http://www.francisxavier.ac.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 1‟s. 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.

Page 166: C++ fundamentals

166

http://www.francisxavier.ac.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. i0

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

3. do A[i]0 (flip, reset)

4. ii+1

5. if i<k

6. then A[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.

….

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

Thus total #flips is i=0k-1 n/2

i

< ni=0 1/2

i

=2n.

Page 167: C++ fundamentals

167

http://www.francisxavier.ac.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).

Page 168: C++ fundamentals

168

http://www.francisxavier.ac.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 –

Dijkstra’s 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.

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) ≠ (V2 , V1)

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) = (V2 , V1)

V1

V4 V3

V2

V1

V3

V2

V1

V3

V2

Page 169: C++ fundamentals

169

http://www.francisxavier.ac.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 5

4 6 6 7

6

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.

Number of vertices is 4

Number of edges is 6

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

V1

V3

V2 V1

V3

V2

V1

V4 V3

V2

Page 170: C++ fundamentals

170

http://www.francisxavier.ac.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

N–1. 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.

Page 171: C++ fundamentals

171

http://www.francisxavier.ac.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

Outdegree of vertex V1 = 1

Indegree of vertex V2 = 1

Outdegree of vertex V2 = 2

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

Adjacency matrix for undirected graph

0 1 1 0

0 0 0 1

0 1 0 0

0 0 1 0

0 1 0 1

1 0 1 1

0 1 0 1

1 1 1 0

V1

V4 V3

V2

V1

V3 V4

V2

V1

V4 V3

V2

Page 172: C++ fundamentals

172

http://www.francisxavier.ac.in

Adjacency matrix for weighted graph

3

9 1 7

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(n2) 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

0 3 9 ∞

∞ 0 ∞ 7

∞ 1 0 ∞

∞ ∞ 8 0

V1

V3 V4

V2

Page 173: C++ fundamentals

173

http://www.francisxavier.ac.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. for each u in V − {s} ▷ for each vertex u in V[G] except s.

2. do color[u] ← WHITE

Page 174: C++ fundamentals

174

http://www.francisxavier.ac.in

3. d[u] ← infinity

4. π[u] ← NIL

5. color[s] ← GRAY ▷ Source vertex discovered

6. d[s] ← 0 ▷ initialize

7. π[s] ← NIL ▷ initialize

8. Q ← {} ▷ Clear queue Q

9. ENQUEUE(Q, s)

10 while Q is non-empty

11. do u ← DEQUEUE(Q) ▷ That is, u = head[Q]

12. for each v adjacent to u ▷ for loop for every node along with edge.

13. do if color[v] ← WHITE ▷ if color is white you've never seen it before

14. then color[v] ← GRAY

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.

Page 175: C++ fundamentals

175

http://www.francisxavier.ac.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.

Page 176: C++ fundamentals

176

http://www.francisxavier.ac.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);

}

.

Page 177: C++ fundamentals

177

http://www.francisxavier.ac.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

incomplete are processed in a LIFO order.

The vertices to be explored are organized as a

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 indegree‟s 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 );

Page 178: C++ fundamentals

178

http://www.francisxavier.ac.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

0 1 1 1 0 0 0

0 0 0 1 1 0 0

0 0 0 0 0 1 0

0 0 1 0 0 1 1

0 0 0 1 0 0 1

0 0 0 0 0 0 0

0 0 0 0 0 1 0

Page 179: C++ fundamentals

179

http://www.francisxavier.ac.in

Solution

1. Number of 1„s 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 1 2 3 4 5 6 7

--------------------------------------------------------------------------------

v1 0 0 0 0 0 0 0

v2 1 0 0 0 0 0 0

v3 2 1 1 1 0 0 0

v4 3 2 1 0 0 0 0

v5 1 1 0 0 0 0 0

v6 3 3 3 3 2 1 0

v7 2 2 2 1 0 0 0

-------------------------------------------------------------------------------

enqueue v1 v2 v5 v4 v3 v7 v6

--------------------------------------------------------------------------------------------------------------------

dequeue v1 v2 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.

Page 180: C++ fundamentals

180

http://www.francisxavier.ac.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 prim’s

algorithm and kruskal’s algorithm.

5.6 KRUSKAL AND PRIM’S ALGORITHM:

5.6.1 KRUSKAL’S 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.

Page 181: C++ fundamentals

181

http://www.francisxavier.ac.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) 1 Accepted

(v6,v7) 1 Accepted

(v1,v2) 2 Accepted

(v3,v4) 2 Accepted

(v2,v4) 3 Rejected

(v1,v3) 4 Rejected

(v4,v7) 4 Accepted

Page 182: C++ fundamentals

182

http://www.francisxavier.ac.in

(v3,v6) 5 Rejected

(v5,v7) 6 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 );

Page 183: C++ fundamentals

183

http://www.francisxavier.ac.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 PRIM’S 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

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 dv.

iv. 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.

Page 184: C++ fundamentals

184

http://www.francisxavier.ac.in

Example:

i. v1 is selected as initial node in the spanning tree and construct initial configuration of the

table.

v Known dv pv

V1 0 0 0

V2 0 ∞ 0

V3 0 ∞ 0

V4 0 ∞ 0

V5 0 ∞ 0

V6 0 ∞ 0

V7 0 ∞ 0

ii. 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

v Known dv pv

V1 1 0 0

V2 0 2 V1

V3 0 4 V1

V4 0 1 V1

V5 0 ∞ 0

V6 0 ∞ 0

V7 0 ∞ 0

Page 185: C++ fundamentals

185

http://www.francisxavier.ac.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

v Known dv pv

V1 1 0 0

V2 0 2 V1

V3 0 2 V4

V4 1 1 V1

V5 0 7 V4

V6 0 8 V4

V7 0 4 V4

V7 0 4 V4

iv. 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

v Known dv pv

V1 1 0 0

V2 1 2 V1

V3 0 2 V4

V4 1 1 V1

V5 0 7 V4

V6 0 8 V4

V7 0 4 V4

Page 186: C++ fundamentals

186

http://www.francisxavier.ac.in

v. Among all vertices v3‟s dv value is lower so v3 is selected. v3‟s 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

v Known dv pv

V1 1 0 0

V2 1 2 V1

V3 1 2 V4

V4 1 1 V1

V5 0 7 V4

V6 0 5 V3

V7 0 4 V4

vi. Among v5, v6, v7, v7‟s 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

v Known dv pv

V1 1 0 0

V2 1 2 V1

V3 1 2 V4

V4 1 1 V1

V5 0 6 V7

V6 0 1 V7

V7 1 4 V4

Page 187: C++ fundamentals

http://www.francisxavier.ac.in Page 187

vii. Among v5 and v6, v6 is declared as known vertex. v6‟s adjacent vertices are v3, v4, and

v7, no change in dv value, all are known vertices.

v Known dv pv

V1 1 0 0

V2 1 2 V1

V3 1 2 V4

V4 1 1 V1

V5 0 6 V7

V6 1 1 V7

V7 1 4 V4

viii. 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 1 0 0

V2 1 2 V1

V3 1 2 V4

V4 1 1 V1

V5 1 6 V7

V6 1 1 V7

V7 1 4 V4

The minimum cost of spanning tree is 16.

Page 188: C++ fundamentals

http://www.francisxavier.ac.in Page 188

Algorithm Analysis

The runnig time is O(|V|2) 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;

}

}

}

Page 189: C++ fundamentals

http://www.francisxavier.ac.in Page 189

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: Dijkstra‟s 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 DIJKSTRA’S 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 );

Page 190: C++ fundamentals

http://www.francisxavier.ac.in Page 190

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.

v Known dv pv

V1 0 ∞ 0

V2 0 ∞ 0

V3 0 0 0

V4 0 ∞ 0

V5 0 ∞ 0

V6 0 ∞ 0

V7 0 ∞ 0

Q V3

Page 191: C++ fundamentals

http://www.francisxavier.ac.in Page 191

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

v Known dv pv

V1 0 1 V3

V2 0 ∞ 0

V3 1 0 0

V4 0 ∞ 0

V5 0 ∞ 0

V6 0 1 V3

V7 0 ∞ 0

Q V1 , V6

iii. Find the adjacent node for v1. v2 and v4 are adjacent node for v1, v2 and v4 inserted

into the queue.

V1 Dequeued

v Known dv pv

V1 1 1 V3

V2 0 2 V1

V3 1 0 0

V4 0 2 V1

V5 0 ∞ 0

V6 0 1 V3

V7 0 ∞ 0

Q V6 , V2 , V4

iv. No adjacent vertices for v6. No change in path value for all vertices.

Page 192: C++ fundamentals

http://www.francisxavier.ac.in Page 192

V6 Dequeued

v Known dv pv

V1 1 1 V3

V2 0 2 V1

V3 1 0 0

V4 0 2 V1

V5 0 ∞ 0

V6 1 1 V3

V7 0 ∞ 0

Q V2 , V4

v. Find the adjacent vertices for v2. v4 and v5 are adjacent nodes to v2 and inserted into

queue.

V2 Dequeued

v Known dv pv

V1 1 1 V3

V2 1 2 V1

V3 1 0 0

V4 0 2 V1

V5 0 3 V2

V6 1 1 V3

V7 0 ∞ 0

Q V4 , V5

vi. 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.

Page 193: C++ fundamentals

http://www.francisxavier.ac.in Page 193

V4 Dequeued

v Known dv pv

V1 1 1 V3

V2 1 2 V1

V3 1 0 0

V4 1 2 V1

V5 0 3 V2

V6 1 1 V3

V7 0 3 V4

Q V5 , V7

vii. 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

v Known dv pv

V1 1 1 V3

V2 1 2 V1

V3 1 0 0

V4 1 2 V1

V5 1 3 V2

V6 1 1 V3

V7 0 3 V4

Q V7

viii. 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.

Page 194: C++ fundamentals

http://www.francisxavier.ac.in Page 194

V7 Dequeued

v Known dv pv

V1 1 1 V3

V2 1 2 V1

V3 1 0 0

V4 1 2 V1

V5 1 3 V2

V6 1 1 V3

V7 1 3 V4

Q Empty

Algorithm Analysis

Running time is O(|E| + |V|)

Weighted Graph

The general method to solve the single source shortest path problem is known as

Dijkstra‟s algorithm. It applied to weighted graph.

Procedure

It uses greedy technique.

It proceeds in stages.

It selects a vertex v, which has the smallest dv among all the unknown vertices and

declares 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.

Page 195: C++ fundamentals

http://www.francisxavier.ac.in Page 195

1. v1 is taken as source.

v Known dv pv

V1 0 0 0

V2 0 ∞ 0

V3 0 ∞ 0

V4 0 ∞ 0

V5 0 ∞ 0

V6 0 ∞ 0

V7 0 ∞ 0

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

v Known dv pv

V1 1 0 0

V2 0 2 V1

V3 0 ∞ 0

V4 0 1 V1

V5 0 ∞ 0

V6 0 ∞ 0

V7 0 ∞ 0

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

Page 196: C++ fundamentals

http://www.francisxavier.ac.in Page 196

v Known dv pv

V1 1 0 0

V2 0 2 V1

V3 0 3 V4

V4 1 1 V1

V5 0 3 V4

V6 0 9 V4

V7 0 5 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.

v Known dv pv

V1 1 0 0

V2 1 2 V1

V3 0 3 V4

V4 1 1 V1

V5 0 3 V4

V6 0 9 V4

V7 0 5 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.

Page 197: C++ fundamentals

http://www.francisxavier.ac.in Page 197

v Known dv pv

V1 1 0 0

V2 1 2 V1

V3 1 3 V4

V4 1 1 V1

V5 1 3 V4

V6 0 8 V3

V7 0 5 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 1 0 0

V2 1 2 V1

V3 1 3 V4

V4 1 1 V1

V5 1 3 V4

V6 0 6 V7

V7 1 5 V4

7. The last vertex v6 is declared as known. No adjacent vertices for v6. No updation in the

table.

v Known dv pv

V1 1 0 0

V2 1 2 V1

V3 1 3 V4

V4 1 1 V1

V5 1 3 V4

V6 1 6 V7

V7 1 5 V4

Page 198: C++ fundamentals

http://www.francisxavier.ac.in Page 198

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

O(|E| + |V|2 ) = O(|V|

2 )

Declarations for Dijkstra’s 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;

}

Page 199: C++ fundamentals

http://www.francisxavier.ac.in Page 199

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 Dijkstra’s 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;

}

}

}

Page 200: C++ fundamentals

http://www.francisxavier.ac.in Page 200

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

Page 201: C++ fundamentals

http://www.francisxavier.ac.in Page 201

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. for each edge (u,v) ∈ G.E

4. RELAX(u,v,w)

5. for each edge (u,v) ∈ G.E

6. if v.d > u.d + w(u,v)

7. 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).

Page 202: C++ fundamentals

http://www.francisxavier.ac.in Page 202

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

Page 203: C++ fundamentals

http://www.francisxavier.ac.in Page 203

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

Page 204: C++ fundamentals

http://www.francisxavier.ac.in Page 204

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}

Page 205: C++ fundamentals

http://www.francisxavier.ac.in Page 205

Thus if we define a quantity d(k)

ij as the minimum weight of the path from vertex i to

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

2. D(0)

= W

3. Π(0)

= π(0)

ij = NIL if i=j or wij = ∞

= i if i≠j and wij < ∞

4. for k = 1 to n

5. let D(k)

= (d(k)

ij) be a new nxn matrix

6. for i = 1 to n

7. for j = 1 to n

8. dk

ij = min(d(k-1)

ij, d(k-1)

ik + d(k-1)

kj)

9. if d(k-1)

ij ≤ d(k-1)

ik + d(k-1)

kj

10. π(k)

ij = π(k-1)

ij

11. else

12. π(k)

ij = π(k-1)

kj

13. return D(n)

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

loops, the run time is clearly O(V3).

Example:

Page 206: C++ fundamentals

http://www.francisxavier.ac.in Page 206

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

Page 207: C++ fundamentals

http://www.francisxavier.ac.in Page 207

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