Ec6301 Oops & Ds Notes
Ec6301 Oops & Ds Notes
Ec6301 Oops & Ds Notes
Page 1
An Object is a collection of data members and associated member functions also known
as methods.
Classes
Classes are data types based on which objects are created. Objects with similar properties
and methods are grouped together to form a Class. Thus a Class represent a set of individual
objects. Characteristics of an object are represented in a class as Properties. The actions that can
be performed by objects becomes functions of the class and is referred to as Methods.
For example consider we have a Class of Cars under which Santro Xing, Alto and
WaganRrepresents individual Objects. In this context each Car Object will have its own, Model,
Year of Manufacture, Colour, Top Speed, Engine Power etc., which form Properties of the Car
class and the associated actions i.e., object functions like Start, Move, and Stop form the
Methods of CarClass.
No memory is allocated when a class is created. Memory is allocated only when an object
is created, i.e., when an instance of a class is created.
Inheritance
Inheritance is the process of forming a new class from an existing class or base class. The
base class is also known as parent class or super class. The new class that is formed is called
derived class. Derived class is also known as a child class or sub class. Inheritance helps in
reducing the overall code size of the program, which is an important concept in object-oriented
programming.
Page 2
Data Abstraction
Data abstraction refers to, providing only essential information to the outside world and
hiding their background details, i.e., to represent the needed information in program without
presenting the details.
Data abstraction is a programming (and design) technique that relies on the separation of
interface and implementation.
Data Encapsulation
Data Encapsulation combines data and functions into a single unit called class. When
using Data Encapsulation, data is not accessed directly; it is only accessible through the
functions present inside the class. Data Encapsulation enables the important concept of data
hiding possible.
Polymorphism
Polymorphism allows routines to use variables of different types at different times. An
operator or function can be given different meanings or functions. Polymorphism refers to a
single function or multi-functioning operator performing in different ways.
Overloading
Overloading is one type of Polymorphism. It allows an object to have different meanings,
depending on its context. When an existing operator or function begins to operate on new data
type, or class, it is understood to be overloaded.
Reusability
This term refers to the ability for multiple programmers to use the same written and
debugged existing class of data. This is a time saving device and adds code efficiency to the
language. Additionally, the programmer can incorporate new features to the existing class,
further developing the application and allowing users to achieve increased performance. This
time saving feature optimizes code, helps in gaining secured applications and facilitates easier
maintenance.
Dynamic Binding
Binding refers to the linking of a procedure call to the code. Dynamic binding means that
the code associated with a given procedure call.
Page 3
Message Passing
An object oriented program consists of a set of objects that communicate with each other.
Employee.salary (name)
Object
Message information
1.2 STRUCTURES
Structure is the collection of variables of different types under a single name for better
visualization of problem. Arrays is also collection of data but arrays can hold data of only one
type whereas structure can hold data of one or more types.
Defining a structure in C++ programming
The struct keyword defines a structure type followed by an identifier (name of the
structure). Then inside the curly braces, you can declare one or more members (declare variables
inside curly braces) of that structure. For example:
struct person {
char name[50];
int age;
float salary;
};
Here a structure person is defined which has three members: name, age and salary.
When a structure is created, no memory is allocated. The structure definition is only the
blueprint for the creating of variables. You can imagine it as a datatype. When you define an
integer as below:
int foo;
The int specifies that, variable foo can hold integer element only. Similarly, structure
definition only specifies that, what property a structure variable holds when it is defined.
Defining a structure variable
Once you declare a structure person as above. You can define a structure variable as:
person bill;
Page 4
Here, a structure variable bill is defined which is of type structure person. When structure
variable is defined, then only the required memory is allocated by the compiler. Considering you
have either 32-bit or 64-bit system, the memory of float is 4 bytes, memory of int is 4 bytes and
memory of char is 1 byte. Hence, 58 bytes of memory is allocated for structure variable bill.
Accessing members of a structure
The members of structure variable are accessed using dot operator. Suppose, you want to
access age of structure variable bill and assign it 50 to it. You can perform this task by using
following code below:
bill.age = 50;
C++ Program to assign data to members of a structure variable and display it
#include <iostream.h>
struct person
{
char name[50];
int age;
float salary;
};
void main()
{
person p1;
cout << "Enter Full name: ";
cin.get(p1.name, 50);
cout << "Enter age: ";
cin >> p1.age;
cout << "Enter salary: ";
cin >> p1.salary;
cout << "\nDisplaying Information." << endl;
cout << "Name: " << p1.name << endl;
cout <<"Age: " << p1.age << endl;
cout << "Salary: " << p1.salary;
Page 5
A pointer can be re-assigned any number of times while a reference cannot be reassigned
after binding.
Pointers can point nowhere (NULL), whereas reference always refer to an object.
You can't take the address of a reference like you can with pointers.
Page 6
Function declarations;
public :
Variable declarations;
Function declarations;
};
Example
class student
{
int rno;
int age;
public :
void get(int a,int b);
void put();
};
Creating Objects
Once a class has been declared, we can create variables of that type by using the class
name.
student s;
We may also declare more than one object in one statement.
student s1,s2,s3;
Accessing Class members
The private data of a class can be accessed only through the member functions of that
class.
objectname.functionname(actual arguments);
For example,
The function call statement
s.get(100,12);
s.put();
Page 7
Page 8
Page 9
}
void main()
{
int y;
...
}
variable x is accessible throughout the program, n and z are accessible throughout
function f (but not within function main), and variable m is accessible within block A (but not
accessible anywhere outside block A). Variable y is accessible only within function main. Thus
the scope of variable y is the block for function main, the scope of variable m is block A, and the
scope of variable x is the entire program.
Global and Local Scope
In general, global scope applies to an entire program and local scope is restricted to a
component, such as a function or block, of a program.
Thus x is global in the above code, while n and z are local to function f and m is local to
block A.
Some of the terms that are used for access privileges to identifiers defined in a class
definition are:
public: the identifier is accessible to any code anywhere
protected: the identifier is accessible only within the methods of the class in which it is defined
and in the methods of every subclass
private: the identifier is accessible only within the methods of the class in which it is defined.
The scope levels, in general, within a method of a class are
variables defined in the enclosing block, if there is an enclosing block; (This is repeated
until the outer block of the method body is reached.)
parameters;
Page 10
class foo {
int x, m;
Page 11
public:
A(); //Constructor
};
While defining a constructor you must remember that the name of constructor will be
same as the name of the class, and constructors never have return type.
Constructors can be defined either inside the class definition or outside the class
definition using class name and scope resolution :: operator.
class A
{
int i;
public:
A(); //Constructor declared
};
A::A() //Constructor definition
{
i=1;
}
The constructor functions have some special characteristics:
They do not have return types, and they cannot return values.
Types of Constructors
1. Default Constructor
2. Parameterized Constructor
3. Copy Constructor
4. Dynamic Constructor
1. Default Constructor
Default constructor is the constructor which doesn't take any argument. It has no
parameter.
Page 12
Syntax :
class_name ()
{ Constructor Definition }
Example :
class Cube
{
int side;
public:
Cube()
{
side=10;
}
};
void main()
{
Cube c;
cout << c.side;
}
Output : 10
In this case, as soon as the object is created the constructor is called which initializes its
data members.
A default constructor is so important for initialization of object members, that even if we
do not define a constructor explicitly, the compiler will provide a default constructor implicitly.
2. Parameterized Constructor
These are the constructors with parameter. Using this Constructor you can provide
different values to data members of different objects, by passing the appropriate values as
argument.
Example:
class Cube
{
Page 13
int side;
public:
Cube(int x)
{
side=x;
}
};
void main()
{
Cube c1(10);
Cube c2(20);
Cube c3(30);
cout << c1.side;
cout << c2.side;
cout << c3.side;
}
Output : 10 20 30
By using parameterized constructor in above case, we have initialized 3 objects with user
defined values. We can have any number of parameters in a constructor.
3. Copy Constructor
These are special type of Constructors which takes an object as argument, and is used to
copy values of data members of one object into other object.
Example:
class Cube
{
int side;
public:
Cube()
{
side=10;
Page 14
}
};
void main()
{
Cube c;
Cube c1(c);
cout << c.side;
cout<<c1.side;
}
Output: 10 10
4. Dynamic Constructor
This constructor is used to allocate the memory to the objects at the run time.The memory
allocation to objects is allocated with the help of 'new' operator.By using this constructor, we can
dynamically initialize the objects.
Example :
#include <iostream.h>
#include <conio.h>
class Account
{
private:
int account_no;
int balance;
public :
Account(int a,int b)
{
account_no=a;
balance=b;
}
void display()
{
Page 15
1.7 DESTRUCTORS
Destructor is a special class function which destroys the object as soon as the scope of
object ends. The destructor is called automatically by the compiler when the object goes out of
scope.
The syntax for destructor is same as that for the constructor, the class name is used for the name
of destructor, with a tilde ~ sign as prefix to it. Destructors will never have any arguments.
Syntax:
class A
{
Page 16
public:
~A();
};
Example:
class A
{
A()
{
cout << "Constructor called";
}
~A()
{
cout << "Destructor called";
}
};
void main()
{
A obj1; // Constructor Called
int x=1;
if(x)
{
A obj2; // Constructor Called
} // Destructor Called for obj2
} // Destructor called for obj1
Output:
Constructor called
Constructor called
Destructor called
Destructor called
Page 17
Page 18
width = wid;
}
// Note: printWidth() is not a member function of any class.
void printWidth( Box box )
{
/* Because printWidth() is a friend of Box, it can directly access any member of this class */
cout << "Width of box : " << box.width <<endl;
}
void main( )
{
Box box;
box.setWidth(10.0);
// Use friend function to print the width.
printWidth( box );
}
When the above code is compiled and executed, it produces the following result:
Width of box : 10
Storing its address in a pointer (so that the space can be accessed)
Page 19
If creating an array dynamically, use the same form, but put brackets with a size after the
type:
new int[40];
// declare a pointer p
p = new int;
De-allocation
Deallocation is the "clean-up" of space being used for variables or other data storage.
Compile time variables are automatically deallocated based on their known extent (this is the
same as scope for "automatic" variables). It is the programmer's job to deallocate dynamically
created space
To de-allocate dynamic memory, we use the delete operator
int * ptr = new int;
delete ptr;
Example
#include <iostream.h>
void main()
{
double * pvalue = NULL; // Pointer initialized with null
pvalue = new double; // Request memory for the variable
*pvalue = 29494.99;
Page 20
Only one copy of that member is created for the entire class and is shared by all the
objects of that class, no matter how many objects are created.
It is visible only within the class, but its lifetime is the entire program.
A static function can have access to only other static members declared in the same class.
A static member function can be called using the class name as follows:
o classname :: functionname;
Example
#include<iostream.h>
class test
{
int code;
static int count;
public :
void setcode()
{
code = ++count;
}
void showcode()
{
cout<< object number : << code;
}
static void showcount()
Page 21
{
cout<< Count : << count;
}
};
void main()
{
test t1,t2,t3;
t1.setcode();
t2.setcode();
test :: showcount();
test t3;
t3.setcode();
test :: showcount();
t1.showcode();
t2.showcode();
t3.showcode();
}
Ouput
Count : 2
Count : 3
Object number : 1
Object number : 2
Object number : 3
Page 22
Container
The STL contains many different container classes that can be used in different
situations. Generally speaking, the container classes fall into three basic categories: Sequence
containers, Associative containers, and Container adapters.
Sequence Containers
Sequence contains are container classes that maintain the ordering of elements in the
container. A defining characteristic of sequence containers is that you can choose where to insert
your element by position. The most common example of a sequence container is the array: if you
insert four elements into an array, the elements will be in the exact order you inserted them.
The STL contains 3 sequence containers: vector, deque, and list.
vector class in the STL is a dynamic array capable of growing as needed to contain its
elements. The vector class allows random access to its elements via operator[], and
inserting and removing elements from the end of the vector is generally fast.
A list is a special type of sequence container called a doubly linked list where each
element in the container contains pointers that point at the next and previous elements in
the list. Lists only provide access to the start and end of the list -- there is no random
access provided
Page 23
The following program inserts 6 numbers into a vector and uses the overloaded [] operator to
access them in order to print them.
Example
#include <vector.h>
#include <iostream.h>
void main()
{
vector<int>vect;
for (int nCount=0; nCount< 6; nCount++)
vect.push_back(10 - nCount); // insert at end of array
for (int nIndex=0; nIndex<vect.size(); nIndex++)
cout<<vect[nIndex] << " ";
}
Output
10 9 8 7 6 5
Associative Containers
Associative contains are containers that automatically sort their inputs when those inputs
are inserted into the container. By default, associative containers compare elements using
operator<. A set is a container that stores unique elements, with duplicate elements disallowed.
The elements are sorted according to their values.
A map (also called an associative array) is a set where each element is a pair, called a
key/value pair. The key is used for sorting and indexing the data, and must be unique.
The value is the actual data.
A multimap (also called a dictionary) is a map that allows duplicate keys. Real-life
dictionaries are multimaps: the key is the word, and the value is the meaning of the word.
All the keys are sorted in ascending order, and you can look up the value by key. Some
words can have multiple meanings, which is why the dictionary is a multimap rather than
a map.
Page 24
Container Adapters
Container adapters are special predefined containers that are adapted to specific uses. The
interesting part about container adapters is that you can choose which sequence container you
want them to use.
A stack is a container where elements operate in a LIFO (Last In, First Out) context,
where elements are inserted (pushed) and removed (popped) from the end of the
container. Stacks default to using deque as their default sequence container (which seems
odd, since vector seems like a more natural fit), but can use vector or list as well.
A queue is a container where elements operate in a FIFO (First In, First Out) context,
where elements are inserted (pushed) to the back of the container and removed (popped)
from the front. Queues default to using deque, but can also use list.
A priority queue is a type of queue where the elements are kept sorted (via operator<).
When elements are pushed, the element is sorted in the queue. Removing an element
from the front returns the highest priority item in the priority queue.
Iterator
An Iterator is an object that can traverse (iterate over) a container class without the user
having to know how the container is implemented. With many classes (particularly lists and the
associative classes), iterators are the primary way elements of these classes are accessed.
An iterator is best visualized as a pointer to a given element in the container, with a set of
overloaded operators to provide a set of well-defined functions:
* Dereferencing the iterator returns the element that the iterator is currently pointing
at.
++
Moves the iterator to the next element in the container. Most iterators also
Assign the iterator to a new position (typically the start or end of the containers
elements). To assign the value of the element the iterator is point at, deference the iterator first,
then use the assign operator.
== and != Basic comparison operators to determine if two iterators point to the same
element. To compare the values that two iterators are pointing at, deference the iterators first, and
then use a comparison operator.
Page 25
Each container includes four basic member functions for use with Operator=:
begin() returns an iterator representing the beginning of the elements in the container.
end() returns an iterator representing the element just past the end of the elements.
cbegin() returns a const (read-only) iterator representing the beginning of the elements in
the container.
cend() returns a const (read-only) iterator representing the element just past the end of the
elements.
Page 26
Proxy classes are used to simplify a complex object's interface, by hiding details that are
of no relevance within the object's current context.
When working with a large and complex object, it is often undesirable to copy the object,
but there may be a need to have several references to it. A
Proxy class ensures that there is only ever one instance of the object, and multiple
references are handled by multiple instances of the lightweight proxy, thus reducing the
memory footprint.
When all instances of the proxy fall from scope, the object itself falls from scope.
Note: Proxy classes do not derive from the classes they represent. They simply maintain a
pointer to the object and expose a limited (or simplified) interface to the object.
Example
class RealImage
{
int m_id;
public:
RealImage(int i)
{
m_id = i;
cout << " $$ ctor: " << m_id << '\n';
}
~RealImage()
{
cout << " dtor: " << m_id << '\n';
}
void draw()
{
Page 27
}
};
// 1. Design an "extra level of indirection" wrapper class
class Image
{
// 2. The wrapper class holds a pointer to the real class
RealImage *m_the_real_thing;
int m_id;
static int s_next;
public:
Image()
{
m_id = s_next++;
// 3. Initialized to null
m_the_real_thing = 0;
}
~Image()
{
delete m_the_real_thing;
}
void draw()
{
// 4. When a request comes in, the real object is created "on first use"
if (!m_the_real_thing)
m_the_real_thing = new RealImage(m_id);
// 5. The request is always delegated
m_the_real_thing->draw();
}
};
Page 28
int Image::s_next = 1;
void main()
{
Image images[5];
for (int i; true;)
{
cout << "Exit[0], Image[1-5]: ";
cin >> i;
if (i == 0)
break;
images[i - 1].draw();
}
}
Output
Exit[0], Image[1-5]: 2
$$ ctor: 2
drawing image 2
Exit[0], Image[1-5]: 4
$$ ctor: 4
drawing image 4
Exit[0], Image[1-5]: 2
drawing image 2
Exit[0], Image[1-5]: 0
dtor: 4
dtor: 2
Page 29
Page 30
2. Declare the operator function operator op() in the public part of the class. It may be
either a member function or a friend function.
3. Define the operator function to implement the required operations.
Almost any operator can be overloaded in C++. However there are few operator which
cannot be overloaded. Operators that are nor overloaded as follows.
size-of Operator
member selector(.)
Page 31
{
a = -a;
b = -b;
}
};
void main()
{
sample s;
s.get(10,20);
s.disp();
-s;
s.disp();
}
Output
10
20
-10
-20
sample(intx,int y)
{
a=x;
b=y;
Page 32
}
sample operator +(sample s)
{
sample t;
t.a=a+s.a;
t.b=b+s.b;
return(t);
}
voiddisp()
{
cout<< a << \t << b;
}
};
void main()
{
sample s1,s2,s3;
s1=sample(10,10);
s2=sample(10,10);
s3=s1+s2;
cout<< s1.disp();
cout<< s2.disp();
cout<< s3.disp();
}
Output
10
10
10
10
20
20
Function Overloading
Function overloading allows you to use the same name for different functions, to
perform, either same or different functions in the same class.
Page 33
Function overloading is usually used to enhance the readability of the program. If you
have to perform one single operation but with different number or types of arguments then you
can simply overload the function.
Example
#include<iostream.h>
int sum(int x,int y)
{
return x+y;
}
int sum(int x,int y, int z)
{
return x+y+z;
}
void main()
{
int a=sum(3,4);
cout<< a;
int b=sum(3,4,5);
cout<< b;
}
Output
7
12
Page 34
Page 35
Single Inheritance
A derived class with only one base class, is called single inheritance.
Example
#include<iostream.h>
#include<conio.h>
class A
{
public:
int a;
int b;
public:
void get()
{
cout<< Enter the value of a and b;
cin>> a >> b;
}
};
class B: public A
{
public:
int c;
public:
void add()
{
c = a + b;
cout<< Sum= << c;
}
};
void main()
Page 36
{
B b;
b.get();
b.add();
getch();
}
Output
Enter the value of a and b : 4 5
Sum = 9
Multiple inheritance
Deriving a class from more than one direct base class is called multiple inheritance.
Example
#include<iostream.h>
#include<conio.h>
class A
{
public:
int a;
public:
void geta()
{
cout<< Enter the value of a ;
cin>> a;
}
};
class B
{
public:
Page 37
int b;
public:
void getb()
{
cout<< Enter the value of a ;
cin>> b;
}
};
Page 38
Output
Enter the value of a : 4
Enter the value of b : 5
Sum = 9
Multilevel Inheritance
Deriving a class from another derived class is known as multilevel inheritance.
Example
#include<iostream.h>
#include<conio.h>
class A
{
public:
int a;
public:
void geta()
{
cout<< Enter the value of a ;
cin>> a;
}
};
class B : public A
{
public:
int b;
public:
void getb()
{
cout<< Enter the value of a ;
cin>> b;
Page 39
}
};
class C: public B
{
public:
int c;
public:
void add()
{
c = a + b;
cout<< Sum= << c;
}
};
void main()
{
C c;
c.geta();
c.getb();
c.add();
getch();
}
Output
Enter the value of a : 4
Enter the value of b : 5
Sum = 9
Hierarchical inheritance
Hierarchical inheritance is the process of deriving two or more classes from only one
base class.
Page 40
Example
#include<iostream.h>
#include<conio.h>
class A //Base Class
{
public:
int a,b;
void getnumber()
{
cout<<"\n\nEnter Number :::\t";
cin>>a;
}
};
class B : public A //Derived Class 1
{
public:
void square()
{
getnumber(); //Call Base class property
cout<<"\n\n\tSquare of the number :::\t"<<(a*a);
cout<<"\n\n\t----------------------------------------------------";
}
};
class C :public A //Derived Class 2
{
public:
void cube()
{
getnumber(); //Call Base class property
cout<<"\n\n\tCube of the number :::\t"<<(a*a*a);
Page 41
}
};
void main()
{
B b1;
Page 42
cin>>rno;
}
void putdata()
{
cout<<"\n\tName = "<<name;
cout<<"\n\tRollno = "<<rno<<endl;
}
};
class test:public virtual student
{
protected:
float mark1, mark2;
public:
void getmarks()
{
cout<<" Enter Mark 1 : ";
cin>>mark1;
cout<<" Enter Mark 2 : ";
cin>>mark2;
}
void putmarks()
{
cout<<"\tMark1 = "<<mark1<<endl;
cout<<"\tMark2 ="<<mark2<<endl;
}
};
class sports:public virtual student
{
protected:
float score;
Page 43
public:
void getscore()
{
cout<<" Enter the score in sports:";
cin>>score;
}
Void putscore()
{
cout<<"\tScore = "<<score<<endl;
}
};
class result:public test,public sports
{
float total;
public:
void display()
{
total=mark1+mark2+score;
putdata();
putmarks();
putscore();
cout<<"\tTotal = "<<total<<endl;
}
};
void main()
{
clrscr();
result r;
r.getdata();
r.getmarks();
Page 44
r.getscore();
cout<<"\n\t\t Result ";
r.display();
getch();
}
Output
Enter the name : Sam
Enter rollno : 36
Enter Mark 1 : 92
Enter Mark 2 : 93
Enter the score in sports: 99
Result
Name = Sam
Rollno = 36
Mark1 = 92
Mark2 = 93
Score = 99
Total = 284
Virtual Base Class
Grandparent
Parent 1
Parent 2
Child
Page 45
Inheritance by the child might pose some problems. All the public and protected
members of grandparent are inherited into child twice, first via parent1 again via parent2.
This means child would have duplicate sets of the members inherited from grandparent. This
introduces ambiguity and should be avoided.
The duplication of inherited members due to these multiple paths can be avoided by
making the common base class as virtual base class while declaring the direct or intermediate
base classes which is shown as follow:
class A
//grandparent
{
.
.
.
};
class B1 : virtual public A
//parent1
{
.
.
.
};
class B2 : virtual public A
//parent2
{
.
.
.
};
class C : public B1,public B2 //child
{
.
// will be inherited
Page 46
};
When a class is made a virtual base class, C++ takes necessary care to see that only one
copy of that class is inherited, regardless of how many inheritance path exist between the virtual
base class and a derived class.
Page 47
Page 48
By default all the members of a class would be private, for example in the following class
width is a private member, which means until you label a member, it will be assumed a private
member:
class Box
{
double width;
public:
double length;
void setWidth( double wid );
double getWidth( void );
};
Practically, we define data in private section and related functions in public section so
that they can be called from outside of the class as shown in the following program.
#include <iostream.h>
class Box
{
public:
double length;
void setWidth( double wid );
double getWidth( void );
private:
double width;
};
// Member functions definitions
double Box::getWidth(void)
{
return width ;
}
void Box::setWidth( double wid )
{
Page 49
width = wid;
}
// Main function for the program
void main( )
{
Box box;
// set box length without member function
box.length = 10.0; // OK: because length is public
cout << "Length of box : " << box.length <<endl;
// set box width without member function
// box.width = 10.0; // Error: because width is private
box.setWidth(10.0); // Use member function to set it.
cout << "Width of box : " << box.getWidth() <<endl;
}
When the above code is compiled and executed, it produces the following result:
Length of box : 10
Width of box : 10
The protected members
A protected member variable or function is very similar to a private member but it
provided one additional benefit that they can be accessed in child classes which are called
derived classes.
Following example is similar to above example and here width member will be accessible by any
member function of its derived class SmallBox.
#include <iostream.h>
class Box
{
protected:
double width;
};
class SmallBox:Box // SmallBox is the derived class.
Page 50
{
public:
void setSmallWidth( double wid );
double getSmallWidth( void );
};
// Member functions of child class
double SmallBox::getSmallWidth(void)
{
return width ;
}
void SmallBox::setSmallWidth( double wid )
{
width = wid;
}
// Main function for the program
void main( )
{
SmallBox box;
// set box width using member function
box.setSmallWidth(5.0);
cout << "Width of box : "<< box.getSmallWidth() << endl;
}
When the above code is compiled and executed, it produces the following result:
Width of box : 5
Page 51
from
outside
protected
public
yes
yes
yes
no
yes
yes
no
no
yes
private
protected
public
yes
yes
yes
no
yes
yes
no
no
no
derived
class?
Accessible
private
derived
class?
Accessibility in Protected Inheritance
Accessibility
Accessible from own class?
Accessible
from
derived
class?
Accessible
outside
derived
class?
Accessibility in Private Inheritance
Accessibility
private
from
class?
outside
public
yes
yes
yes
no
yes
yes
no
no
no
derived
class?
Accessible
protected
derived
Page 52
Public Inheritance
#include<iostream.h>
#include<conio.h>
class A
{
public:
int a;
int b;
public:
void get()
{
cout<< Enter the value of a and b;
cin>> a >> b;
}
};
class B: public A
{
public:
int c;
public:
void add()
{
c = a + b;
cout<< Sum= << c;
}
};
void main()
{
B b;
b.get();
Page 53
b.add();
getch();
}
Output
Enter the value of a and b : 4 5
Sum = 9
Private Inheritance
#include<iostream.h>
#include<conio.h>
class A
{
public:
int a;
int b;
public:
void get()
{
cout<< Enter the value of a and b;
cin>> a >> b;
}
};
class B: private A
{
public:
int c;
public:
void add()
{
c = a + b;
cout<< Sum= << c;
Page 54
}
};
void main()
{
B b;
b.get();
b.add();
getch();
}
Output
Enter the value of a and b : 4 5
Sum = 9
Protected Inheritance
#include<iostream.h>
#include<conio.h>
class A
{
public:
int a;
int b;
public:
void get()
{
cout<< Enter the value of a and b;
cin>> a >> b;
}
};
class B: protected A
{
public:
Page 55
int c;
public:
void add()
{
c = a + b;
cout<< Sum= << c;
}
};
void main()
{
B b;
b.get();
b.add();
getch();
}
Output
Enter the value of a and b : 4 5
Sum = 9
2.4 OVERRIDING
If base class and derived class have member functions with same name and arguments
or 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.
Page 56
Page 57
Page 58
{
int a;
public :
sample(int a)
{
this->a=a;
}
voiddisp()
{
cout<< A= << a;
cout<< this;
}
};
void main()
{
sample s(2);
s.disp();
}
Output
A=2
Page 59
implements the concept of virtual function as a simple member function, like all member
functions of the class.
Properties of Virtual Functions
Virtual Functions are resolved during run-time or dynamic binding. Virtual functions are
also simple member functions. The main difference between a non-virtual C++ member function
and a virtual member function is in the way they are both resolved. A non-virtual C++ member
function is resolved during compile time or static binding. Virtual Functions are resolved during
run-time or dynamic binding. Virtual functions are member functions of a class. Virtual
functions are declared with the keyword virtual. Virtual function takes a different functionality in
the derived class.
Example
#include<iostream.h>
#include<conio.h>
class base
{
public:
virtual void show()
{
cout<<"\n Base class show:";
}
void display()
{
cout<<"\n Base class display:" ;
}
};
class drive : public base
{
public:
void display()
{
Page 60
Page 61
// Length of a box
double breadth;
// Breadth of a box
double height;
// Height of a box
};
The purpose of an abstract class (often referred to as an ABC) is to provide an
appropriate base class from which other classes can inherit. Abstract classes cannot be used to
Page 62
Page 63
Page 64
Page 65
Concrete c(s);
c. printContent();
}
Page 66
{
cout<<"Constructing Derive";
}
~Derive(){ cout<<"Destroying Derive";}
};
void main()
{
Base *basePtr = new Derive();
delete basePtr;
}
The output after running the code above would be:
Constructing Base
Constructing Derive
Destroying Base
Based on the output above, we can see that the constructors get called in the appropriate
order when we create the Derive class object pointer in the main function. But there is a major
problem with the code above: the destructor for the "Derive" class does not get called at all when
we delete basePtr.
So, how can we fix this problem? we can make the base class destructor virtual, and that
will ensure that the destructor for any class that derives from Base (in our case, its the "Derive"
class) will be called.
]
Example with a Virtual Destructor
So, the only thing we will need to change is the destructor in the Base class and heres
what it will look like:
class Base
{
Page 67
public:
Base(){ cout<<"Constructing Base";}
will
be
in
reverse
order
of
their
derivation
in
the
derived
class.
Example
#include<iostream.h>
class Base
{
public:
Base ( )
{
Page 68
Page 69
Page 70
public:
void rollup() const {}
void rolldown() const {}
};
class Door {
public:
Window window;
void open() const {}
void close() const {}
};
class Car {
public:
Engine engine;
Wheel wheel[4];
Door left, right; // 2-door
};
void main() {
Car car;
car.left.window.rollup();
car.wheel[0].inflate(72);
}
Inheritance is a way to form new classes (instances of which are called objects) using
classes that have already been defined. One class can use features from another class to extend
its functionality (an Is a relationship) i.e., a Car is a Automobile.
Page 71
pointer is a type of pointer that points to a function instead of a variable. The function that a
function pointer points to can be called by using the function call operator (()) on the pointer.
For example, the following code calls the Add() function:
1
2
3
4
5
6
7
8
9
#include<iostream.h>
#include<conio.h>
int Add(int nX, int nY)
{
return nX + nY;
}
int main()
{
clrscr();
// Create a function pointer and make it point to the Add function
1
1
return 0;
}
Calling a function via a function pointer is also known as an indirect function call. The
following calculator program is functionally identical to the calculator example above, except it
uses a function pointer instead of a direct function call:
#include <iostream.h>
#include<conio.h>
int Add(int nX, int nY)
{
return nX + nY;
}
int Subtract(int nX, int nY)
{
return nX - nY;
}
Page 72
Page 73
}
In this example, instead of calling the Add(), Subtract(), or Multiply() function directly,
weve instead set pFcn to point at the function we wish to call. Then we call the function through
the pointer. The compiler is unable to use early binding to resolve the function call pFcn(nX,
nY) because it cannot tell which function pFcn will be pointing to at compile time!
Page 74
play(sq);
Upcasting allows us to treat a derived type as though it were its base type. Here the
assumption is "You're a Shape, I know you can move(), draw(), and shrink( ) yourself, do it, and
take care of the details correctly." Thus, the objects of all the classes are passed to the function
shape.
class Parent {
public:
void sleep() {}
};
class Child: public Parent {
public:
void gotoSchool(){}
};
int main( )
{
Parent parent;
Child child;
// upcast - implicit type cast allowed
Parent *pParent = &child;
// downcast - explicit type case required
Child *pChild = (Child *) &parent;
pParent -> sleep();
pChild -> gotoSchool();
return 0;
}
A Child object is a Parent object in that it inherits all the data members and member
functions of a Parent object. So, anything that we can do to a Parent object, we can do to
a Child object. Therefore, a function designed to handle a Parent pointer (reference) can perform
the same acts on a Child object without any problems. The same idea applies if we pass a pointer
Page 75
Page 76
Page 77
Page 78
Non Linear Data structure dont have a linear relationship between its adjacent elements.
Each node may point to several nodes. But in linear data structure, each node has a link which
points to another node.
Ex : Tree , Graph
Abstract Data Type (ADT)
A data type that is defined entirely by a set of operations is referred to as an ADT. An
ADT is a combination of interface and implementation. The interface defines the logical
properties of an ADT and especially the signature of its operations.
The implementation defines the representation of the data structure and the algorithm that
implements the operations.
Linear Data Structures
There are two methods by which we can construct a linear data structure. They are,
Method 1: By using a sequence of memory locations. These are implemented using arrays.
Method 2: By using pointers or links. These are implemented using linked lists.
The different types of linear data structures are:
Lists
The list can be implemented using arrays and pointers.
Stacks
The stacks can be implemented using arrays and linked lists.
Queues
The queue can be implemented using arrays and linked lists.
Non-Linear Data Structures
Non-linear data structure dont have a linear relationship between its adjacent elements.
Each node may point to several nodes. But in linear data structure ,each node has a link which
points to another node.
Example
Tree, Graph.
Tree
A tree is a non-linear data structure that may point to one (or) more nodes at a time.
Page 79
Graph
A graph is similar to tree except that it has no hierarchical relationship between its adjacent
elements.
Create a list.
Delete a list.
Implementation of LIST
List can be implemented in two ways. They are:
Using arrays
Page 80
#include<stdio.h>
#include<conio.h>
#define MAX 20 //maximum no of elements in the list
//user defined datatypes
struct list
{
int list[MAX];
int element; //new element to be inserted
int pos; //position of the element to be inserted or deleted
int length; //total no of elements
}l;
enum boolean { true, false };
typedef enum boolean boolean;
void main()
{
int ch;
int element;
int pos;
l.length = 0;
while(1)
{
ch = menu();
switch (ch)
{
case 1:
l.length = 0;
create();
break;
case 2:
if (islistfull() != true)
Page 81
case 3:
if (islistempty() != true)
{
printf("Enter the position of element to be deleted : ");
scanf("%d", &pos);
delet(pos);
}
else
{
printf("List is Empty.");
printf("\nPress any key to continue...");
getch();
}
break;
case 4:
printf("No of elements in the list is %d", l.length);
Page 82
case 5:
printf("Enter the element to be searched : ");
scanf("%d", &element);
find(element);
break;
case 6:
display();
break;
case 7:
exit(0);
break;
default:
printf("Invalid Choice");
printf("\nPress any key to continue...");
getch();
}
}
}
/* function to display the list of elements */
int menu()
{
int ch;
clrscr();
printf("\n\t\t********************************************\n");
printf("\t\t******LIST Implementation Using Arrays******\n");
printf("\t\t********************************************\n\n");
Page 83
Create\n\t2.
Insert\n\t3.
Count\n\t5.
Find\n\t6.
Display\n\t7.
Page 84
Page 85
if(pos == 0)
{
printf("\n\nCannot delete at zeroth position");
getch();
return;
}
if (pos > l.length)
{
printf("\n\nOnly %d elements exit. Cannot delete", l.length, pos);
printf("\nPress any key to continue...");
getch();
return;
}
for (i=pos-1; i<l.length; i++)
{
l.list[i] = l.list[i+1];
}
l.length--;
}
/* function to find the position of the given element, if exists */
void find(int element)
{
int i;
int flag = 1;
for (i=0; i<l.length; i++)
{
if(l.list[i] == element)
{
printf ("%d exists at %d position",element, i+1);
flag = 0;
Page 86
Page 87
A Linked list is a collection of elements called nodes, each of which stores two items
called info and link. Info is an element of the list and a link is a pointer to the next element. The
linked list is also called a chain.
The different types of Linked lists are,
In a singly linked list, the first node always pointed by a pointer called HEAD. If the link
of the node points to NULL, then that indicates the end of the list.
Operations of Singly Linked List
The following operations that can be performed on a singly linked list are,
NULL
head
Page 88
Next if we want to insert another element 20 into the linked list,then store the address of 20 in
the link part of 10.
10
20
NULL
head
Next if we want to insert another element 30 into the linked list,then store the address of 30 in
the link part of 20.
10
20
30
NULL
head
Example for deletion of an element
Now if we want to delete 20 from the linked list, just store the address of 30 in the link part of
10.
10
20
30
NULL
head
10
30
NULL
head
/* C++ Program to Implement Singly Linked List */
#include<iostream.h>
#include<stdlib.h>
/* Node Declaration */
struct node
{
int info;
struct node *next;
}*start;
/* Class Declaration */
class single_llist
Page 89
{
public:
node* create_node(int);
void insert_begin();
void insert_pos();
void insert_last();
void delete_pos();
void sort();
void search();
void update();
void reverse();
void display();
single_llist()
{
start =NULL;
}
};
/* Main :contains menu */
void main()
{
int choice, nodes, element, position, i;
single_llist sl;
start =NULL;
while(1)
{
cout<<endl<<"---------------------------------"<<endl;
cout<<endl<<"Operations on singly linked list"<<endl;
cout<<endl<<"---------------------------------"<<endl;
cout<<"1.Insert Node at beginning"<<endl;
cout<<"2.Insert node at last"<<endl;
Page 90
Page 91
cout<<endl;
break;
case5:
cout<<"Delete a particular node: "<<endl;
sl.delete_pos();
break;
case6:
cout<<"Update Node Value:"<<endl;
sl.update();
cout<<endl;
break;
case7:
cout<<"Search element in Link List: "<<endl;
sl.search();
cout<<endl;
break;
case8:
cout<<"Display elements of link list"<<endl;
sl.display();
cout<<endl;
break;
case9:
cout<<"Reverse elements of Link List"<<endl;
sl.reverse();
cout<<endl;
break;
case10:
cout<<"Exiting..."<<endl;
exit(1);
break;
Page 92
default:
cout<<"Wrong choice"<<endl;
}
}
}
/* Creating Node */
node *single_llist::create_node(int value)
{
struct node *temp, *s;
temp =new(struct node);
if(temp ==NULL)
{
cout<<"Memory not allocated "<<endl;
return0;
}
else
{
temp->info = value;
temp->next =NULL;
return temp;
}
}
/* Inserting element in beginning */
void single_llist::insert_begin()
{
int value;
cout<<"Enter the value to be inserted: ";
cin>>value;
struct node *temp, *p;
temp = create_node(value);
Page 93
if(start ==NULL)
{
start = temp;
start->next =NULL;
}
else
{
p = start;
start = temp;
start->next = p;
}
cout<<"Element Inserted at beginning"<<endl;
}
/* Inserting Node at last */
void single_llist::insert_last()
{
int value;
cout<<"Enter the value to be inserted: ";
cin>>value;
struct node *temp, *s;
temp = create_node(value);
s = start;
while(s->next !=NULL)
{
s = snext;
}
temp->next =NULL;
s->next = temp;
cout<<"Element Inserted at last"<<endl;
}
Page 94
Page 95
}
elseif(pos >1&& pos <= counter)
{
s = start;
for(i =1; i < pos; i++)
{
ptr = s;
s = s->next;
}
ptr->next = temp;
temp->next = s;
}
else
{
cout<<"Positon out of range"<<endl;
}
}
/* Sorting Link List */
void single_llist::sort()
{
struct node *ptr, *s;
int value;
if(start ==NULL)
{
cout<<"The List is empty"<<endl;
return;
}
ptr = start;
while(ptr !=NULL)
{
Page 96
Page 97
{
while(s !=NULL)
{
s = s->next;
counter++;
}
if(pos >0&& pos <= counter)
{
s = start;
for(i =1;i < pos;i++)
{
ptr = s;
s = s->next;
}
ptr->next = s->next;
}
else
{
cout<<"Position out of range"<<endl;
}
free(s);
cout<<"Element Deleted"<<endl;
}
}
/* Update a given Node */
void single_llist::update()
{
int value, pos, i;
if(start ==NULL)
{
Page 98
cout<<"List is empty"<<endl;
return;
}
cout<<"Enter the node postion to be updated: ";
cin>>pos;
cout<<"Enter the new value: ";
cin>>value;
struct node *s, *ptr;
s = start;
if(pos ==1)
{
start->info = value;
}
else
{
for(i =0;i < pos -1;i++)
{
if(s ==NULL)
{
cout<<"There are less than "<<pos<<" elements";
return;
}
s = s->next;
}
s->info = value;
}
cout<<"Node Updated"<<endl;
}
/* Searching an element */
void single_llist::search()
Page 99
{
int value, pos =0;
bool flag =false;
if(start ==NULL)
{
cout<<"List is empty"<<endl;
return;
}
cout<<"Enter the value to be searched: ";
cin>>value;
struct node *s;
s = start;
while(s !=NULL)
{
pos++;
if(s->info == value)
{
flag =true;
cout<<"Element "<<value<<" is found at position "<<pos<<endl;
}
s = s->next;
}
if(!flag)
cout<<"Element "<<value<<" not found in the list"<<endl;
}
/* Reverse Link List */
void single_llist::reverse()
{
struct node *ptr1, *ptr2, *ptr3;
if(start ==NULL)
Page 100
{
cout<<"List is empty"<<endl;
return;
}
if(start->next ==NULL)
{
return;
}
ptr1 = start;
ptr2 = ptr1->next;
ptr3 = ptr2->next;
ptr1->next =NULL;
ptr2->next = ptr1;
while(ptr3 !=NULL)
{
ptr1 = ptr2;
ptr2 = ptr3;
ptr3 = ptr3->next;
ptr2->next = ptr1;
}
start = ptr2;
}
/* Display Elements of a link list */
void single_llist::display()
{
struct node *temp;
if(start ==NULL)
{
cout<<"The List is Empty"<<endl;
return;
Page 101
}
temp = start;
cout<<"Elements of list are: "<<endl;
while(temp !=NULL)
{
cout<<temp->info<<"->";
temp = temp->next;
}
cout<<"NULL"<<endl;
}
APPLICATION OF LIST
POLYNOMIAL MANIPULATION
Polynomial addition, multiplication (8th degree polynomials) using arrays:
//Addition of Two Polynomial
#include <iostream.h>
#include <iomanip.h>
#include <conio.h>
struct poly{
int coeff;
int pow;
poly *next;
};
class add2poly
{
poly *poly1, *poly2, *poly3;
public:
add2poly(){poly1=poly2=poly3=NULL;}
void addpoly();
void display();
Page 102
};
void add2poly :: addpoly(){
int i,p;
poly *newl=NULL,*end=NULL;
cout<<"Enter highest power for x\n";
cin>>p;
//Read first poly
cout<<"\nFirst Polynomial\n";
for(i=p;i>=0;i--)
{
newl=new poly;
newl->pow=p;
cout<<"Enter Co-efficient for degree"<<i<<":: ";
cin>>newl->coeff;
newl->next=NULL;
if(poly1==NULL)
poly1=newl;
else
end->next=newl;
end=newl;
}
//Read Second poly
cout<<"\n\nSecond Polynomial\n";
end=NULL;
for(i=p;i>=0;i--)
{
newl=new poly;
newl->pow=p;
cout<<"Enter Co-efficient for degree"<<i<<":: ";
cin>>newl->coeff;
Page 103
newl->next=NULL;
if(poly2==NULL)
poly2=newl;
else
end->next=newl;
end=newl;
}
//Addition Logic
poly *p1=poly1,*p2=poly2;
end=NULL;
while(p1 !=NULL && p2!=NULL){
if(p1->pow == p2->pow){
newl=new poly;
newl->pow=p--;
newl->coeff=p1->coeff + p2->coeff;
newl->next=NULL;
if(poly3==NULL)
poly3=newl;
else
end->next=newl;
end=newl;
}
p1=p1->next;
p2=p2->next;
}
}
void add2poly :: display(){
poly *t=poly3;
cout<<"\n\nAnswer after addition is : ";
while(t!=NULL){
Page 104
cout.setf(ios::showpos);
cout<<t->coeff;
cout.unsetf(ios::showpos);
cout<<"X"<<t->pow;
t=t->next;
}
}
void main(){
clrscr();
add2poly obj;
obj.addpoly();
obj.display();
getch();
}
//Multiplication of 2 polynomials
#include <iostream.h>
class poly
{
private:
struct polynode
{
float coeff ;
intexp;
polynode*link ;
}*p ;
public:
poly();
void poly_append (float c, int e );
void display_poly();
Page 105
Page 106
polynode*temp = p ;
int f =0;
while( temp !=NULL)
{
if( f !=0)
{
if( temp -> coeff >0)
cout<<" + ";
else
cout<<" ";
}
if( temp ->exp!=0)
cout<< temp -> coeff <<"x^"<< temp ->exp;
else
cout<< temp -> coeff ;
temp= temp -> link ;
f =1;
}
}
void poly ::poly_multiply( poly &p1, poly &p2 )
{
polynode*temp1, *temp2 ;
float coeff1, exp1 ;
temp1 =p1.p;
temp2 =p2.p;
if( temp1 ==NULL&& temp2 ==NULL)
return;
if( temp1 ==NULL)
p =p2.p;
else
Page 107
{
if( temp2 ==NULL)
p =temp1 ;
else
{
while( temp1 !=NULL)
{
while( temp2 !=NULL)
{
coeff1 = temp1 -> coeff * temp2 ->coeff ;
exp1 = temp1 ->exp+ temp2 ->exp;
temp2 = temp2 ->link ;
padd( coeff1, exp1 );
}
temp2 =p2.p;
temp1 = temp1 ->link ;
}
}
}
}
void poly ::padd(float c, int e )
{
polynode*r, *temp ;
temp= p ;
if( temp ==NULL|| c > temp ->exp)
{
r =newpolynode ;
r-> coeff = c ;
r->exp= e ;
if( p ==NULL)
{
Page 108
Page 109
Page 110
p3.poly_multiply( p1, p2 );
cout<<"\nResultant polynomial: "<< endl ;
p3.display_poly();
}
Logic
Polynomial A: 3x3+2x2+x+1
Polynomial B: 5x3+7x
Step 1:
3x3
2x2
i
5x3
7x
j
8x3
k
Step 2:
3x3
2x2
i
5x
7x
j
8x3
2x2
k
Step 3:
3x3
2x2
Page 111
i
5x3
7x
j
8x3
2x2
8x
k
Step 4:
3x3
2x2
i
5x
8x
7x
j
2x
8x
Page 112
Coaches of train
Piles of notebook.
Array Implementation
An integer variable top can be used to mark the top of the stack.
Page 113
When a new element is to be pushed then the top can be incremented and the element can
be added.
Push operation
If the elements are added continuously to the stack using the push operation then the
stack grows at one end.
Initially when the stack is empty the top = -1. The top is a variable which indicates the
position of the topmost element in the stack.
If arrays are used for implementing the stacks, it would be very easy to manage the
stacks.
However, the problem with an array is that we are required to declare the size of the array
before using it in a program.
This means the size of the stack should be fixed. We can declare the array with a
maximum size large enough to manage a stack.
As result, the stack can grow or shrink within the space reserved for it.
Pop operation
On deletion of elements the stack shrinks at the same end, as the elements at the top get removed.
Page 114
#include<iostream.h>
#include<conio.h>
#include<stdlib.h>
class stack
{
int stk[5];
int top;
public:
stack()
{
top=-1;
}
void push(int x)
{
if(top >4)
{
cout<<"stack over flow";
return;
}
stk[++top]=x;
cout<<"inserted"<<x;
}
void pop()
{
Page 115
if(top <0)
{
cout<<"stack under flow";
return;
}
cout<<"deleted"<<stk[top--];
}
void display()
{
if(top<0)
{
cout<<" stack empty";
return;
}
for(int i=top;i>=0;i--)
cout<<stk[i]<<" ";
}
};
main()
{
int ch;
stack st;
while(1)
{
cout<<"\n1.push 2.pop 3.display 4.exit\nEnter ur choice";
cin>> ch;
switch(ch)
{
case1:cout<<"enter the element";
Page 116
cin>> ch;
st.push(ch);
break;
case2: st.pop();break;
case3: st.display();break;
case4:exit(0);
}
}
return(0);
}
Implementation of Stack ADT using Linked Lists
The stack can be implemented by using the singly linked list. This type of the
representation has more advantage than representing stack using array.They are,
Linked list representation of stack can grow and shrink in size without wasting the
memory space depending upon the insertion and deletion that occurs in the list.
Initially, when the stack is empty, top points to NULL. When an element is added using the
push operation, top is made to point to the latest element whichever is added.
Push operation
Create a temporary node and store the value of x in the data part of the node.
Now make link part of temp point to Top and then top point to Temp. That will make the
new node as the topmost element in the stack.
Page 117
Pop operation
The data in the topmost node of the stack is first stored in a variable called item.
Then a temporary pointer is created to point to top. The top is now safely moved to the
next node below it in the stack.
#include<iostream.h>
#include<conio.h>
#include<stdlib.h>
class node
{
public:
class node *next;
int data;
};
class stack :public node
{
Page 118
node *head;
int tos;
public:
stack()
{
tos=-1;
}
void push(int x)
{
if(tos <0)
{
head =new node;
head->next=NULL;
head->data=x;
tos ++;
}
else
{
node *temp,*temp1;
temp=head;
if(tos >=4)
{
cout<<"stack over flow";
return;
}
tos++;
while(temp->next !=NULL)
temp=temp->next;
temp1=new node;
temp->next=temp1;
Page 119
temp1->next=NULL;
temp1->data=x;
}
}
void display()
{
node *temp;
temp=head;
if(tos <0)
{
cout<<" stack under flow";
return;
}
while(temp !=NULL)
{
cout<<temp->data<<" ";
temp=temp->next;
}
}
void pop()
{
node *temp;
temp=head;
if( tos <0)
{
cout<<"stack under flow";
return;
}
tos--;
while(temp->next->next!=NULL)
Page 120
{
temp=temp->next;
}
temp->next=NULL;
}
};
main()
{
stack s1;
int ch;
while(1)
{
cout<<"\n1.PUSH\n2.POP\n3.DISPLAY\n4.EXIT\n enter ur choice:";
cin>> ch;
switch(ch)
{
case1:cout<<"\n enter a element";
cin>> ch;
s1.push(ch);
break;
case2: s1.pop();break;
case3: s1.display();
break;
case4:exit(0);
}
}
return(0);
}
Applications of Stack ADT
Some of the applications of the stack include,
Page 121
Towers of Hanoi
Towers of Hanoi
The objective of this puzzle is to transfer the entire disks from Tower1 to Tower3 using
Tower2.
The rules to be followed in moving the disks from tower1 to tower3 using tower2.
Only the top disc on any tower can be moved to any other tower.
It can be implemented using recursion. To move the largest disc to the bottom of tower3.
We move the remaining n-1 disks to tower2 and then move the largest disc to tower 3.
This process is continue until to place the entire disc in towerr3 in order.
Since, disc are moved from each tower in a LIFO manner each tower may be considered
as stack.
The least no of moves required to solve the problem according to our algorithm is given
by O(N)= 2N-1.
Main characteristics of the stack are reversing the order of its contents.
The tasks can be accomplished by pushing each character until the end of the string.
Now, the individual characters are popped off from the stack.
Since the last character pushed into the stack would be the first character to be popped off
from the stack.
Page 122
Since, the individual character are moved from the stack in a LIFO manner, the stack
operation is implemented.
Recursion is a process by which a function calls itself repeatedly until some specified
condition has been satisfied.
When a recursive program is executed, the recursive function calls are not executed
immediately.
They are placed on a stack (LIFO) until the condition that terminates the recursive
function.
The function calls are then executed in reverse order, as they are popped off the stack.
For example,
#include<stdio.h>
#include<conio.h>
void main()
{
int num,fac;
cout<<Enter the no;
cin>>num;
fac=fact(num);
printf(The factorial val %d is,fac);
}
int fact(int x)
{
if(x<=1)
return 1;
else
return (x*fact(x-1));
}
Evaluation of Arithmetic Expression
Page 123
Infix Notation
In this form of expressing an arithmetic expression the operator comes in between its
operands.
Advantages
Its easier to see visually which operation is done from the first to last.
Prefix Notation
It is a way of representing algebraic expression without the use of parenthesis (or) rules
of operator precedence.
In this form of expressing an arithmetic expression the operator is written before its
operands.
Postfix Notation
In this form of expressing an arithmetic expression the operator is written after its
operands.
Conversion of Notations
Rules to be followed during infix to postfix conversion
Page 124
Fully, parenthesize the expression starting from left to right. (During parenthesizing the
operators having higher precedence are the first parenthesized)
Move the operators one by one to their right such that each operator replaces their
corresponding right parenthesize.
The
part of the expression, which has been converted into postfix, is to be treated as
single operand.
Once, the expression is converted into postfix form remove all the paranthesis.
For example,
The infix expression is,
3 + 8 * 4 / 2 (8 -3)
3+8*4/2833+84*/283
3+84* 2/ 83
384*2/+-83
384*2/+83-The postfix expression is,3 8 4 * 2 / + 8 3 - Rules to be followed during infix to prefix conversion
Fully, parenthesize the expression starting from left to right. (During parenthesizing the
operators having higher precedence are the first parenthesized).
Move the operators one by one to their right such that each operator replaces their
corresponding right parenthesis.
The
part of the expression, which has been converted into postfix, is to be treated as
single operand.
Once, the expression is converted into postfix form remove all the paranthesis.
3 + 8 * 4 / 2 - (8 - 3)
3+8*4/2 - - 83
+ *84 /2 --83
+ / *84 2 - -83
+3 /* 84 2 - -83
+ 3/ * 84 2-83
Page 125
If the item is an operator push it on the stack , if any of the following conditions are
satisfied.
If the precedence of the operator at the top of the stack is of lower priority than the
operator being processed.
If all the above condition fails, then pop the operator being processed to the postfix
string.
When the infix string is empty, pop the elements of the stack onto the postfix string to get
the result.
STACK
a+b*c+(d*e+f)*g
POSTFIX STRING
a
+b*c+(d*e+f)*g
b *c+(d*e+f) *g
ab
*c+(d*e+f)*g
ab
c + (d*e+f)*g
+*
abc
+ ( d*e+f)*g
abc*+
(d*e+f)*g
+(
abc*+
d*e+f)*g
+(
abc*+ d
*e + f )*g
+( *
abc *+ d
e +f)*g
+(*
abc *+ de
f)*g
+(+
abc *+de *f
Page 126
)*g
+(+
abc *+de*f+
*g
+*
abc*+de*f+
+*
abc * + de * f+g*+
If an operator is encountered pop two elements from the stack evaluate those operands
with that operator and push the result back in the stack.
When the evaluation of the entire expression is over, the only thing left on the stack
should be the final result.
If there are zero (or) more than one operands left on the stack either your program is
inconsistent (or) the expression was invalid.
In a queue, the elements which are inserted at one end and deletions are made at another
end.
The end at which the insertions are made is referred to as the rear end.
The end at which the deletions are made is referred to as the front end.
In a queue , the first element inserted will be the first element to be removed. So a queue
is referred to as FIFO List.(First-in-First-out List).
Page 127
Deletion
Insertion
Front
Rear
Representation of Queue
Example
A Reservation Counter
Jobs in a printer
Enqueue()
Dequeue()
Enqueue()
This process is carried out by incrementing the rear end and adding a new element at the
rear end position.
Dequeue()
A dequeue() operation is carried out by incrementing the front end and deleting the first
element at the front end position.
Linear Queue
Circular Queue
Page 128
Deque
Linear Queue
The queue has two ends such as front end and rear end.
The rear end is where we insert the elements and the front end is where we delete the
elements.
In a linear queue if the front pointer is in first position, and the rear pointer is in the last
position then the queue is said to be fully occupied.
Initially, the front and rear ends are at the same position(Initialized to -1.)
When we insert the elements, the rear pointer moves one by one until the last index
position is reached.(the front pointer doesn't change.)
When we delete the elements, the front pointer moves one by one until the rear pointer is
reached.(the rear pointer doesn't change.)
If the front and rear pointer positions are initialized to -1, then the queue is said to be
empty.
Circular Queue
Circular Queue is another form of a linear queue in which the last position is connected to
the first position of the list.
It is similar to linear queue has two ends such as front and rear ends.
The rear end is where we insert the elements and front end is where we delete the
elements.
When we insert an element, the rear pointer moves one by one until the front end is
reached.(front end doesn't change.)
If the next position of the rear is front, then the queue is said to be fully occupied.
When we delete an element, the front pointer moves one by one until the rear end is
reached.
If the front end reaches the rear end, then the queue is said to be empty.
Page 129
It is another form of a queue in which insertion and deletions are made at the both front
and rear ends of the queue.
Represent
ation Of Deque
Implementation of Queue ADT
A queue can be implemented in two ways.
Page 130
The number of elements in the array is fixed. But the size of the queue is constantly
changed when the elements are enqueued and dequeued.
The queue is stored in a part of the array, so an array can be declared large enough to
hold the maximum no of elements of the queue.
During execution of the program, the queue size can be varied within the space reserved
for it.
Operations on a Queue
They are addition of an element to the queue and deletion of an element from the queue.
Two variables front and rear are used to point to the ends of the queue.
The front points to the front end of the queue where deletion takes place and rear points
to the rear end of the queue, where the addition of elements takes place.
Initially, when the queue is empty, the front and rear is equal to -1.
Creation()
Creation of a queue requires the declaration of an array and initializing front and rear end
indicates to -1 respectively.
Enqueue(X)
An element can be added to the queue only at the rear end of the queue.
If the queue is full, then addition cannot take place. Otherwise, the element is added to
the end of the list at the rear side.
Page 131
Dequeue( )
The dequeue ( ) operation deletes the element from the front of the queue.
Before deleting and element, it is checked if the queue is empty. If not the element
pointed by front is deleted from the queue and front is now made to point to the next
element in the queue.
Page 132
front=rear=-1;
return;
}
queue1[++rear]=x;
cout<<"inserted"<<x;
}
void delet()
{
if(front==rear)
{
cout<<"queue under flow";
return;
}
cout<<"deleted"<<queue1[++front];
}
void display()
{
if(rear==front)
{
cout<<" queue empty";
return;
}
for(int i=front+1;i<=rear;i++)
cout<<queue1[i]<<" ";
}
};
main()
{
int ch;
queue qu;
Page 133
while(1)
{
cout<<"\n1.insert 2.delet 3.display 4.exit\nEnter ur choice";
cin>> ch;
switch(ch)
{
case1:cout<<"enter the element";
cin>> ch;
qu.insert(ch);
break;
case2: qu.delet();break;
case3: qu.display();break;
case4:exit(0);
}
}
return(0);
}
Linked list implementation of queue
Linked lists do not have any restrictions on the number of elements it can hold.
Space for the elements in a linked list is allocated dynamically; hence it can grow as long
as there is enough memory available for dynamic allocation.
The queue represented using linked list would be represented as shown. The front
pointer points to the front of the queue and rear pointer points to the rear of the queue.
This representation has more advantages than representing queue using arrays.
Page 134
Linked list representation of queue can grow and shrink in size without wasting the
memory space depending upon the insertion and deletion that occurs in the list.
Basic Operations
The basic operations can be performed on the queue are,
Enqueue()
Dequeue()
Enqueue Operation
In linked list representation of queue, the addition of new element to the queue takes
place at the rear end. It is the normal operation of adding a node at the end of a list.
Dequeue Operation
The dequeue( ) operation deletes the first element from the front end of the queue.
Initially it is checked, if the queue is empty. If it is not empty, then return the value in the node
pointed by front, and moves the front pointer to the next node.
#include<iostream.h>
#include<conio.h>
#include<stdlib.h>
class node
{
public:
class node *next;
int data;
};
class queue :public node
{
Page 135
node *head;
int front,rare;
public:
queue()
{
front=-1;
rare=-1;
}
void push(int x)
{
if(rare <0)
{
head =new node;
head->next=NULL;
head->data=x;
rare ++;
}
else
{
node *temp,*temp1;
temp=head;
if(rare >=4)
{
cout<<"queue over flow";
return;
}
rare++;
while(temp->next !=NULL)
temp=temp->next;
temp1=new node;
Page 136
temp->next=temp1;
temp1->next=NULL;
temp1->data=x;
}}
void display()
{
node *temp;
temp=head;
if(rare <0)
{
cout<<" queue under flow";
return;
}
while(temp !=NULL)
{
cout<<temp->data<<" ";
temp=temp->next;
}
}
void pop()
{
node *temp;
temp=head;
if( rare <0)
{
cout<<"queue under flow";
return;
}
if(front == rare)
Page 137
{
front = rare =-1;
head=NULL;
return;
}
front++;
head=head->next;
}
};
main()
{
queue s1;
int ch;
while(1)
{
cout<<"\n1.PUSH\n2.POP\n3.DISPLAY\n4.EXIT\n enter ru choice:";
cin>> ch;
switch(ch)
{
case1:
cout<<"\n enter a element";
cin>> ch;
s1.push(ch);break;
case2: s1.pop();break;
case3: s1.display();break;
case4:exit(0);
}
}
return(0);
Page 138
}
Applications Of Queue Adt
The applications of the queue such as,
Priority Queue
Scheduling Algorithms
Priority queue
A priority queue is a collection of elements in which the elements are added to the end
and the high priority element is deleted.
In a priority queue, each and every element containing the key referred as the priority for
the elements.
The operations performed in a queue are similar to the queue except that the insertion and
deletion elements made in it.
Elements can be inserted in any order, but are arranged in order of their priority value in
the queue.
The elements are deleted from the queue in the order of their priority.
The elements with the same priority are given equal importance and processed
accordingly.
Modeling of systems. Where the keys might correspond to event times, to be processed in
chronological order.
CPU scheduling in computer systems, where the keys might correspond to priorities
indicating which processes are to be served first.
Numerical computations, where the keys might be computational errors indicating that
the largest should be dealt with first.
Page 139
UNIT IV
NON LINEAR DATA STRUCTURES
Syllabus: Trees Binary Trees Binary tree representation and traversals Application of trees:
Set representation and Union-Find operations Graph and its representations Graph Traversals
Representation of Graphs Breadth-first search Depth-first search Connected components.
Page 140
Ancestors
Ancestors of a node are all the nodes along the path from root to that node. Hence root is
ancestor of all the nodes in the tree.
Level
Level of a node is defined by letting root at level one. If a node is at level L, then its
children are at level L + 1.
Height or depth
The height or depth of a tree is defined to be the maximum level of any node in the tree.
Climbing
The process of traversing the tree from the leaf to the root is called climbing the tree.
Descending
The process of traversing the tree from the root to the leaf is called descending the tree.
Page 141
Right child
The node present to the right of the parent node is called the right child.
Page 142
(ii)
Page 143
A
B
D
A
1
B
2
C
4
D
7
Page 144
2.
3.
Algorithm ( Preorder)
PREORDER( ROOT )
Temp = ROOT
If temp = NULL
Return
End if
Print info(temp)
If left(temp) NULL
PREORDER( left(temp))
End if
If right(temp) NULL
PREORDER(right(temp))
End if
End PREORDER
Inorder Traversal
1. Traverse the left subtree of N in inorder.
2. Process the root N.
3. Traverse the right subtree of N in inorder.
Algorithm ( Inorder)
INORDER( ROOT )
Temp = ROOT
If temp = NULL
Return
End if
If left(temp) NULL
Page 145
INORDER(left(temp))
End if
Print info(temp)
If right(temp) NULL
INORDER(right(temp))
End if
End INORDER
Postorder Traversal
Traverse the left subtree of N in postorder.
Traverse the right subtree of N in postorder.
Process the root N.
Algorithm ( Postorder)
POSTORDER( ROOT )
Temp = ROOT
If temp = NULL
Return
End if
If left(temp) NULL
POSTORDER(left(temp))
End if
If right(temp) NULL
POSTORDER(right(temp))
End if
Print info(temp)
End POSTORDER
Page 146
Example
Pre-order: F, B, A, D, C, E, G, I, H
In-order: A, B, C, D, E, F, G, H, I
Page 147
Post-order: A, C, E, D, B, H, I, G, F
remElt would require a method that traverses the list and removes the given element
element is not already there. There are other ways to do this though: the constraint on "no
duplicates" is reflected in the behavior of the size method.
Representation using Binary Search Tree
One obvious way to implement sets is to use Binary Search Tree. The code would have a
variable of type list. The operations are:
Page 148
hasElt optimizes on hasElt on a plain binary tree: if the element youre looking for is not
in the root, the search recurs on only one of the left subtree (if the element to find is
smaller than that in the root) or the right subtree (if the element to find is larger than that
in the root).
addElt always inserts new elements at a leaf in the tree. It starts from the root, moving to
the left or right subtree as needed to maintain the invariant. When it hits a empty
tree, addElt replaces it with a new node with the data to add and two empty subtrees.
remElt traverses the BST until it finds the node with the element to remove at the root. If
the node has no children, remElt returns the empty tree. If the node has only one
child, remElt replaces it with its child node. If the node has two children, remElt replaces
the value in the node with either the largest element in the left subtree or the smallest
element in the right subtree; remElt then removes the moved node value from its subtree.
Union-Find Operations
Operations supported
Union( x, y ) - Performs a union o f the sets containing two elements x and y.
Find( x ) - Returns a pointer to the set Returns a pointer to the set containing element x.
Example applications
Algorithm
function MakeSet(x)
x.parent := x
function Find(x)
if x.parent == x
return x
else
return Find(x.parent)
function Union(x, y)
xRoot := Find(x)
Page 149
yRoot := Find(y)
xRoot.parent := yRoot
Undirected Graph
If the edge in a graph is not directionally oriented, then it is called undirected graph.
Path
It is a sequence of vertices w1, w2..wn such that (wi, wi+1) V for 1iN.
Page 150
Path length
It is the number of edges present in the path, which is equal to N-1 , where N is the
number of vertices.
Path: 1 2 3 1
Acyclic graph
A directed graph is said to be acyclic when there is no cyclic path in it. It is also called
DAG (Directed Acyclic graph).
Complete graph
A graph is said to be complete graph in which there is an edge between every pair of
vertices.
Page 151
Strongly Connected
In a digraph, if there is a path from every vertex to every other vertex is called strongly
connected. Otherwise it is said to be weakly connected graph.
A
Strongly Connected
Weakly Connected
Loop
A loop is a special case of a cycle in which a single arc Begins and ends with
the same vertex
A
Disjoint
A graph is said to be disjoint, if it is not connected.
Degree
The degree of a vertex is the number of arcs or edges incident to it.
Page 152
Indegree
The indegree is the numbers of arcs are entering into the vertex.
Outdegree
The outdegree of a vertex is the number of arcs exiting (or leaving) from the vertex.
B
E
Degree of D = 4
Indegree of D is 3
Outdegree of D is 1
Representation
Adjacency Matrix
Having mapped the vertices to integers, one simple representation for the graph uses
an adjacency matrix. Using a |V| x |V| matrix of booleans, we set aij = true if an edge
connects i and j. Edges can be undirected, in which case if aij = true, then aji = true also,
or directed, in which aij != aji, unless there are two edges, one in either direction,
between i and j. The diagonal elements, aii, may be either ignored or, in cases such as state
machines, where the presence or absence of a connection from a node to itself is relevant, set
to true or false as required.
When space is a problem, bit maps can be used for the adjacency matrix. In this case, an
ADT for the adjacency matrix improves the clarity of your code immensely by hiding the bit
twiddling that this space saving requires. In undirected graphs, only one half of the matrix needs
to be stored. If the graph is dense, i.e most of the nodes are connected by edges, then
the O(|V|2) cost of initializing an adjacency matrix is matched by the cost of inputting and
Page 153
setting the edges. However, if the graph is sparse, ie |E| is closer to |V|, then an adjacency list
representation may be more efficient.
Adjacency List Representation
Adjacency lists are lists of nodes that are connected to a given node. For each node, a
linked list of nodes connected to it can be set up. Adding an edge to a graph will generate two
entries in adjacency lists - one in the lists for each of its extremities.
Following is an example undirected graph with 5 vertices.
There are two methods for traversing through the nodes of the graph. They are.
* Breadth First Search Traversal
Page 154
As the name implies, this method traverse the nodes of the graph by searching through
the nodes breadth wise.
Rules
Select an unvisited node V, visit it. Its level is called the current level.
From each node X in the current level, in the order in which the level nodes were visited.
Visit all the unvisited neighbors of X. The newly visited nodes from this level form a new
level. This new level becomes the next current level.
Algorithm
Algorithm BFT ( G , n )
Begin
repeat for i=1 to n
visited[i] = 0
end repeat
repeat for i=1 to n
if visited[i] = 0
BFS(i)
end if
end repeat
end
Algorithm BFS ( v)
u=v
visited [ v ] = 1
repeat while ( true )
repeat for all vertices w adjacent from u
if visited [w] = 0
Add w to Queue
Page 155
end if
end repeat
if Queue is empty
return
end if
delete u from Queue
End while
End BFS
Page 156
As the name implies, this method traverse the nodes of the graph by searching through
the nodes depth wise.
Page 157
Rules
Select an unvisited node V, visit it. Its level is called the current level.
Find unvisited neighbors of the current node, visit it and make it the current node.
If more than one unvisited neighbors then resolve the tie by following the alphabetical
order.
If the current node has no unvisited neighbors, backtrack to its parent and make it new
current node.
Algorithm
Algorithm DFT ( G , n )
Begin
repeat for i=1 to n
visited[i] = 0
end repeat
repeat for i=1 to n
if visited[i] = 0
DFS(i)
end if
end repeat
end
Algorithm DFS ( v)
u=v
visited [ v ] = 1
repeat for each vertex w adjacent from v
if visited [w] = 0
DFS( w )
end if
End
Page 158
Page 159
Page 160
This traversal is done with the help of stack This traversal is done with the help of queue
data structure.
data structure.
It works using two ordering. The first order is It works using one ordering. The order in
the order in which the vertices are reached for which the vertices are reached in the same
the first time and second order in which the order they get removed from the queue.
vertices become dead.
DFS sequence is composed of tree edges and BFS sequence is composed of tree edges and
back edges.
cross edges.
The efficiency of the adjacency matrix graph is The efficiency of the adjacency matrix graph is
O(V2)
(V2)
The efficiency of the adjacency list graph is The efficiency of the adjacency list graph is
(|V|+|E|)
O(|V|+|E|)
We
can
find
all
strongly
connected
components
in
O(V+E)
time.
1) Create an empty stack S and do DFS traversal of a graph. In DFS traversal, after calling
Page 161
DFS
Reverse
for
adjacent
directions
of
vertices
of
all
arcs
vertex,
to
push
obtain
the
the
vertex
to
transpose
stack.
graph.
3) One by one pop a vertex from S while S is not empty. Let the popped vertex be v. Take v as
source and do DFS .The DFS starting from v prints strongly connected component of v.
Working
The above algorithm is DFS based. It does DFS two times. DFS of a graph produces a
single tree if all vertices are reachable from the DFS starting point. Otherwise DFS produces a
forest. So DFS of a graph with only one SCC always produces a tree. The important point to note
is DFS may produce a tree or a forest when there are more than one SCCs depending upon the
chosen starting point. For example, in the above diagram, if we start DFS from vertices 0 or 1 or
2, we get a tree as output. And if we start from 3 or 4, we get a forest.
To find and print all SCCs, we would want to start DFS from vertex 4 (which is a sink
vertex), then move to 3 which is sink in the remaining set (set excluding 4) and finally any of the
remaining vertices (0, 1, 2).Unfortunately, there is no direct way for getting this sequence.
However, if we do a DFS of graph and store vertices according to their finish times, we make
sure that the finish time of a vertex that connects to other SCCs (other that its own SCC), will
always be greater than finish time of vertices in the other SCC.
For example, in DFS of above example graph, finish time of 0 is always greater than 3
and 4 (irrespective of the sequence of vertices considered for DFS). And finish time of 3 is
always greater than 4. DFS doesnt guarantee about other vertices, for example finish times of 1
and 2 may be smaller or greater than 3 and 4 depending upon the sequence of vertices considered
for DFS. So to use this property, we do DFS traversal of complete graph and push every finished
vertex to a stack. In stack, 3 always appears after 4, and 0 appear after both 3 and 4.
In the next step, we reverse the graph. Consider the graph of SCCs. In the reversed graph, the
edges that connect two components are reversed. So the SCC {0, 1, 2} becomes sink and the
SCC {4} becomes source. In stack, we always have 0 before 3 and 4. So if we do a DFS of the
reversed graph using sequence of vertices in stack, we process vertices from sink to source. Print
SCCs one by one.
Page 162
Syllabus: Sorting algorithms: Insertion sort - Quick sort Merge sort Searching: Linear
search Binary search.
5.1 SORTING
Sorting is an operation of arranging data, in some given order such as increasing (or)
decreasing with numerical data (or) alphabetically with character data.Sorting methods can be
characterized into two categories:
Internal sorting
External sorting
Internal Sorting
Internal sorting methods are the methods that can be used when the list to be sorted is
small enough so that the entire sort can be carried out in main memory.The key principles of
internal sorting is that all the data items to be stored are retained in the main memory and random
access in the memory space can be efficiently used to sort the data items.The various internal
sorting techniques are:
Bubble sort
Selection sort
Insertion sort
Shell sort
Quick sort
External Sorting
External sorting methods are the methods to be used when the list to be sorted is large
and cannot be accommodated entirely in the main memory. In this case, some of data is present
in the main memory and some is kept in auxiliary memory such as hard disk, floppy disk, tape
etc.
The key principle of external sorting is to move data from secondary storage to main
memory in large blocks for ordering the data.The various external sorting methods are:
Page 163
Merge sort
Tape sort
memory.The insertion sort algorithm scans A from A[1] to A[N] inserting each element A[K]
into its proper position in the previously sorted subarray A[1],A[2],.A[k-1].
Principle
In insertion sort algorithm, each element A[k] in the list is compared with all the elements
before it (A[1] to A[k-1]).If any element A[1] is found to be greater than A[k] then A[k] is
inserted in the place of A[1]. This process is repeated till all the elements are sorted.
Program
#include<iostream.h>
#include<conio.h>
main()
{
int i,j,temp,a[10],n;
clrscr();
cout << "Enter the Limit :";
cin >> n;
cout << "Enter the elements :";
for(i=0;i<n;i++)
cin >> a[i];
for(i=1;i<=n-1;i++)
{
temp=a[i];
for(j=i;j>=1;j--)
{
if(temp < a[j-1])
Page 164
else
break;
}
a[j]=temp;
}
cout << "The Sorted List is :";
for(i=0;i<n;i++)
cout << a[i] << "\t";
getch();
}
Example
Advantages
Sorts the list faster when the list has less number of elements.
Efficient in cases where a new element has to be inserted into a sorted list.
Disadvantages
Page 165
Page 166
getch();
}
void mergesplit(int a[],int first,int last)
{
int mid;
if(first < last)
{
mid=(first+last)/2;
mergesplit(a,first,mid);
mergesplit(a,mid+1,last);
merge(a,first,mid,mid+1,last);
}
}
void merge(int a[],int f1,int l1,int f2,int l2)
{
int i,j,k=0;
i=f1;
j=f2;
while(i <= l1 && j <= l2)
{
if(a[i] < a[j])
b[k]=a[i++];
else
b[k]=a[j++];
k++;
}
while(i <= l1)
b[k++]=a[i++];
while(j <= l2)
b[k++]=a[j++];
Page 167
i=f1;
j=0;
while(i <= l2 && j < k)
a[i++]=b[j++];
}
Example
Advantages
Disadvantages
Needs a temporary array every time, for sorting the new list.
Page 168
The main idea of the quick sort is to divide the initial unsorted list into two parts, such
that the every element in the first list is less than all the elements present in the second list.The
procedure is repeated recursively for both the parts, upto relatively short sequence which can be
sorted until the sequences reduces to length one.The first step of the algorithm requires choosing
a pivot value that will be used to divide large and small numbers.
The first element of list is chosen as a pivot value.Once, the pivot value has been
selected, all the elements smaller than the pivot are placed towards the beginning of the set and
all the elements larger than the pivot are placed at the right.This process essentially sets the pivot
value in the correct place each time.Each side of the pivot is then quick sorted.
The quick sort algorithm reduces the unnecessary swaps and moves an item a great
distance in one move.The median-of-three portioning method is used to select the pivot. In this
method, three elements are randomly chosen and the median of these three values is chosen as
the pivot element.
Principle
A pivot item near the middle of the list is chosen, and the items on either side are moved
so that the data items on one side of the pivot element are smaller than the pivot element where
as those on the other side are larger.
The middle (or) the pivot element is now in its correct position. This procedure is then
applied recursively to the 2 parts of the list, on either side of the pivot element until the whole list
is sorted.
Program
#include<iostream.h>
#include<conio.h>
int i,j,n,pivot,a[20];
void quick(int a[],int left,int right);
void swap(int a[],int i,int j);
main()
{
int i,n,a[20];
cout << "Enter the limit";
Page 169
cin >> n;
cout << "Enter the elements";
for(i=0;i<n;i++)
cin >> a[i];
quick(a,0,n-1);
cout << "Sorted List is:";
for(i=0;i<n;i++)
cout << a[i];
getch();
}
void quick(int a[],int first,int last)
{
if(first < last)
{
pivot=a[first];
i=first;
j=last;
while(i < j)
{
while(a[i] <= pivot && i < last)
i++;
while(a[j] >= pivot && j > first)
j--;
if(i < j)
swap(a,i,j);
}
swap(a,first,j);
quick(a,first,j-1);
quick(a,j+1,last);
}
Page 170
}
void swap(int a[],int i,int j)
{
int t;
t=a[i];
a[i]=a[j];
a[j]=t;
}
Example
45
28
90
46
39
33
i/pivot
87
j
Increment i till the element pointed by i is less than pivot. Decrement j till the element
pointed by j is greater than the pivot element.
45
28
90
pivot
46
39
33
87
28
33
pivot
45
46
39
90
28
33
87
46
pivot
39
i
90
87
90
87
90
87
28
33
39
Pivot
45
Pivot
46
i
28
33
39
46
j
Page 171
Once, i and j crosses swap the element pointed by j and pivot and fix the position of the
pivot element.
39
28
33
45
46
90
87
Consider the elements left to pivot element as one sub array and the elements right to the
pivot as another sub array. Apply quick sort to the sub arrays separately.
39
28
33
Pivot/i
39
45
46
90
87
45
46
90
87
j
28
33
Pivot
j/i
If i and j stops at same position, swap the element pointed by j and pivot and fix the
position of the pivot element.
1
28
33
39
45
46
90
87
39
45
46
90
87
39
45
46
90
87
28
33
Pivot/i
1
j
28
Pivot/j
33
Once, i and j crosses swap the element pointed by j and pivot and fix the position of the
pivot element.
1
28
33
39
45
46
90
87
33
39
45
46
90
87
33
39
45
46
90
87
28
Pivot/i
1
Pivot/j
j
28
i
Once, i and j crosses swap the element pointed by j and pivot and fix the position of the
pivot element.
Page 172
28
39
45
46
90
87
45
46
90
87
90
87
28
33
39
Pivot/i
j
1
28
33
39
45
46
Pivot/j
Once, i and j crosses swap the element pointed by j and pivot and fix the position of the
pivot element.
1
28
33
39
45
46
90
87
39
45
46
90
87
28
33
Pivot/i
j
1
28
33
39
45
46
90
87
Pivot
i/j
If i and j stops at same position, swap the element pointed by j and pivot and fix the
position of the pivot element.
1
28
33
39
45
46
87
90
39
45
46
87
90
28
33
Page 173
Advantages
Faster than any other commonly used sorting algorithm. It has a best average case
behavior.
Reduces complexity.
Disadvantages
5.5 SEARCHING
Searching is the process which is used to find the location of a target element among a
list of elements. It is used in situation where we want to find whether a particular item is present
in a list or not. For eg, in a given voter list of a colony, a person may search his name to ascertain
whether he is a valid voter or not. There are two types of searching namely,
Linear search
Binary search
The search starts from the first element and continues in a sequential fashion from
element to element till the desired element is found.
In the worst case, a total number of N steps need to be taken for a list of size N.
Program
#include<iostream.h>
#include<conio.h>
void main()
{
clrscr();
Page 174
int a[100],i,n,item,s=0;
cout<<"\n------------ LINEAR SEARCH ------------ \n\n";
cout<<"Enter No. of Elements=";
cin>>n;
cout<<"\nEnter Elements=\n";
for(i=1;i<=n;i++)
{
cin>>a[i];
}
cout<<"\nEnter Element you want to Search=";
cin>>item;
for(i=1;i<=n;i++)
{
if(a[i]==item)
{
cout<<"\nData is Found at Location : "<<i;
s=1;
break;
}
}
f(s==0)
{
cout<<"Data is Not Found";
}
getch();
}
Page 175
Program
#include<iostream.h>
#include<conio.h>
void main()
{
clrscr();
int a[100],n,i,beg,end,mid,item;
beg=1;
end=n;
mid=(beg+end)/2;
Page 176
{
if(a[mid]<item)
beg=mid+1;
else
end=mid-1;
mid=(beg+end)/2;
}
if(a[mid]==item)
{
cout<<"\nData is Found at Location : "<<mid;
}
else
{
cout<<"Data is Not Found";
}
getch();
}
Example
Find 6 in {-1, 5, 6, 18, 19, 25, 46, 78, 102, 114}.
Step 1 (middle element is 19 > 6):
-1 5 6 18 19 25 46 78 102 114
-1 5 6 18 19 25 46 78 102 114
-1 5 6 18 19 25 46 78 102 114
Page 177
Page 178