EC6301 Object Oriented Programming and Data Structure 1
EC6301 Object Oriented Programming and Data Structure 1
net
TEXT BOOKS:
1. Deitel and Deitel, “C++, How To Program”, Fifth Edition, Pearson Education, 2005.
2. Mark Allen Weiss, “Data Structures and Algorithm Analysis in C++”, Third Edition, Addison-
Wesley, 2007.
REFERENCES:
1. Bhushan Trivedi, “Programming with ANSI C++, A Step-By-Step approach”, Oxford University
Press, 2010.
2. Goodrich, Michael T., Roberto Tamassia, David Mount, “Data Structures and Algorithms in
C++”, 7th Edition, Wiley. 2004.
3. Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest and Clifford Stein, "Introduction
to Algorithms", Second Edition, Mc Graw Hill, 2002.
4. Bjarne Stroustrup, “The C++ Programming Language”, 3rd Edition, Pearson Education, 2007.
5. Ellis Horowitz, Sartaj Sahni and Dinesh Mehta, “Fundamentals of Data Structures in C++”,
Galgotia Publications, 2007.
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
CONTENTS
UNIT- I
1 Overview of C++ 1
3 Reference Variables 4
4 Initialization 6
5 Constructors 8
6 Destructors 9
8 Friend Function 15
12 Proxy Classes 27
13 Overloading: 30
13.1 Function overloading and
13.2 Operator Overloading.
UNIT- II
INHERITANCE AND POLYMORPHISM
14 Base Classes and Derived Classes 31
15 Protected Members 33
17 Overriding 36
18 Public 38
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
21 Implicit Derived 41
25 Virtual functions 44
26 This Pointer 45
28 Virtual Destructors 47
UNIT III
LINEAR DATA STRUCTURES
29 3.1 Abstract Data Types (ADTs) 48
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
UNIT- IV
NON-LINEAR DATA STRUCTURES
37 4.1. Trees 66
UNIT- V
SORTING and SEARCHING
44 5.1. Sorting algorithms 84
5.7.1. Characteristics
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
.
UNIT- I
1 Overview of C++
2 Structures Class Scope and Accessing Class Members
3 Reference Variables
4 Initialization
5 Constructors
6 Destructors
7 Member Functions and Classes
8 Friend Function
9 Dynamic Memory Allocation
10 Static Class Members
11 Container Classes and Integrators
12 Proxy Classes
13 Overloading:
13.1 Function overloading and
13.2 Operator Overloading.
1. Overview of C++:
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
result = 1;
This statement is a simple example of an assignment statement, which sets the variable on the
left of the equal sign to the value of the expression on the right.
3 Variables
Data values in a program are usually stored in variables. In C++, if you want to use avariable to
hold some information, you must declare that variable before you use it.
Declaring a variable establishes the following properties:
1.3.1 • Name. Every variable has a name, which is formed according to the rules described in
the section entitled ―Naming conventions‖ later in this chapter. You use the name in the
program to refer to the variable and the value it contains.
Type.Each variable in a C++ program is constrained to hold values of a particular
data type. C++ includes several predefined types and also allows you to define new types of your
own.
1.3.2• Lifetime. Depending on how they are declared, some variables persist throughout the
entire program, while others are created and destroyed dynamically as the program moves
through various levels of function call.
1.3.3• Scope. The declaration of a variable also controls what parts of the program have access to
the variable, which is called its scope.
The standard syntax for declaring a variable is
typenamelist;
int result;
int result;
result = 0;
4. Initializion
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
A data type is defined by two properties: a domain, which is the set of values that belong
to that type, and a set of operations, which defines the behavior of that type. The type int, which
corresponds to the standard representation of an integer on the computer system you are using.
C++ defines three integer types— short, int, and long
The internal size of an integer cannot decrease as you move from short to into long. A compiler
designer for C++ could, for example, decide to make short and int the same size but could not
make intsmaller than short.
• The maximum value of type intmust be at least 32,767 (215–1).
• The maximum value of type long must be at least 2,147,483,647 (231–1).
Numbers that include a decimal fraction are called floating-point numbers, which are
used to approximate real numbers in mathematics. As with integers, C++ defines three different
floating-point types: float, double, and long double.
The most primitive elements of text data are individual characters, which are represented in
C++ using the predefined data type char.
Characters are most useful when they are collected together into sequential units. In
programming, a sequence of characters is called a string.
it is often necessary to test a particular condition that affects the subsequent behavior of your
code. Typically, that condition is specified using an expression whose value is either true or
false. This data type—for which the only legal values are true and false—is called Boolean data,
In C++, the Boolean type is called bool and its domain consists of the values true and
false. all input and output operations—which are often referred to collectively as I/O
operations—are performed by calling functions provided as part of a library.
int main() {
cout<< "This program averages three numbers." <<endl;
cout<< "1st number: ";
double n1 = GetReal();
cout<< "2nd number: ";
double n2 = GetReal();
cout<< "3rd number: ";
double n3 = GetReal();
double average = (n1 + n2 + n3) / 3;
cout<< "The average is " << average <<endl;
return 0;
}
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
is re-written as
The point of listing all the operators in a single table is to establish how they relate to one
another in terms of precedence, which is a measure of how tightly an operator binds to its
operands in the absence of parentheses.
It is, however, important to note that the – operator occurs in two forms. When it is
written between two operands, it is a binary operator representing subtraction. When it is
written in front of a single operand, as in is -b, it is a unary operator representing negation. If
two operators have the same precedence, they are applied in the order specified by Their
associativity, which indicates whether that operator groups to the left or to the right.
Most operators in C++ are left-associative, which means that the leftmost operator is evaluated
first. A few operators—primarily the assignment operator, which is discussed in more detail later
in this chapter—are right-associative, which mean that they are evaluated from right to left.
Type casts
a unary operator that consists of the desired type followed by the value you wish to convert in
parentheses
The assignment operator
In C++, assignment of values to variables is built into the expression structure. The =
operator takes two operands, just like + or *. The left operand must indicate a value that
can change, which is typically a variable name. When the assignment operator is
executed, the expression on the right-hand side is evaluated, and the resulting value is
then stored in the variable that appears on the left-hand side.
Assignments that are written as part of larger expressions are called embedded assignments.
n1 = (n2 = (n3 = 0));
The expression n3 = 0 is evaluated, which sets n3 to 0 and then passes 0 along as the value of the
assignment expression. That value is assigned to n2, and the result is then assigned to n1.
Statements of this sort are called multiple assignments. C++ allows you to combine assignment
with a binary operator to produce a form called a shorthand assignment. For any binary
operator op, the statement
variable op= expression;
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
3 Overloading:
You can have multiple definitions for the same function name in the same scope. The
definition of the function must differ from each other by the types and/or the number of
arguments in the argument list. You can not overload function declarations that differ only by
return type.
Following is the example where same function print() is being used to print different data
types:
#include<iostream>
usingnamespacestd;
classprintData
{
public:
voidprint(inti){
cout<<"Printing int: "<<i<<endl;
}
voidprint(double f){
cout<<"Printing float: "<< f <<endl;
6
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
}
voidprint(char* c){
cout<<"Printing character: "<< c <<endl;
}
};
int main(void)
{
printDatapd;
// Call print to print integer
pd.print(5);
// Call print to print float
pd.print(500.263);
// Call print to print character
pd.print("Hello C++");
return0;
}
When the above code is compiled and executed, it produces the following result:
Printingint:5
Printingfloat:500.263
Printing character:Hello C++
You can redefine or overload most of the built-in operators available in C++. Thus a programmer
can use operators with user-defined types as well.
Overloaded operators are functions with special names the keyword operator followed by the
symbol for the operator being defined. Like any other function, an overloaded operator has a
return type and a parameter list.
Boxoperator+(constBox&);
declares the addition operator that can be used to add two Box objects and returns final Box
object. Most overloaded operators may be defined as ordinary non-member functions or as
class member functions. In case we define above function as non-member function of a class
then we would have to pass two arguments for each operand as follows:
Boxoperator+(constBox&,constBox&);
Following is the example to show the concept of operator over loading using a member function.
Here an object is passed as an argument whose properties will be accessed using this object, the
object which will call this operator can be accessed using this operator as explained below:
#include<iostream>
usingnamespacestd;
classBox
{
7
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
public:
doublegetVolume(void)
{
return length * breadth * height;
}
voidsetLength(doublelen)
{
length=len;
}
voidsetBreadth(doublebre)
{
breadth=bre;
}
voidsetHeight(doublehei)
{
height=hei;
}
// Overload + operator to add two Box objects.
Boxoperator+(constBox& b)
{
Boxbox;
box.length=this->length +b.length;
box.breadth=this->breadth +b.breadth;
box.height=this->height +b.height;
return box;
}
private:
double length;// Length of a box
double breadth;// Breadth of a box
double height;// Height of a box
};
// Main function for the program
int main()
{
BoxBox1;// Declare Box1 of type Box
BoxBox2;// Declare Box2 of type Box
BoxBox3;// Declare Box3 of type Box
double volume =0.0;// Store the volume of a box here
// box 1 specification
Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);
// box 2 specification
Box2.setLength(12.0);
Box2.setBreadth(13.0);
8
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Box2.setHeight(10.0);
// volume of box 1
volume=Box1.getVolume();
cout<<"Volume of Box1 : "<< volume <<endl;
// volume of box 2
volume=Box2.getVolume();
cout<<"Volume of Box2 : "<< volume <<endl;
// Add two object as follows:
Box3=Box1+Box2;
// volume of box 3
volume=Box3.getVolume();
cout<<"Volume of Box3 : "<< volume <<endl;
return0;
}
When the above code is compiled and executed, it produces the following result:
Volume of Box1:210
Volume of Box2:1560
Volume of Box3:5400
A container class is a class designed to hold and organize multiple instances of another class.
There are many different kinds of container classes, each of which has various advantages,
disadvantages, and restrictions in their use. By far the most commonly used container in
programming is the array, which you have already seen many examples of. Although C++
has built-in array functionality, programmers will often use an array container class instead
because of the additional benefits it provides. Unlike built-in arrays, array container classes
generally provide dynamically resizing (when elements are added or removed) and do
bounds-checking. This not only makes array container classes more convenient than normal
arrays, but safer too.
Container classes typically implement a fairly standardized minimal set of functionality. Most
well-defined containers will include functions that:
Create an empty container (via a constructor)
Insert a new object into the container
Remove an object from the container
Report the number of objects currently in the container
Empty the container of all objects
Provide access to the stored objects
Sort the elements (optional)
Sometimes certain container classes will omit some of this functionality. For example,
arrays container classes often omit the insert and delete functions because they are slow and the
class designer does not want to encourage their use.
Container classes generally come in two different varieties.
Value containers are compositions that store copies of the objects that they are holding (and
thus are responsible for creating and destroying those copies).
9
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
6. Reference containers are aggregations that store pointers or references to other objects (and
thus are not responsible for creation or destruction of those objects).
Unlike in real life, where containers can hold whatever you put in them, in C++,
containers typically only hold one type of data. For example, if you have an array of integers, it
will only hold integers. Unlike some other languages, C++ generally does not allow you to mix
types inside a container. If you want one container class that holds integers and another that
holds doubles, you will have to write two separate containers to do this (or use templates, which
is an advanced C++ feature). Despite the restrictions on their use, containers are immensely
useful, and they make programming easier, safer, and faster.
#ifndef INTARRAY_H
#define INTARRAY_H
class IntArray
{
};
#endif
Our IntArray is going to need to keep track of two values: the data itself, and the size of the
array. Because we want our array to be able to change in size, we’ll have to do some dynamic
allocation, which means we’ll have to use a pointer to store the data.
#ifndef INTARRAY_H
#define INTARRAY_H
class IntArray
{
private:
intm_nLength;
int *m_pnData;
};
#endif
Now we need to add some constructors that will allow us to create IntArrays. We are
going to add two constructors: one that constructs an empty array, and one that will allow us to
construct an array of a predetermined size.
10
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
#ifndef INTARRAY_H
#define INTARRAY_H
class IntArray
{
private:
intm_nLength;
int *m_pnData;
public:
IntArray()
{
m_nLength = 0;
m_pnData = 0;
}
IntArray(intnLength)
{
m_pnData = new int[nLength];
m_nLength = nLength;
}
};
#endif
We’ll also need some functions to help us clean up IntArrays. First, we’ll write a
destructor, which simply deallocates any dynamically allocated data. Second, we’ll write a
function called Erase(), which will erase the array and set the length to 0.
~IntArray()
{
delete[] m_pnData;
}
void Erase()
{
delete[] m_pnData;
// We need to make sure we set m_pnData to 0 here, otherwise it will
// be left pointing at deallocated memory!
m_pnData = 0;
m_nLength = 0;
}
Now let’s overload the [] operator so we can access the elements of the array. We should
bounds check the index to make sure it’s valid, which is best done using the assert() function.
We’ll also add an access function to return the length of the array.
#ifndef INTARRAY_H
#define INTARRAY_H
11
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
12
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
~IntArray()
{
#include<iostream>
usingnamespacestd;
classBox
{
public:
staticintobjectCount;
// 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;
// Increase every time object is created
objectCount++;
}
doubleVolume()
{
return length * breadth * height;
}
private:
double length;// Length of a box
double breadth;// Breadth of a box
double height;// Height of a box
};
// Initialize static member of class Box
intBox::objectCount=0;
int main(void)
{
BoxBox1(3.3,1.2,1.5);// Declare box1
BoxBox2(8.5,6.0,2.0);// Declare box2
// Print total number of objects.
cout<<"Total objects: "<<Box::objectCount<<endl;
return0;
}
When the above code is compiled and executed, it produces the following result:
Constructor called.
Constructor called.
Total objects:2
13
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
By declaring a function member as static, you make it independent of any particular object of
the class. A static member function can be called even if no objects of the class exist and the
static functions are accessed using only the class name and the scope resolutionoperator ::.
A static member function can only access static data member, other static member functions
and any other functions from outside the class.
Static member functions have a class scope and they do not have access to the this pointer of
the class. You could use a static member function to determine whether some objects of the
class have been created or not.
Let us try the following example to understand the concept of static function members:
#include<iostream>
usingnamespacestd;
classBox
{
public:
staticintobjectCount;
// 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;
// Increase every time object is created
objectCount++;
}
doubleVolume()
{
return length * breadth * height;
}
staticintgetCount()
{
returnobjectCount;
}
private:
double length;// Length of a box
double breadth;// Breadth of a box
double height;// Height of a box
};
// Initialize static member of class Box
intBox::objectCount=0;
int main(void)
{
// Print total number of objects before creating object.
cout<<"Inital Stage Count: "<<Box::getCount()<<endl;
14
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Here, foo is a pointer, and thus, the first element pointed to by foo can be accessed either with
the expressionfoo[0] or the expression *foo (both are equivalent). The second element can be
accessed either with foo[1] or *(foo+1), and so on...
15
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
There is a substantial difference between declaring a normal array and allocating dynamic
memory for a block of memory using new. The most important difference is that the size of a
regular array needs to be a constant expression, and thus its size has to be determined at the
moment of designing the program, before it is run, whereas the dynamic memory allocation
performed by new allows to assign memory during runtime using any variable value as size.
The dynamic memory requested by our program is allocated by the system from the memory
heap. However, computer memory is a limited resource, and it can be exhausted. Therefore,
there are no guarantees that all requests to allocate memory using operator new are going to
be granted by the system.
C++ provides two standard mechanisms to check if the allocation was successful:
One is by handling exceptions. Using this method, an exception of type bad_alloc is thrown
when the allocation fails. Exceptions are a powerful C++ feature explained later in these
tutorials. But for now, you should know that if this exception is thrown and it is not handled by a
specific handler, the program execution is terminated.
This exception method is the method used by default by new, and is the one used in a
declaration like:
foo = newint [5]; // if allocation fails, an exception is thrown
The other method is known as nothrow, and what happens when it is used is that when a
memory allocation fails, instead of throwing a bad_alloc exception or terminating the program,
the pointer returned by new is a null pointer, and the program continues its execution normally.
This method can be specified by using a special object called nothrow, declared in
header <new>, as argument fornew:
foo = new (nothrow) int [5];
In this case, if the allocation of this block of memory fails, the failure can be detected by
checking if foo is a null pointer:
int * foo;
foo = new (nothrow) int [5];
if (foo == nullptr) {
// error assigning memory. Take measures.
}
This no throw method is likely to produce less efficient code than exceptions, since it implies
explicitly checking the pointer value returned after each and every allocation. Therefore, the
exception mechanism is generally preferred, at least for critical allocations. Still, most of the
coming examples will use the nothrow mechanism due to its simplicity.
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
The first statement releases the memory of a single element allocated using new, and the
second one releases the memory allocated for arrays of elements using new and a size in
brackets ([]).
The value passed as argument to delete shall be either a pointer to a memory block previously
allocated with new, or a null pointer (in the case of a null pointer, delete produces no effect).
// rememb-o-matic
#include <iostream>
#include <new>
usingnamespacestd;
int main ()
{
inti,n;
int * p;
cout<<"How many numbers would you like to type? ";
cin>>i;
p= new (nothrow) int[i];
if (p == nullptr)
cout<<"Error: memory could not be allocated";
else
{
for (n=0; n<i; n++)
{
cout<<"Enter number: ";
cin>> p[n];
}
cout<<"You have entered: ";
for (n=0; n<i; n++)
cout<< p[n] <<", ";
delete[] p;
}
return 0;
}
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
cannot allocate enough memory for it. For example, when I tried to give a value of 1 billion
to the "How many numbers" question, my system could not allocate that much memory for
the program, and I got the text message we prepared for this case (Error: memory could not
be allocated).
It is considered good practice for programs to always be able to handle failures to allocate
memory, either by checking the pointer value (if nothrow) or by catching the proper exception.
To declare all member functions of class ClassTwo as friends of class ClassOne, place a
following declaration in the definition of class ClassOne: friend class ClassTwo;
Consider the following program:
#include <iostream>
using namespace std;
class Box
{
double width;
public:
friend void printWidth( Box box );
voidsetWidth( double wid );
};
// Member function definition
18
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
When the above code is compiled and executed, it produces the following result:
Width of box : 10
A member function of a class is a function that has its definition or its prototype within the
class definition like any other variable. It operates on any object of the class of which it is a
member, and has access to all the members of a class for that object.
Let us take previously defined class to access the members of the class using a member
function instead of directly accessing them:
class Box
{
public:
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
doublegetVolume(void);// Returns box volume
};
Member functions can be defined within the class definition or separately using scope
resolution operator, ::. Defining a member function within the class definition declares the
function inline, even if you do not use the inline specifier. So either you can
define Volume() function as below:
class Box
19
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
{
public:
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
doublegetVolume(void)
{
return length * breadth * height;
}
};
If you like you can define same function outside the class using scope resolution operator,
:: as follows:
double Box::getVolume(void)
{
return length * breadth * height;
}
Here, only important point is that you would have to use class name just before :: operator. A
member function will be called using a dot operator (.) on a object where it will manipulate
data related to that object only as follows:
Box myBox; // Create an object
myBox.getVolume(); // Call member function for the object
Let us put above concepts to set and get the value of different class members in a class:
#include <iostream>
using namespace std;
class Box
{
public:
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
// Member functions declaration
doublegetVolume(void);
voidsetLength( double len );
voidsetBreadth( double bre );
voidsetHeight( double hei );
};
// Member functions definitions
double Box::getVolume(void)
{
return length * breadth * height;
}
void Box::setLength( double len )
{
length = len;
}
20
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
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>
using namespace std;
class Line
{
public:
voidsetLength( double len );
doublegetLength( void );
Line(double len); // This is the constructor
private:
double length;
22
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
};
// Member functions definitions including constructor
Line::Line( double len)
{
cout<< "Object is being created, length = " <<len<<endl;
length = len;
}
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
Using Initialization Lists to Initialize Fields:
In case of parameterized constructor, you can use following syntax to initialize the fields:
Line::Line( double len): length(len)
{
cout<< "Object is being created, length = " <<len<<endl;
}
Above syntax is equal to the following syntax:
Line::Line( double len)
{
cout<< "Object is being created, length = " <<len<<endl;
length = len;
}
If for a class C, you have multiple fields X, Y, Z, etc., to be initialized, then use can use same
syntax and separate the fields by comma as follows:
C::C( double a, double b, double c): X(a), Y(b), Z(c)
{
23
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
....
}
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
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 of line : 6
Object is being deleted
Variables Initialization
A variable can be considered as a box that can hold a single value. However, initially the content
of a variable (or a box) is empty. Therefore, before one can use a variable, it must receive a
value. Do not assume the compiler or computer will put some value, say 0, into a variable.
There are at least three ways to put a value into a variable:
initializing it when the program is run
using an assignment statement
reading a value from keyboard or other device with a READ statement.
The way of initializing a variable is very similar to the use of PARAMETER attribute. More
precisely, do the following to initial a variable with the value of an expression:
add an equal sign (=) to the right of a variable name
to the right of the equal sign, write an expression. It is important to note that all names
in the expression must constants or names of constants.
Initializing a variable is only done exactly once when the computer loads your program into
memory for execution. That is, all initializations are done before the program starts its execution.
The use of un-initialized variables may cause unexpected result.
Examples:
The following example initializes variables Offset to 0.1, Length to 10.0, and tolerance to
1.E-7.
REAL :: Offset = 0.1, Length = 10.0, tolerance = 1.E-7
25
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Basic Syntax
Declaring a variable as a reference rather than a normal variable simply entails appending an
ampersand to the type name, such as this "reference to an int"
int& foo = ....;
Did you notice the "...."? (Probably, right? After all, it's 25% of the example.) When a
reference is created, you must tell it which variable it will become an alias for. After you
create the reference, whenever you use the variable, you can just treat it as though it were a
regular integer variable. But when you create it, you must initialize it with another variable,
whose address it will keep around behind the scenes to allow you to use it to modify that
variable.
In a way, this is similar to having a pointer that always points to the same thing. One key
difference is that references do not require dereferencing in the same way that pointers do;
you just treat them as normal variables. A second difference is that when you create a
reference to a variable, you need not do anything special to get the memory address. The
compiler figures this out for you:
int x;
int& foo = x;
// foo is now a reference to x so this sets x to 56
foo = 56;
std::cout<< x <<std::endl;
After the swap, a will be 3 and b will be 2. The fact that references require no extra work can
lead to confusion at times when variables magically change after being passed into a function.
BjarneStroustrup suggests that for arguments that the function is expected to change, using a
pointer instead of a reference helps make this clear--pointers require that the caller explicitly pass
in the memory address.
Efficiency Gains
26
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
You might wonder why you would ever want to use references other than to change the value--
well, the answer is that passing by reference means that the variable need not be copied, yet it
can still be passed into a function without doing anything special. This gives you the most bang
for your buck when working with classes. If you want to pass a class into a function, it almost
always makes sense for the function to take the class "by reference"—but generally, you want to
use a const reference.
This might look something like this:
intworkWithClass( constMyClass&a_class_object )
{
}
The great thing about using const references is that you can be sure that the variable isn't
modified, so you can immediately change all of your functions that take large objects—no need
to make a copy anymore. And even you were conscientious and used pointers to pass around
large objects, using references in the future can still make your code that much cleaner.
For the sake of full disclosure, it is possible to have an invalid references in one minor and one
major case.
First, if you explicitly assign a reference to a dereferenced NULL pointer, your reference will
be invalid:
int *x = 0;
int& y = *x;
Now when you try to use the reference, you'll get a segmentation fault since you're trying to
access invalid memory (well, on most systems anyhow).
By the way, this actually does work: since you're not actually accessing the value stored in *x
when you make the reference to it, this will compile just fine.
A more pressing issue is that it is possible to "invalidate" a reference in the sense that it is
possible that a reference to a block of memory can live on past the time when the memory is
valid. The most immediate example is that you shouldn't return a reference to local memory:
int&getLocalVariable()
{
int x;
return x;
}
Once the stack frame containing the memory for getLocalVariable is taken off the stack, then
the reference returned by this function will no longer be valid. Oops.
27
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Structures
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
The struct database declares that database has three variables in it, age, id_number, and salary.
You can use database like a variable type like int. You can create an employee with the database
type as I did above. Then, to modify it you call everything with the 'employee.' in front of it. You
can also return structures from functions by defining their return type as a structure type. For
instance: databasefn(); I will talk only a little bit about unions as well. Unions are like structures
except that all the variables share the same memory. When a union is declared the compiler
allocates enough memory for the largest data-type in the union. It's like a giant storage chest
where you can store one large item, or a small item, but never the both at the same time. The '.'
operator is used to access different variables inside a union also. As a final note, if you wish to
have a pointer to a structure, to actually access the information stored inside the structure that is
pointed to, you use the -> operator in place of the . operator. All points about pointers still apply.
A quick example:
#include <iostream>
using namespace std;
structxampl {
int x;
};
int main()
{
xampl structure;
xampl *ptr;
structure.x = 12;
ptr = &structure; // Yes, you need the & when dealing with structures
// and using pointers to them
cout<<ptr->x; // The -> acts somewhat like the * when used with pointers
// It says, get whatever is at that memory address
// Not "get what that memory address is"
cin.get();
}
30
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
UNIT II
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
short level;
...
}
Member functions of derived class cannot directly access private members of base class
• Example:–
Manager member functions in previous example cannot read manager’s own name!
Because data members of a class are by default private
A base class’s protected members can be accessed by
members and friends of the base class, and
members and friends of any class derived from the base class.
Derived-class member functions can refer to public and protected members of the base class.
By simply using their names
is-a relationship:: inheritance
– e.g., derived class object, car, is an object of the base class vehicle
– e.g., derived class object, Manager, is an object of the base class Employee
– has-a relationship:: composition
– e.g., a TreeNode object has (i.e., contains) a member object of type string
Base classes typically represent larger sets of objects than derived classes
Example
– Base class: vehicle
• Includes cars, trucks, boats, bicycles, etc.
– Derived class: car
a smaller, more-specific subset of vehiclesI.e., base classes have more objects
• But fewer data and function members
• Derived classes have only subsets of the objects
• Hence the term subclass
• But a derived class has more data and function members
Dynamic Binding
Explanation
In OOPs Dynamic Binding refers to linking a procedure call to the code that will be executed
only at run time. The code associated with the procedure in not known until the program is
executed, which is also known as late binding.
Example:
#include <iostream.h>
int Square(int x)
{ return x*x; }
int Cube(int x)
{ return x*x*x; }
int main()
{
int x =10;
int choice;
32
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
do
{
cout<< "Enter 0 for square value, 1 for cube value: ";
cin>> choice;
} while (choice < 0 || choice > 1);
int (*ptr) (int);
switch (choice)
{
case 0: ptr = Square; break;
case 1: ptr = Cube; break;
}
cout<< "The result is: " <<ptr(x) <<endl;
return 0;
}
Result:
Enter 0 for square value, 1 for cube value:0
The result is:100
In the above OOPs example the functions "Square" and "Cube" are called only at runtime based
on the value given for "choice". Then a pointer "ptr" is used to call the appropriate function to
get the result.
• protected (C++)
• protected:
• [member-list]
• protected base-class
The protected keyword specifies access to class members in the member-list up to the next
access specifier (public or private) or the end of the class definition. Class members declared as
protected can be used only by the following:
Member functions of the class that originally declared these members.
Friends of the class that originally declared these members.
Classes derived with public or protected access from the class that originally declared these
members.
Direct privately derived classes that also have private access to protected members.
When preceding the name of a base class, the protected keyword specifies that the public and
protected members of the base class are protected members of its derived classes. Protected
members are not as private as private members, which are accessible only to members of the
class in which they are declared, but they are not as public as public members, which are
accessible in any function. Protected members that are also declared as static are accessible to
any friend or member function of a derived class. Protected members that are not declared as
static are accessible to friends and member functions in a derived class only through a pointer to,
reference to, or object of the derived class.
Public inheritance
33
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Public inheritance is by far the most commonly used type of inheritance. In fact, very rarely will
you use the other types of inheritance, so your primary focus should be on understanding this
section. Fortunately, public inheritance is also the easiest to understand. When you inherit a base
class publicly, all members keep their original access specifications. Private members stay
private, protected members stay protected, and public members stay public.
class Base
{
public:
intm_nPublic;
private:
intm_nPrivate;
protected:
intm_nProtected;
};
class Pub: public Base
{
// Public inheritance means:
// m_nPublic stays public
// m_nPrivate stays private
// m_nProtected stays protected
Pub()
{
// The derived class always uses the immediate parent's class access specifications
// Thus, Pub uses Base's access specifiers
m_nPublic = 1; // okay: anybody can access public members
m_nPrivate = 2; // not okay: derived classes can't access private members in the base
class!
m_nProtected = 3; // okay: derived classes can access protected members
}
};
int main()
{
// Outside access uses the access specifiers of the class being accessed.
// In this case, the access specifiers of cPub. Because Pub has inherited publicly from
Base,
// no access specifiers have been changed.
Pub cPub;
cPub.m_nPublic = 1; // okay: anybody can access public members
cPub.m_nPrivate = 2; // not okay: can not access private members from outside class
cPub.m_nProtected = 3; // not okay: can not access protected members from outside
class
}
This is fairly straightforward. The things worth noting are:
1. Derived classes can not directly access private members of the base class.
34
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
2. The protected access specifier allows derived classes to directly access members of the base
class while not exposing those members to the public.
3. The derived class uses access specifiers from the base class.
4. The outside uses access specifiers from the derived class.
To summarize in table form:
Private inheritance
With private inheritance, all members from the base class are inherited as private. This means
private members stay private, and protected and public members become private. Note that this
does not affect that way that the derived class accesses members inherited from its parent! It only
affects the code trying to access those members through the derived class.
class Base
{
public:
intm_nPublic;
private:
intm_nPrivate;
protected:
intm_nProtected;
};
class Pri: private Base
{
// Private inheritance means:
// m_nPublic becomes private
// m_nPrivate stays private
// m_nProtected becomes private
Pri()
{
// The derived class always uses the immediate parent's class access specifications
// Thus, Pub uses Base's access specifiers
35
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Protected inheritance
Protected inheritance is the last method of inheritance. It is almost never used, except in very
particular cases. With protected inheritance, the public and protected members become protected,
and private members stay private.
36
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Protected inheritance is similar to private inheritance. However, classes derived from the derived
class still have access to the public and protected members directly. The public (stuff outside the
class) does not.
THIS POINTER
Every object in C++ has access to its own address through an important pointer called this
pointer. The thispointer is an implicit parameter to all member functions. Therefore, inside a
member function, this may be used torefer to the invoking object. Friend functions do not have a
thispointer, because friends are not members of a class. Only member functionshave a this
pointer.
Let us try the following example to understand the concept of this pointer:
#include <iostream>
using namespace std;
classBox
{
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;
}
doubleVolume()
{
returnlength * breadth * height;
}
intcompare(Box box)
{
return this->Volume() >box.Volume();
}
private:
doublelength; // Length of a box
37
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
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
An interface describes the behavior or capabilities of a C++ class without committing to a
particularimplementation of that class.
The C++ interfaces are implemented using abstract classes and these abstract classes should
not beconfused with data abstraction which is a concept of keeping implementation details
separate from associateddata.
A class is made abstract by declaring at least one of its functions as pure virtual function. A
pure virtual functionis specified by placing "= 0" in its declaration as follows:
classBox
{
public:
// pure virtaul function
virtual double getVolume() = 0;
private:
doublelength; // Length of a box
doublebreadth; // Breadth of a box
doubleheight; // Height of a box
};
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
override a pure virtual function in a derivedclass, then attempting to instantiate objects of that
class, is a compilation error.
Classes that can be used to instantiate objects are called concrete c lasses.
Consider the following example where parent class provides an interface to the base class to
implement a function called g etArea():
#include <iostream>
using namespace std;
// Base class
classShape
{ public:
// pure virtual function providing interface framework.
virtualintgetArea() = 0;
voidsetWidth(intw)
{
width= w;
}
voidsetHeight(inth)
{
height= h;
}
protected:
intwidth;
intheight;
};
// Derived classes
classRectangle: public Shape
{ public:
intgetArea()
{
return(width * height);
}
};
classTriangle: public Shape
{ public:
intgetArea()
{
return(width * height)/2;
}
};
intmain(void)
{
Rectangle Rect;
39
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Triangle Tri;
Rect.setWidth(5);
Rect.setHeight(7);
// Print the area of the object.
cout<<"Total Rectangle area: " <<Rect.getArea() <<endl;
Tri.setWidth(5);
Tri.setHeight(7);
// Print the area of the object.
cout<<"Total Triangle area: " <<Tri.getArea() <<endl;
return0;
}
When the above code is compiled and executed, it produces the following result:
Total Rectangle area: 35
derivedClassObject = baseClassObject;
May not work properly
– Unless an assignment operator is overloaded in the derived class, data members exclusive to
the derived class will be unassigned Base class has less data members than the derived class
– Some data members missing in the derived class object
Four ways to mix base and derived class pointers andobjects
Referring to a base-class object with a base-class pointer
– Allowed
40
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
int * pi;
you define a pointer to an int member of class A like this:
class A{/**/};
int A::*pmi; // pmi is a pointer to an int member of A
You can initialize pmi like this:
class A
{
public:
41
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
intnum;
int x;
};
int A::*pmi = &A::num; // 1
The statement numbered 1 defines a pointer to an int member of class A and initializes it with
the address of num. Now you can use the pointer pmi to examine and modify num's value in
any object of class A:
A a1;
A a2;
In fact, a pointer to a member function looks just like an ordinary pointer to function, except that
it also contains the class's name immediately followed by the :: operator. You can invoke the
member function to which pmf points like this:
42
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Pointers to member functions respect polymorphism; if you call a virtual member function
through a pointer to member, the call will be resolved dynamically as the following code
shows:
class Base
{
public:
virtualint f (int n);
};
class Derived : public Base {
public:
int f (int h); //override
};
Base *pb = new Derived;
int (Base::*pmf)(int) = &Base::f;
(pb->*pmf)(5); // call resolved as D::f(5);
Note that you cannot take the address of constructors and destructors.
struct A
{
int x;
void f();
43
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
};
int A::*pmi = &A::x;
void (A::*pmf)() = &A::f;
int n = sizeof (pmi); // 8 byte with my compiler
int m = sizeof (pmf); // 12 bytes with my compiler
Note that each of these pointers may have a different representation, depending on the class
in question and whether the member function is virtual.
Function Overriding
If base class and derived class have member functions with same name and
arguments. If you create an object of derived class and write code to access that member function
then, the member function in derived class is only invoked, i.e., the member function of derived
class overrides the member function of base class. This feature in C++ programming is known as
function overriding.
Accessing
44
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
45
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Class A
{
int a;
public:
A()
{
a = 1;
}
virtual void show()
46
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
{
cout<<a;
}
};
Class B: public A
{
int b;
public:
B()
{
b = 2;
}
virtual void show()
{
cout<<b;
}
};
int main()
{
A *pA;
B oB;
pA = &oB;
pA->show();
return 0;
}
class a
{
public:
a(){printf("\nBase Constructor\n");}
~a(){printf("\nBase Destructor\n");}
};
class b : public a
{
public:
b(){printf("\nDerived Constructor\n");}
~b(){printf("\nDerived Destructor\n");}
47
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
};
int main()
{
a* obj=new b;
delete obj;
return 0;
}
Output:
Base Constructor
Derived Constructor
Base Destructor
By Changing
~a(){printf("\nBase Destructor\n");}
to
virtual ~a(){printf("\nBase Destructor\n");}
Output:
Base Constructor
Derived Constructor
Derived Destructor
Base Destructor
UNIT III
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
List ADT
• Often, we could just use an array
• May wish to separate what a list does from its implementation (abstraction)
• Allows for a variety of implementations:
• Fixed versus arbitrary capacity
• Array-based versus linked lists (later in course)
• More natural to work with than an array: first position is location 1 in a list, but at index 0 in
an array
3.2.2. List ADT Implementation 1
• We’ll store either simple types (int, char, etc) or pointers to simple types or to more complex
objects - to avoid copying complex objects
• Underlying structure is an array with a fixed maximum size remove and retrieve will return the
item at a specified position; precondition: the position must be one that currently exists in the list
• replace will change the item stored at a specified position, and return the displaced item;
precondition: the position must be one that currently exists in the list
• swap will change positions of 2 items stored at 2 specified positions, precondition: the positions
must currently exist in the list Adding an item to a list will change, at most, the predecessor of
one item and the successor of one item
49
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
• Removing an item will change, at most, the predecessor of one item and the successor of one
item
Add value 5 at loc 3 of the list 7,0,23,16,8,4 to get 7,0,5,23,16,8,4
Delete 1st item from 9,3,6,0,7 to get 3,6,0,7;
delete 3rd item from this list to get 3,6,7
code:
constint DEFAULT_LIST = 200;
template<class Item>
class List {
public:
List(unsigned capacity = DEFAULT_LIST);
~List( ); // destructor
boolisEmpty( ) const;
boolisFull( ) const;
unsignedgetLength( ) const;
void insert (unsigned pos, Item item);
Item remove (unsigned pos);
Item replace(unsigned pos, Item item );
Item retrieve (unsigned pos) const;
void swap (unsigned i, unsigned j);
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
-----------------
|A|B|||
-----------------
0123
contents
So, a sequence of pops produce the following effects:
1. letter = Pop(stack)
2. stack (made up of 'contents' and 'top')
3. ----------------- ----- -----
4. | A | B | | | | 1 | | C |
5. ----------------- ----- -----
6. 0 1 2 3 top letter
7. contents
8. letter = Pop(stack)
9. stack (made up of 'contents' and 'top')
10. ----------------- ----- -----
11. | A | | | | | 0 | | B |
12. ----------------- ----- -----
13. 0 1 2 3 top letter
14. contents
15. letter = Pop(stack)
16. stack (made up of 'contents' and 'top')
17. ----------------- ----- -----
18. | | | | | | -1| | A |
19. ----------------- ----- -----
20. 0 1 2 3 top letter
What happens if we apply the following set of operations?
1. Push(stack, 'D')
2. Push(stack, 'E')
3. Push(stack, 'F')
4. Push(stack, 'G')
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
53
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
{
return data;
}
node* node::getNext () const
{
return next;
}
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
node* tail;
int size;
voiddeleteAll ();
node* getNthAddress (int);
voiddeleteWithOneNode ();
voiddeleteAtBeginning ();
voiddeleteLast ();
voiddeleteInMiddle (int);
};
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
isFull(S);
//Returns "true" if and only if the stack S has a bounded size and holds the maximum
number
of elements it can.
top(S);
Return the element at the top of the stack S, or error if the stack is empty.
S = push(S,ch);
Push the character ch at the top of the stack S.
S = pop(S);
Pop an element from the top of the stack S.
print(S);
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
57
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Continuing with our standard practice followed so far, we are going to provide two
implementations of the queue ADT, the first using static memory, the second using dynamic
memory. The implementations aim at optimizing both the insertion and deletion operations.
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
}
intisFull ( queue Q )
{
return (Q.front == (Q.back + 2) % MAXLEN);
}
char front ( queue Q )
{
if (isEmpty(Q)) {
fprintf(stderr,"front: Queue is empty\n");
return '\0';
}
returnQ.element[Q.front];
}
queueenqueue ( queue Q , char ch )
{
if (isFull(Q)) {
fprintf(stderr,"enqueue: Queue is full\n");
return Q;
}
++Q.back;
if (Q.back == MAXLEN) Q.back = 0;
Q.element[Q.back] = ch;
return Q;
}
queuedequeue ( queue Q )
{
if (isEmpty(Q)) {
fprintf(stderr,"dequeue: Queue is empty\n");
return Q;
}
++Q.front;
if (Q.front == MAXLEN) Q.front = 0;
return Q;
}
void print ( queue Q )
{
inti;
if (isEmpty(Q)) return;
i = Q.front;
while (1) {
printf("%c", Q.element[i]);
if (i == Q.back) break;
if (++i == MAXLEN) i = 0;
}
}
Here is a sample main() for these functions.
59
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
int main ()
{
queue Q;
Q = init(); printf("Current queue : "); print(Q); printf("\n");
Q = enqueue(Q,'h'); printf("Current queue : "); print(Q); printf("\n");
Q = enqueue(Q,'w'); printf("Current queue : "); print(Q); printf("\n");
Q = enqueue(Q,'r'); printf("Current queue : "); print(Q); printf("\n");
Q = dequeue(Q); printf("Current queue : "); print(Q); printf("\n");
Q = dequeue(Q); printf("Current queue : "); print(Q); printf("\n");
Q = enqueue(Q,'c'); printf("Current queue : "); print(Q); printf("\n");
Q = dequeue(Q); printf("Current queue : "); print(Q); printf("\n");
Q = dequeue(Q); printf("Current queue : "); print(Q); printf("\n");
Q = dequeue(Q); printf("Current queue : "); print(Q); printf("\n");
}
Finally, this is the output of the complete program.
Current queue :
Current queue : h
Current queue :hw
Current queue :hwr
Current queue :wr
Current queue : r
Current queue :rc
Current queue : c
Current queue :
dequeue: Queue is empty
Current queue :
Tokens
Because we are going to have to deal with inputs made up of many parts that have to be
processed in an algorithm, the first step is to transform our input into a collection of objects that
we can manipulate. If our input comes to us in the form of a String and the elements of the input
are properly separated by spaces, we can start by using the String class's split() method to split
the input String into an array of Strings.
This solves the problem of separating the input into individual elements we can
manipulate. We are also going to go one step further, turning each of these elements into an
object called a Token.
60
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Tokens come in three basic types: numbers, operators, and parentheses. Tokens of type
number have an associated numeric value, while operators will have an associated precedence
value.
An example
Here is an illustration of this algorithm in action. The expression we want to compute is
2+3*4-6
At the start of the algorithm both stacks are empty and the tokens are lined up in the input.
61
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
The next operator in the input has a higher precedence than the operator at the top of the
operator stack, so we push the next operator. The next number token also gets pushed on the
value stack.
62
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
The next operator in the input sequence has a precedence lower than that of the operator at
the top of the operator stack. This causes us to process and remove the operator at the top of
the operator stack.
Once
Once again, the operator in the input has a precendence equal to that of the operator at the top
of the operator stack, so we process and remove the operator from the operator stack.
63
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
At this point the operator stack is empty, so the operator token at the front of the input gets
pushed on the operator stack. The number token at the end of the input gets pushed on the
value stack.
Once the input has emptied out, we process any operators that remain on the operator stack.
Once all of those operators have been processed, the sole remaining number on the value
stack is the result of the computation.
64
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Handling parentheses
The algorithm outlined above can easily be extended to also handle parentheses correctly. All
that is required is a couple of additional rules.
• When we encounter a left parentheses token in the input, we push that token on the
operator stack.
• When we encounter a right parenthesis token in the input, we process operator s and
remove them from the top of the operator stack until a left parenthesis appears at the
top of the operator stack. We then pop off the left parenthesis token and discard both
of the parenthesis tokens.
65
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
UNIT IV
4.1. TREE
a tree is a widely used abstract data type (ADT) or data structure implementing this ADT
that simulates a hierarchical tree structure, with a root value and subtrees of children, represented
as a set of linked nodes. A tree data structure can be defined recursively (locally) as a collection
of nodes (starting at a root node), where each node is a data structure consisting of a value,
together with a list of references to nodes (the "children"), with the constraints that no reference
is duplicated, and none points to the root. Alternatively, a tree can be defined abstractly as a
whole (globally) as an ordered tree, with a value assigned to each node. Both these perspectives
are useful: while a tree can be analyzed mathematically as a whole, when actually represented as
a data structure it is usually represented and worked with separately by node (rather than as a list
of nodes and an adjacency list of edges between nodes, as one may represent a digraph, for
instance). For example, looking at a tree as a whole, one can talk about "the parent node" of a
given node, but in general as a data structure a given node only contains the list of its children,
but does not contain a reference to its parent (if any). A simple unordered tree; in this diagram,
the node labeled 7 has two children, labeled 2 and 6, and one parent, labeled 2. The root node, at
the top, has no parent.
Definition
A tree is a non-linear data structure that consists of a root node and potentially many
levels of additional nodes that form a hierarchy. A tree can be empty with no nodes called the
null or empty tree or a tree is a structure consisting of one node called the root and one or more
subtrees.
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Binary tree
A simple binary tree of size 9 and height 3, with a root node whose value is 2. The above tree
is unbalanced and not sorted. In computer science, a binary tree is a treedata structure in which
each node has at most two children (referred to as the left child and the right child). In a binary
tree, the degree of each node can be at most two. Binary trees are used to implement binary
search trees and binary heaps, and are used for efficient searching and sorting. A binary tree is a
special case of a Kary tree, where k is 2.
67
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Tree rotations are very common internal operations on self-balancing binary trees.
A rooted binary tree is a tree with a root node in which every node has at most two children.
• A full binary tree (sometimes 2-tree or strictly binary tree) is a tree in which every node
other than the leaves has two children. A full tree is sometimes ambiguously defined as a perfect
tree. Physicists define a binary tree to mean a full binary tree.[1]
• A proper binary tree is an ordered tree in which each internal node has exactly two children.
• A perfect binary tree is a full binary tree in which all leaves have the same depth or same
level, and in which every parent has two children.[2] (This is ambiguously also called a complete
binary tree (see next).) An example of a perfect binary tree is the ancestry chart of a person to a
given depth, as each person has exactly two biological parents (one mother and one father); note
that this reverses the usual parent/child tree convention, and these trees go in the opposite
direction from usual (root at bottom).
• A complete binary tree is a binary tree in which every level, except possibly the last, is
completely filled, and all nodes are as far left as possible.[3] A tree is called an almost complete
binary tree or nearly complete binary tree if the exception holds, i.e. the last level is not
completely filled. This type of tree is used as a specialized data structure called a heap.
• An infinite complete binary tree is a tree with a countably infinite number of levels, in which
every node has two children, so that there are 2d nodes at level d. The set of all nodes is
countably infinite, but the set of all infinite paths from the root is uncountable, having the
cardinality of the continuum. These paths correspond by an order-preserving bijection to the
points of the Cantor set, or (using the example of a Stern–Brocot tree) to the set of positive
irrational numbers.
• A balanced binary tree is commonly defined as a binary tree in which the depth of the left
and right subtrees of every node differ by 1 or less,[4] although in general it is a binary tree
where no leaf is much farther away from the root than any other leaf. (Different balancing
schemes allow different definitions of "much farther".[5]) Binary trees that are balanced
according to this definition have a predictable depth (how many nodes are traversed from the
root to a leaf, counting the root as node 0 and subsequent nodes as 1, 2, ...,n). This depth (also
called the height) is equal to the integer part of log2(n), where n is the number of nodes on the
balanced tree. For example, for a balanced tree with only 1 node, log2(1) = 0, so the depth of the
tree is 0. For a balanced tree with 100 nodes, log2(100) = 6.64, so it has a depth of 6.
• A degenerate (or pathological) tree is a tree where each parent node has only one associated
child node. This means that performance-wise, the tree will behave like a linked list data
structure.
Note that this terminology often varies in the literature, especially with respect to the meaning of
"complete" and "full".
68
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
• The number of nodes n in a perfect binary tree can also be found using this formula: n = 2l-1
where l is the number of leaf nodes in the tree.
• The number of null links (i.e., absent children of nodes) in a complete binary tree of n nodes
is (n+1).
• The number of internal nodes (i.e., non -leaf nodes or n-l) in a complete binary tree of n
nodes is n/2 .
• For any non -empty binary tree with n0 leaf nodes and n2 nodes of degree 2, n0 = n2 + 1.[6]
Common operations
There are a variety of different operations that can be performed on binary trees. Some
are mutator operations, while others simply return useful information about the tree.
Insertion
Nodes can be inserted into binary trees in between two other nodes or added after a leaf node. In
binary trees, a node that is inserted is specified as to which child it is.
External nodes
Say that the external node being added onto is node A. To add a new node after node A, A
assigns the new node as one of its children and the new node assigns node A as its parent.
Internal nodes
The process of inserting a node into a binary tree Insertion on internal nodes is slightly more
complex than on external nodes. Say that the internal node is node A and that node B is the child
of A. (If the insertion is to insert a right child, then B is the right child of A, and similarly with a
left child insertion.) A assigns its child to the new node and the new node assigns its parent to A.
Then the new node assigns its child to B and B assigns its parent as the new node.
Deletion
Deletion is the process whereby a node is removed from the tree. Only certain nodes in a binary
tree can be removed unambiguously.[7]
69
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
The process of deleting an internal node in a binary tree Say that the node to delete is node A. If
a node has no children (external node), deletion is accomplished by setting the child of A's parent
to null. If it has one child, set the parent of A's child to A's parent and set the child of A's parent
to A's child.
Node with two children
In a binary tree, a node with two children cannot be deleted unambiguously.[7] However, in
certain binary trees (including binary search trees) these nodes can be deleted, though with a
rearrangement of the tree structure.
Traversal
Pre-order, in-order, and post-order traversal visit each node in a tree by recursively visiting each
node in the left and right subtrees of the root.
Depth-first order
In depth-first order, we always attempt to visit the node farthest from the root node that we can,
but with the caveat that it must be a child of a node we have already visited. Unlike a depth-first
search on graphs, there is no need to remember all the nodes we have visited, because a tree
cannot contain cycles. Pre-order is a special case of this. See depth-first search for more
information.
Breadth-first order
Contrasting with depth-first order is breadth-first order, which always attempts to visit the node
closest to the root that it has not already visited. See breadth-first search for more information.
Also called a level-order traversal. In a complete binary tree, a node's breadth-index (i - (2d - 1))
can be used as traversal instructions from the root. Reading bitwise from left to right, starting at
bit d - 1, where d is the node's distance from the root (d = floor(log2(i+1))) and the node in
question is not the root itself (d > 0). When the breadth-index is masked at bit d - 1, the bit values
0 and 1 mean to step either left or right, respectively. The process continues by successively
checking the next bit to the right until there are no more. The rightmost bit indicates the final
traversal from the desired node's parent to the node itself. There is a time-space trade-off
between iterating a complete binary tree this way versus each node having pointer/s to its
sibling/s.
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
The binary tree can be thought of as the original tree tilted sideways, with the black left edges
representing first child and the blue right edges representing next sibling. The leaves of the tree
on the left would be written in Lisp as:
(((N O) I J) C D ((P) (Q)) F (M))
which would be implemented in memory as the binary tree on the right, without any letters on
those nodes that have a left child.
Binary Trees
A binary tree is composed of zero or more nodes
unique path
ain a value
71
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
tree:
root, left, right
Preorder traversal
first
‟s a preorder traversal to print out all the elements in the binary tree:
public void preorderPrint(BinaryTreebt) {
if (bt == null) return;
System.out.println(bt.value);
preorderPrint(bt.leftChild);
preorderPrint(bt.rightChild);
72
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
}
Inorder traversal
in the middle
‟s an inorder traversal to print out all the elements in the binary tree:
public void inorderPrint(BinaryTreebt) {
if (bt == null) return;
inorderPrint(bt.leftChild);
System.out.println(bt.value);
inorderPrint(bt.rightChild);
}
Postorder traversal
ted last
‟s a postorder traversal to print out all the elements in the binary tree:
public void postorderPrint(BinaryTreebt) {
if (bt == null) return;
postorderPrint(bt.leftChild);
postorderPrint(bt.rightChild);
System.out.println(bt.value);
}
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
There are other representations also like, Incidence Matrix and Incidence List. The choice of the
graph representation is situation specific. It totally depends on the type of operations to be
performed and ease of use.
Adjacency Matrix:
Adjacency Matrix is a 2D array of size V x V where V is the number of vertices in a graph. Let
the 2D array be adj[][], a slot adj[i][j] = 1 indicates that there is an edge from vertex i to vertex j.
Adjacency matrix for undirected graph is always symmetric. Adjacency Matrix is also used to
represent weighted graphs. If adj[i][j] = w, then there is an edge from vertex i to vertex j with
weight w. The adjacency matrix for the above example graph is:
Adjacency List:
An array of linked lists is used. Size of the array is equal to number of vertices. Let the array
be array[]. An entry array[i] represents the linked list of vertices adjacent to the ith vertex.
This representation can also be used to represent a weighted graph. The weights of edges can
be stored in nodes of linked lists. Following is adjacency list representation of the above
graph.
74
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
#include <stdlib.h>
// A structure to represent an adjacency list node
structAdjListNode
{
intdest;
structAdjListNode* next;
};
// A structure to represent an adjacency liat
structAdjList
{
structAdjListNode *head; // pointer to head node of list
};
// A structure to represent a graph. A graph is an array of adjacency lists.
// Size of array will be V (number of vertices in graph)
structGraph
{
intV;
structAdjList* array;
};
// A utility function to create a new adjacency list node
structAdjListNode* newAdjListNode(intdest)
{
structAdjListNode* newNode =
(structAdjListNode*) malloc(sizeof(structAdjListNode));
newNode->dest = dest;
newNode->next = NULL;
returnnewNode;
}
// A utility function that creates a graph of V vertices
structGraph* createGraph(intV)
{
structGraph* graph = (structGraph*) malloc(sizeof(structGraph));
graph->V = V;
// Create an array of adjacency lists. Size of array will be V
graph->array = (structAdjList*) malloc(V * sizeof(structAdjList));
// Initialize each adjacency list as empty by making head as NULL
inti;
for(i = 0; i< V; ++i)
graph->array[i].head = NULL;
returngraph;
}
// Adds an edge to an undirected graph
voidaddEdge(structGraph* graph, intsrc, intdest)
{
75
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
// Add an edge from src to dest. A new node is added to the adjacency
// list of src. The node is added at the begining
structAdjListNode* newNode = newAdjListNode(dest);
newNode->next = graph->array[src].head;
graph->array[src].head = newNode;
// Since graph is undirected, add an edge from dest to src also
newNode = newAdjListNode(src);
newNode->next = graph->array[dest].head;
graph->array[dest].head = newNode;
}
// A utility function to print the adjacenncy list representation of graph
voidprintGraph(structGraph* graph)
{
intv;
for(v = 0; v < graph->V; ++v)
{
structAdjListNode* pCrawl = graph->array[v].head;
printf("\n Adjacency list of vertex %d\n head ", v);
while(pCrawl)
{
printf("-> %d", pCrawl->dest);
pCrawl = pCrawl->next;
}
printf("\n");
}
}
// Driver program to test above functions
intmain()
{
// create the graph given in above fugure
intV = 5;
structGraph* graph = createGraph(V);
addEdge(graph, 0, 1);
addEdge(graph, 0, 4);
addEdge(graph, 1, 2);
addEdge(graph, 1, 3);
addEdge(graph, 1, 4);
addEdge(graph, 2, 3);
addEdge(graph, 3, 4);
// print the adjacency list representation of the above graph
printGraph(graph);
return0;
}
Output:
Adjacency list of vertex 0
76
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Pros: Saves space O(|V|+|E|) . In the worst case, there can be C(V, 2) number of edges in
a graph thus consuming O(V^2) space. Adding a vertex is easier.
Cons: Queries like whether there is an edge from vertex u to vertex v are not efficient and
can be done O(V).
Here is a simple directed graph with four vertices V = {1, 2, 3, 4} and four edges E = {(1, 2), (2,
3), (3, 1), (3, 4)}. Consider the following abstract data type for a directed graph with weighted
edges. Note that while this specification does not explicitly require any particular
implementation, the required running times of some of these functions constrain the
implementation in various ways. For instance, a naive adjacency matrix implementation would
take Θ(n2) time to consider every array entry in producing a list of all the edges. However the
edges function is required to do this in O(n + m) time.
77
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Graph Traversals
One of the most basic graph operations is to traverse a graph, finding the nodes accessible
by following edges from some starting node. You have already seen this operation in CS2110.
79
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
We mark the vertices as visited when we have visited them to keep track of the parts of the graph
that we have already explored. We start with a single vertex and mark it as visited. We then
consider each outgoing edge. If an edge connects to an unvisited node, we put that node in a set
of nodes to explore. Then we repeatedly remove a node from the set, mark it as visited, and
repeat the process with that node. If we ever take a node out of the set and it is already marked as
visited, then we ignore it. The order in which we explore the vertices depends on how we
maintain the set of vertices to explore. If we use a queue, so the unvisited vertices are explored in
a first-infirst- out (FIFO) fashion, then the above traversal process it is known as breadth-first
search (BFS). If we use a stack, so the unvisited vertices are explored in a last-in-first-out (LIFO)
fashion, this is known asdepth-first search (DFS). Of course, such a traversal will only visit
nodes reachable from the start node by a directed path. Here is an implementation of traversal in
a directed graph using the above abstraction. This implementation makes use of a set of vertices
of type VSet to keep track of the visited vertices. It performs a BFS or DFS depending on
whether the Queue or Stack package is opened. It also can traverse either the edges of the graph
or of the ''reverse'' graph (in which all the edges have been reversed), based on the parameter
Connected Components
In an undirected graph, a connected component is the set of nodes that are reachable by
traversal from some node. The connected components of an undirected graph have the property
that all nodes in the component are reachable from all other nodes in the component. In a
directed graph, however, reachable usually means by a path in which all edges go in the positive
80
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
direction, i.e. from source to destination. In directed graphs, a vertex v may be reachable from u
but not vice-versa. For instance, for the graph above, the set of nodes reachable from any of the
nodes 1, 2, or 3 is the set {1, 2, 3, 4}, whereas the set of nodes reachable from node 4 is just the
singleton {4}. The strongly connected components in a directed graph are defined in terms of the
set of nodes that are mutually accessible from one another. In other words, the strongly
connected component of a node u is the set of all nodes v such that v is reachable from u by a
directed path and u is reachable from v by a directed path. Equivalently, u and v lie on a directed
cycle. One can show that this is an equivalence relation on nodes, and the strongly connected
components are the equivalence classes. For instance, the graph above has two strongly
connected components, namely {1, 2, 3} and {4}. It is possible to show that the strongly
connected component from a node vi can be found by searching for nodes that are accessible
from vi both in G and in Grev, where Grev has the same set of vertices as G, and has the reverse
of each edge in G. Thus the following simple algorithm finds the strongly connected
components.
letstrong_component v0 =
VSet.inter (traverse v0 1) (traverse v0 (-1))
letstrong_components g =
letvs = ref VSet.empty
andcs = ref [] in
(List.iter (function (v) ->vs :=VSet.add v !vs) (Graph.vertices g);
while (not (VSet.is_empty !vs)) do
let c = strong_component (VSet.choose !vs) in
(vs := VSet.diff !vs c;
cs := c::!cs)
done;
!cs)
Topological Ordering
In a directed acyclic graph (DAG), the nodes can be ordered such that each node in the
ordering comes before all the other nodes to which it has outbound edges. This is called a
topological sort of the graph. In general, there is not a unique topological order for a given DAG.
If there are cycles in the graph, there is no topological ordering. Topological orderings have
many uses for problems ranging from job scheduling to determining the order in which to
compute quantities that depend on one another (e.g., spreadsheets, order of compilation of
modules in OCaml). The following figure shows a DAG and a topological ordering for the
81
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
graph.
Here is a simple recursive function for computing a topological ordering, which operates by
choosing a vertex with no incoming edges as the first node in the ordering, and then appending
that to the result of recursively computing the ordering of the graph with that node removed. If in
this process there ever is a graph where all the nodes have incoming edges, then the graph is
cyclic and an error is raised. The running time of this method is O(n2), whereas the
asymptotically fastest methods are O(n + m).
lettopological_rec g =
letrectopological_destr gr =
letvl = Graph.vertices gr in
ifvl = [] then []
else
letsl = List.filter (function v ->Graph.in_degree v = 0) vlin
ifsl = [] (* No vertices without incoming edges *)
thenfailwith "Graph is cyclic"
else
let v = List.hdslin
(Graph.remove_vertex gr v;
v :: topological_destr gr) in
topological_destr (Graph.copy g)
Here is an iterative version of topological sort which has O(n + m) running time. Note that while
remove_vertex is O(m) time for a single vertex, it is also O(m) time when all n vertices of the
graph are removed, because each edge is considered a constant number of times overall in the
process of removing all the vertices.
lettopological_iter g =
let gr = Graph.copy g in
letsl = ref (List.filter
(function v ->Graph.in_degree v = 0)
(Graph.vertices gr))
andrevorder = ref [] in
82
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
while !sl<> [] do
let v = List.hd !slin
(sl := List.tl !sl;
List.iter
(function e ->
matchGraph.edge_info e with (_, dst, _) ->
ifGraph.in_degreedst = 1
thensl := dst :: !slelse ())
(Graph.outgoing v);
Graph.remove_vertex gr v;
revorder := v :: !revorder)
done;
ifGraph.num_vertices gr = 0
thenList.rev !revorder
(* Remaining vertices all with incoming edges *)
elsefailwith "Graph is cyclic"
83
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
UNIT V
SORTING and SEARCHING
5.1. Sorting algorithms
5.2. Insertion sort
5.2.1. Pseudo code for Insertion Sort
5.3. Quick sort
5.3.1. Pseudo code for Quick Sort
5.4. Merge sort
5.4.1. Pseudo code for Merge Sort
5.5. Searching
5.6. Linear search
5.6.1. Implementation
5.7. Binary Search
5.7.1. Characteristics
5.1. SORTING
Sorting is the process of placing elements from a collection in some kind of order. For
example, a list of words could be sorted alphabetically or by length. A list of cities could be
sorted by population, by area, or by zip code. We have already seen a number of algorithms that
were able to benefit from having a sorted list (recall the final anagram example and the binary
search). Sorting a large number of items can take a substantial amount of computing resources.
Like searching, the efficiency of a sorting algorithm is related to the number of items being
processed. For small collections, a complex sorting method may be more trouble than it is worth.
The overhead may be too high. On the other hand, for larger collections, we want to take
advantage of as many improvements as possible. In this section we will discuss several sorting
techniques and compare them with respect to their running time. Before getting into specific
algorithms, we should think about the operations that can be used to analyze a sorting process.
First, it will be necessary to compare two values to see which is smaller (or larger). In order to
sort a collection, it will be necessary to have some systematic way to compare values to see if
they are out of order. The total number of comparisons will be the most common way to measure
a sort procedure. Second, when values are not in the correct position with respect to one another,
it may be necessary to exchange them. This exchange is a costly operation and the total number
of exchanges will also be important for evaluating the overall efficiency of the algorithm.
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
sorted. On each pass, one for each item 1 through \(n-1\), the current item is checked against
those in the already sorted sublist. As we look back into the already sorted sublist, we shift those
items that are greater to the right. When we reach a smaller item or the end of the sublist, the
current item can be inserted. The figure below shows the fifth pass in detail. At this point in the
algorithm, a sorted sublist of five items consisting of 17, 26, 54, 77, and 93 exists. We want to
insert 31 back into the already sorted items. The first comparison against 93 causes 93 to be
shifted to the right. 77 and 54 are also shifted. When the item 26 is encountered, the shifting
process stops and 31 is placed in the open position. Now we have a sorted sublist of six items.
The implementation of insertionSort (ActiveCode 4) shows that there are again \(n- 1\)
passes to sort nitems. The iteration starts at position 1 and moves through position \(n-1\), as
these are the items that need to be inserted back into the sorted sublists. Line 8 performs the shift
operation that moves a value up one position in the list, making room behind it for the insertion.
Remember that this is not a complete exchange as was performed in the previous algorithms.
85
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
The maximum number of comparisons for an insertion sort is the sum of the first (n- 1\) integers.
Again, this is \(O(n^{2})\). However, in the best case, only one comparison needs to be done on
each pass. This would be the case for an already sorted list. One note about shifting versus
exchanging is also important. In general, a shift operation requires approximately a third of the
processing work of an exchange since only one assignment is performed. In benchmark studies,
insertion sort will show very good performance.
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
the quick sort. Figure shows that 54 will serve as our first pivot value. Since we have looked at
this example a few times already, we know that 54 will eventually end up in the position
currently holding 31.
87
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
The partitionprocess will happen next. It will find the split point and at the same time move
other items to the appropriate side of the list, either less than or greater than the pivot value.
Partitioning begins by locating two position markers—let’s call them leftmark and rightmark—at
the beginning and end of the remaining items in the list (positions 1 and 8 in Figure below. The
goal of the partition process is to move items that are on the wrong side with respect to the pivot
value while also converging on the split point. Figure above shows this process as we locate the
position of 54.
We begin by incrementing leftmark until we locate a value that is greater than the pivot value.
We then decrement rightmark until we find a value that is less than the pivot value. At this point
we have discovered two items that are out of place with respect to the eventual split point. For
our example, this occurs at 93 and 20. Now we can exchange these two items and then repeat the
process again. At the point where rightmark becomes less than leftmark, we stop. The position of
rightmark is now the split point. The pivot value can be exchanged with the contents of the split
point and the pivot value is now in place. In addition, all the items to the left of the split point are
less than the pivot value, and all the items to the right of the split point are greater than the pivot
value. The list can now be divided at the split point and the quick sort can be invoked recursively
on the two halves.
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
rightmark = last
done = False
while not done:
while leftmark <= rightmark and \
alist[leftmark] <= pivotvalue:
leftmark = leftmark + 1
while alist[rightmark] >= pivotvalue and \
rightmark >= leftmark:
rightmark = rightmark -1
if rightmark < leftmark:
done = True
else:
temp = alist[leftmark]
alist[leftmark] = alist[rightmark]
alist[rightmark] = temp
temp = alist[first]
alist[first] = alist[rightmark]
alist[rightmark] = temp
return rightmark
alist = [54,26,93,17,77,31,44,55,20]
quickSort(alist)
print(alist)
89
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
mid = len(alist)//2
lefthalf = alist[:mid]
righthalf = alist[mid:]
mergeSort(lefthalf)
mergeSort(righthalf)
i=0
j=0
k=0
while i<len(lefthalf) and j<len(righthalf):
if lefthalf[i]<righthalf[j]:
alist[k]=righthalf[j]
j=j+1
k=k+1
while i<len(lefthalf):
alist[k]=lefthalf[i]
i=i+1
k=k+1
while j<len(righthalf):
alist[k]=righthalf[j]
j=j+1
k=k+1
print("Merging ",alist)
alist = [54,26,93,17,77,31,44,55,20]
mergeSort(alist)
print(alist)
5.5. Searching
Computer systems are often used to store large amounts of data from which individual
records must be retrieved according to some search criterion. Thus the efficient storage of data to
facilitate fast searching is an important issue. In this section, we shall investigate the
performance of some searching algorithms and the data structures which they use.
5.6.1. Implementation
#include<iostream>
using namespace std;
int main() {
cout<<"Enter The Size Of Array: ";
int size;
cin>>size;
91
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
for(i=0;i<size;i++){
if(key==array[i]){
cout<<"Key Found At Index Number : "<<i<<endl;
break;
}
}
if(i != size){
cout<<"KEY FOUND at index : "<<i;
}
else{
cout<<"KEY NOT FOUND in Array ";
}
return 0;
}
92
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
93
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Sample Output:
94
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
To Make Logic First We Think That We Have To Traverse Whole Array Form Start
To End So we Decide To Use a Loop
First for Loop Taking Input in Array Element By Element Second Displaying Entered
Elements
Third for Loop Which is Main For Loop Having an if Condition Which Checks Every
Array Element with Key
If an Element Matches With Key if Condition Becomes True and Loop Terminates
With Break Statement
Then If Condition Outside Loop Which Will Become True Because Loop Variable 'i'
not Equal to Size Of Array
If Element Not Found In Array Than Loop Will Run Complete And If Condition Will
Not True Because in This Case Loop Will Run Complete And After Termination
Variable 'i' Will be Equal to Size Variable
Key is equal to 4
3rd for loop comparisons
i=0
if(1==4) false
i=1
if(2==4) false
i=2
if(3==4) false
i=3
if(4==4) True
break for loop
Output:
Key Found At Index Number : 3
95
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
96
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
c. AddToCollection will need to be modified to ensure that each item added is placed in its
correct place in the array.
The procedure is simple:
i. Search the array until the correct spot to insert the new item is found,
ii. Move all the following items up one position and
iii. Insert the new item into the empty position thus created.
bin_search is declared static. It is a local function and is not used outside this class: if it were not
declared static, it would be exported and be available to all parts of the program. The static
declaration also allows other classes to use the same name internally.
A technique for searching an ordered list in which we first check the middle item and – based on
that comparison - "discard" half the data. The same procedure is then applied to the remaining
half until a match is found or there are no more items left.
5.7.1. Characteristics
The worst case performance scenario for a linear search is that it needs to loop through the entire
collection; either because the item is the last one, or because the item isn't found. In other words,
if you have N items in your collection, the worst case scenario to find an item is N iterations.
This is known as O(N) using the Big O Notation. The speed of search grows linearly with the
number of items within your collection. Linear searches don't require the collection to be sorted.
In some cases, you'll know ahead of time that some items will be disproportionally searched for.
In such situations, frequently requested items can be kept at the start of the collection. This can
result in exceptional performance, regardless of size, for these frequently requested items.
Linear Search 1
Problem:
Given a list of N values, determine whether a given value X occurs in the list.
1 2 3 4 5 6 7 8 17 31 9 73 55 12 19 7
For example, consider the problem of determining whether the value 55 occurs in:
There is an obvious, correct algorithm:
start at one end of the list, if the current element doesn't equal the search target,
move to the next element, stopping when a match is found or the opposite end of the list is
reached.
Basic principle: divide the list into the current element and everything before (or after) it;
if current isn't a match, search the other case algorithm Linear Search takes number X, list
number L, number Sz
# Determines whether the value X occurs within the list L.
# Pre: L must be initialized to hold exactly Sz values
## Walk from the upper end of the list toward the lower end,
# looking for a match:
while
Sz > 0 AND L[Sz] != X
Sz := Sz - 1
endwhile
if Sz > 0
# See if we walked off the front of the list display true
# if so, no match else display false
# if not, got a match
97
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
Halt
Glossary
abstract class: A class primarily intended to define an instance, but can not be instantiated without
additional methods.
abstract data type: An abstraction that describes a set of items in terms of a hidden data structure and
operations on that structure.
abstraction: A mental facility that permits one to view problems with varying degrees of detail
depending on the current context of the problem.
accessor: A public member subprogram that provides query access to a private data member.
actor: An object that initiates behavior in other objects, but cannot be acted upon itself.
agent: An object that can both initiate behavior in other objects, as well as be operated upon by other
objects.
AKO: A Kind Of. The inheritance relationship between classes and their superclasses.
allocatable array: A named array having the ability to dynamically obtain memory. Only when space
has been allocated for it does it have a shape and may it be referenced or defined.
array overflow: An attempt to access an array element with a subscript outside the array size bounds.
array section: A subobject that is an array and is not a defined type component.
assignment operator: The equal symbol, “=”, which may be overloaded by a user.
98
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
automatic array: An explicit-shape array in a procedure, which is not a dummy argument, some or all
of whose bounds are provided when the procedure is invoked.
base class: A previously defined class whose public members can be inherited by another class. (Also
called a super class.)
behavior sharing: A form of polymorphism, when multiple entities have the same generic interface.
This is achieved by inheritance or operator overloading.
bintree: A tree structure where each node has two child nodes.
browser: A tool to find all occurrences of a variable, object, or component in a source code.
class: An abstraction of an object that specifies the static and behavioral characteristics of it, including
their public and private nature. A class is an ADT with a constructor template from which object
instances are created.
class attribute: An attribute whose value is common to a class of objects rather than a value peculiar to
each instance of the class.
class descriptor: An object representing a class, containing a list of its attributes and methods as well
as the values of any class attributes.
class diagram: A diagram depicting classes, their internal structure and operations, and the fixed
relationships between them.
class inheritance: Defining a new derived class in terms of one or more base classes.
client: A software component that users services from another supplier class.
constructor: An operation, by a class member function, that initializes a newly created instance of a
99
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
constructor operations: Methods which create and initialize the state of an object.
container class: A class whose instances are container objects. Examples include sets, arrays, and
stacks.
container object: An object that stores a collection of other objects and provides operations to access or
iterate over them.
control variable: The variable which controls the number of loop executions.
data abstraction: The ability to create new data types, together with associated operators, and to hide
the internal structure and operations from the user, thus allowing the new data type to be used in a
fashion analogous to intrinsic data types.
data hiding: The concept that some variables and/or operations in a module may not be accessible to a
user of that module; a key element of data abstraction.
data type: A named category of data that is characterized by a set of values. together with a way to
denote these values and a collection of operations that interpret and manipulate the values. For an
intrinsic type, the set of data values depends on the values of the type parameters.
deallocation statement: A statement which releases dynamic memory that has been previously allocated
to an allocatable array or a pointer.
debugger software: A program that allows one to execute a program in segments up to selected
breakpoints, and to observe the program variables.
declaration statement: A statement which specifies the type and, optionally, attributes of one or more
variables or constants.
default constructor: A class member function with no arguments that assigns default initial values to
all data members in a newly created instance of a class.
defined operator: An operator that is not an intrinsic operator and is defined by a subprogram that is
associated with a generic identifier.
deque: A container that supports inserts or removals from either end of a queue.
derived class: A class whose declaration indicates that it is to inherit the publicmembers of a previously
defined base class.
100
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
derived type: A user defined data type with components, each of which is either of intrinsic type or of
another derived type.
destructor: An operation that cleans up an existing instance of a class that is no longer needed.
destructor operations: Methods which destroy objects and reclaim their dynamic memory.
dummy argument: An argument in a procedure definition which will be associated with the actual
(reference or value) argument when the procedure is invoked.
dynamic binding: The allocation of storage at run time rather than compile time, or the run time
association of an object and one of its generic operations..
edit descriptor: An item in an input/output format which specifies the conversion between internal and
external forms.
encapsulation: A modeling and implementation technique (information hiding) that separates the
external aspects of an object from the internal, implementation details of the object.
exception: An unexpected error condition causing an interruption to the normal flow of program control.
explicit interface: For a procedure referenced in a scoping unit, the property of being an internal
procedure, a module procedure, an external procedure that has an interface (prototype) block, a recursive
procedure reference in its own scoping unit, or a dummy procedure that has an interface block.
explicit shape array: A named array that is declared with explicit bounds.
external file: A sequence of records that exists in a medium external to the program.
friend: A method, in C++, which is allowed privileged access to the private implementation of another
object.
function body: A block of statements that manipulate parameters to accomplish the subprogram’s
purpose.
function definition: Program unit that associates with a subprogram name a return type, a list of
arguments, and a sequence of statements thatmanipulate the arguments to accomplish the subprogram’s
101
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
purpose
function header: A line of code at the beginning of a function definition; includes the argument list, and
the function return variable name.
generic function: A function which can be called with different types of arguments.
generic identifier: A lexical token that appears in an INTERFACE statement and is associated with all
the procedures in the interface block.
generic interface block: A form of interface block which is used to define a generic name for a set of
procedures.
generic name: A name used to identify two or more procedures, the required one being determined by
the types of the non-optional arguments in the procedure invocation.
generic operator: An operator which can be invoked with different types of operands.
Has-A: A relationship in which the derived class has a property of the base class.
hashing technique: A technique used to create a hash table, in which the array element where an item
is to be stored is determined by converting some item feature into an integer in the range of the size of the
table.
heap: A region of memory used for data structures dynamically allocated and de-allocated by a program.
host association: Data, and variables automatically available to an internal procedure from its host.
information hiding: The principle that the state and implementation of an object should be private to
that object and only accessible via its public interface.
inheritance: The relationship between classes whereby one class inherits part or all of the public
description of another base class, and instances inherit all the properties and methods of the classes
which they contain.
instance diagram: A drawing showing the instance connection between two objects along with the
number or range of mapping that may occur.
instantiation: The process of creating (giving a value to) instances from classes.
intent: An attribute of a dummy argument that which indicates whether it may be used to transfer data
into the procedure, out of the procedure, or both.
interaction diagram: A diagram that shows the flow of requests, or messages between objects.
interface: The set of all signatures (public methods) defined for an object.
102
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
internal file: A character string that is used to transfer and/or convert data from one internal storage
mode to a different internal storage mode.
internal procedure: A procedure contained within another program unit, or class, and which can only
be invoked from within that program unit, or class.
intrinsic constructor: A class member function with the same name as the class which receives initial
values of all the data members as arguments.
Is-A: A relationship in which the derived class is a variation of the base class.
keyword: A programming language word already defined and reserved for a single special purpose.
link: The process of combining compiled program units to form an executable program.
linked list: A data structure in which each element identifies its predecessor and/or successor by some
form of pointer.
linker: Software that combines object files to create an executable machine language program.
member data: Variables declared as components of a defined type and encapsulated in a class.
method: A class member function encapsulated with its class data members.
method resolution: The process of matching a generic operation on an object to the unique method
appropriate to the object’s class.
message: A request, from another object, for an object to carry out one of its operations.
message passing: The philosophy that objects only interact by sending messages to each other that
request some operations to be performed.
module: A program unit which allows other program units to access variables, derived type definitions,
classes and procedures declared within it by USE association.
module procedure: A procedure which is contained within a module, and usually used to define generic
103
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
object: A concept, or thing with crisp boundaries and meanings for the problem at hand; an instance of a
class.
object diagram: A graphical representation of an object model showing relationships, attributes, and
operations.
object-oriented (OO): A software development strategy that organizes software as a collection of objects
that contain both data structure and behavior. (Abbreviated OO.)
octree: A tree structure where each node has eight child nodes.
OO (acronym): Object-oriented.
operation: Manipulation of an object’s data by its member function when it receives a request.
operator overloading: A special case of polymorphism; attaching more than one meaning to the same
operator symbol. ‘Overloading’ is also sometimes used to indicate using the same name for different
objects.
overflow: An error condition arising from an attempt to store a number which is too large for the storage
location specified; typically caused by an attempt to divide by zero.
overloading: Using the same name for multiple functions or operators in a single scope.
overriding: The ability to change the definition of an inherited method or attribute in a subclass.
parameterized classes: A template for creating real classes that may differ in well-defined ways as
specified by parameters at the time of creation. The parameters are often data types or classes, but
may include other attributes, such as the size of a collection. (Also called generic classes.)
pass-by-reference: Method of passing an argument that permits the function to refer to the memory
holding the original copy of the argument
pass-by-value: Method of passing an argument that evaluates the argument and stores this value in the
corresponding formal argument, so the function has its own copy of the argument value
pointer: A single data object which stands for another (a “target”), which may be a compound object
such as an array, or defined type.
104
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
pointer array: An array which is declared with the pointer attribute. Its shape and size may not be
determined until they are created for the array by means of a memory allocation statement.
polymorphism: The ability of an function/operator, with one name, to refer to arguments, or return
types, of different classes at run time.
pre-condition: Specifies the condition(s) that must be true before an operation can be executed.
private: That part of an class, methods or attributes, which may not be accessed by other classes, only
by instances of that class.
prototype: A statement declaring a function’s return type, name, and list of argument types.
public: That part of an object, methods or attributes, which may be accessed by other objects, and thus
constitutes its interface.
quadtree: A tree structure where each tree node has four child nodes.
query operation: An operation that returns a value without modifying any objects.
rank: Number of subscripted variables an array has. A scalar has rank zero, a vector has rank one, a
matrix has rank two.
scope: That part of an executable program within which a lexical token (name) has a single interpretation.
sequential: A kind of file in which each record is written (read) after the previously written (read) record.
service: A class member function encapsulated with its class data members.
shape: The rank of an array and the extent of each of its subscripts. Often stored in a rank-one array.
signature: The combination of a subprogram’s (operator’s) name and its argument (operand) types.
Does not include function result types.
105
Visit : www.EasyEngineeering.net
Visit : www.EasyEngineeering.net
stack: Region of memory used for allocation of function data areas; allocation of variables on the stack
occurs automatically when a block is entered, and deallocation occurs when the block is exited
strong typing: The property of a programming language such that the type of each variable must be
declared.
structure component: The part of a data object of derived type corresponding to a component of its
type.
sub-object: A portion of a data object that may be referenced or defined independently of other portions.
It may be an array element, an array section, a structure component, or a substring.
subprogram header: A block of code at the beginning of a subprogram definition; includes the name,
and the argument list, if any.
subscript triplet: A method of specifying an array section by means of the initial and final subscript
integer values and an optional stride (or increment).
super class: A class from which another class inherits. (See base class.)
supplier: Software component that implements a new class with services to be used by a client software
component.
template: An abstract recipe with parameters for producing concrete code for class definitions or
subprogram definitions.
thread: The basic entity to which the operating system allocates CPU time.
tree: A form of linked list in which each node points to at least two other nodes, thus defining a dynamic
data structure.
utility function: A private subprogram that can only be used within its defining class.
106
Visit : www.EasyEngineeering.net