Notes - DS Using C++ Sem IV CBCS - Opt
Notes - DS Using C++ Sem IV CBCS - Opt
Unit – I: Introduction to Data structure & Linear Data Structures: Array, Stack and Queue 18 Hrs.
Unit – II: Non Linear Data Structures: Linked List and Trees 18 Hrs.
Linked List: Concept of linked list, Types of Linked List (Singly-Doubly, Linear-Circular),
Implementation of Linked list, Operations on linear linked list (Insertion, Deletion, Display,
Search)
Application: Implementation of stack and queue using linked list.
Trees: Definition, Terminologies (Root, Child, Parent, Siblings, Descendant, Ancestor,
Leaf/External node, Branch node/Internal node, Degree, Edge, Path, Level, Depth, Height of node,
Height of tree, Forest)
Binary Tree: Definition, Types (Full/Proper/Plane, Complete, Perfect, Skewed, Balanced), Array
representation of Binary Tree
Binary Search Tree: Definition, Representation, Operations (Insertion, Deletion, Search, Tree
Traversal:Preorder, Inorder, Postorder)
Reference Books
1. Data Strucure using C and C++ -Rajesh Shukla
2. Data Strucure using C and C++ - Tanenbaum
3. Data Strucure using C++ - E Balagurusamy
4. Data Strucure using C++ - Yashwant Kanetkar
5. Data Strucure using C++ - D.S.Malik
B. Sc. II Sem. IV (CBCS) Paper VII - Data Structures using C++ Course Code -DSC12D
Unit – I: Introduction to Data structure & Linear Data Structures: Array, Stack and Queue
1.1.1 Definitions:
Data types: A data type is the most basic and the most common classification of data. It is this through
which the compiler gets to know the form or the type of information that will be used
throughout the code. So basically data type is a type of information transmitted between the
programmer and the compiler where the programmer informs the compiler about what type
of data is to be stored and also tells how much space it requires in the memory. Some basic
examples are int, float, string etc.
Data Object: A data object is a region of storage that contains a value or group of values. Each
value can be accessed using its identifier or a more complex expression that refers to the
object. In addition, each object has a unique data type. The data type of an object determines
the storage allocation for that object and the interpretation of the values during subsequent
access.
Data Structure is a systematic way to organize data in order to use it efficiently. Following terms are
the foundation terms of a data structure.
Interface
Each data structure has an interface. Interface represents the set of operations that a data structure
supports. An interface only provides the list of supported operations, type of parameters they can
accept and return type of these operations.
Prof. N. S. Kulkarni (Cell: 9890966539/9096194081) 1
B. Sc. II Sem. IV (CBCS) Paper VII - Data Structures using C++ Course Code -DSC12D
Implementation
Implementation provides the internal representation of a data structure. Implementation also
provides the definition of the algorithms used in the operations of the data structure.
1.1.3 Classification
Data Structures
Primitive Non-Primitive
Floating
Integer Character Pointer Array List File
Point
Linear Non-Linear
Data structures are generally categorized into two classes: primitive and non-primitive data structures.
1.2 Array
An array is a collection of same type of values stored in consecutive memory location. It can be used to
store the values of similar data types; either it is int, float, double, char and string. In other words array
is nothing but collection of element of same type stored under common name. Each value in array is
referenced by name and subscript or index, which indicates the position of the value in array. As
subscripts are used in arrays they are also referred as subscripted variables. The individual values in an
array are called the elements of array. The structure of an array; Myarray containing n element shown
in figure
Myarray[0] Myarray[1] Myarray[2] …………….. Myarray[n-1]
In figure Myarray[0] represents the first element of the array , Myarray [1] represents the second
element of array, Myarray [n-1] represents nth element of array. The simplest form of array is a one-
dimensional array that may be defined as a finite ordered set of homogeneous elements, which is
stored in contiguous memory locations.
Features
i. It is collection of similar data types
ii. Array is Linear/Sequential Data types as it stores its elements/members in consecutive
memory locations in memory.
iii. Array members can be accessed using an integer value that always starts at 0 and
known as index or subscript.
iv. It is multivalued variable as it stores multiple values together.
Array is a linear data structures which stores same kind of element or data. It is called a data structure
because it provide unique index or space for unique element and you can insert, delete ,sort and search
any element easily.
1 Single-Dimensional Array/ 1D
A one dimensional array is used to store linear list of values of the same type. The element in one
dimensional array is stored with the index values starting from 0 to one less than size of array. Each
element of one dimensional array accessed using the same name and single subscripts.
• Declaring one dimensional array
Similar to a variable you need to declare an array before using it. A one dimensional array can be
declared using the following syntax.
<data type> arrayname[dimension];
Here data type represents data type of the array variable, it is either int, float, long, char etc.
arrayname represents name of the array variable and size is nothing but number of elements you
want to store In that array of given data type.
Eg. float per[100]; int array[10];
• Initializing array variable
Once you declared one dimensional an array. You can initialize the individual elements of the array
one by one in same way as you declare a variable, you can also initialize all the elements of an array at
the same time of declaring the array
int marks[5]={ 39,45,90,98,32};
You also initialized array variable following way;
Marks[0]=39;
Marks[1]=45;
Marks[2]=90;
Marks[3]=98;
Marks[4]=32;
2 Two-Dimensional Array / 2D
A two dimensional array is used to store table of values of the same type. It is similar to matrix
containing rows and column
• Declaring one dimensional array
Similar to a variable you need to declare an array before using it. A two dimensional array can be
declared using the following syntax.
<data type > arrayname [dimension] [dimension];
Here data type represents data type of the array variable, it is either int, float, long, char etc.
arrayname represents name of the array variable and size is nothing but number of elements you
want to store In that array of given data type. In preceding syntax, the data type represents the data
type of an array to be declared. Size1 represents the number of rows and size 2 represents the
number of column. Eg. int myarray[3][3];
• Initializing array variable
arr 9 7 6 4 Coefficients
0 1 2 3 Exponents
a. Operations on Polynomial
1. Addition
For adding two polynomials using arrays is straightforward method, since both the arrays may
be added up element wise beginning from 0 to n-1, resulting in addition of two polynomials.
return sum;
}
return 0;
}
Prof. N. S. Kulkarni (Cell: 9890966539/9096194081) 8
B. Sc. II Sem. IV (CBCS) Paper VII - Data Structures using C++ Course Code -DSC12D
Output:
First polynomial is
5 + 0x^1 + 10x^2 + 6x^3
Second polynomial is
1 + 2x^1 + 4x^2
Sum polynomial is
6 + 2x^1 + 14x^2 + 6x^3
2. Product
Multiplication of two polynomials however requires manipulation of each node such that the
exponents are added up and the coefficients are multiplied. After each term of first
polynomial is operated upon with each term of the second polynomial, then the result has to
be added up by comparing the exponents and adding the coefficients for similar exponents
and including terms as such with dissimilar exponents in the result.
Output:
First polynomial is
5 + 0x^1 + 10x^2 + 6x^3
Second polynomial is
1 + 2x^1 + 4x^2
Product polynomial is
5 + 10x^1 + 30x^2 + 26x^3 + 52x^4 + 24x^5
2) Arrays are used to Store List of values
3) Arrays are used to Perform Matrix Operations
4) Arrays are used to implement Search Algorithms
5) Arrays are used to implement Sorting Algorithms
1.3 Sorting
Sorting is a process or operation of ordering items and data according to a specific criterion. For
example, sorting of numbers is ordering numbers either in ascending or descending order. Sorting
refers to the operation or technique of arranging and rearranging sets of data in some specific order. A
Prof. N. S. Kulkarni (Cell: 9890966539/9096194081) 10
B. Sc. II Sem. IV (CBCS) Paper VII - Data Structures using C++ Course Code -DSC12D
collection of records called a list where every record has one or more fields. The fields which contain a
unique value for each record is termed as the key field. For example, a phone number directory can be
thought of as a list where each record has three fields - 'name' of the person, 'address' of that person,
and their 'phone numbers'. Being unique phone number can work as a key to locate any record in the
list. The records are either sorted either numerically or alphanumerically. The records are then
arranged in ascending or descending order depending on the numerical value of the key. Here is an
example, where the sorting of a lists of marks obtained by a student in any particular subject of a class.
The techniques of sorting can be divided into two categories. These are:
• Internal Sorting
If all the data that is to be sorted can be adjusted at a time in the main memory, the internal
sorting method is being performed.
• External Sorting
When the data that is to be sorted cannot be accommodated in the memory at the same time
and some has to be kept in auxiliary memory such as hard disk, floppy disk, magnetic tapes
etc., then external sorting methods are performed.
This is an example of stable sorting here 26 appears twice at position 6 and 8 and their order is
preserved in unsorted and sorted array i.e., element 26 (blue) at position 6 appears first in unsorted
and sorted array (before and after sorting).
In the case of an unstable sort, this order of appearance before and after sorting is not
necessarily preserved. If a sorting algorithm, after sorting the contents, changes the sequence of
similar content in which they appear, it is called unstable sorting.
A Non-Adaptive Sorting Algorithm does not care if the array is already sorted or not it will apply its all
resources to sort the sorted elements.
If order of the elements to be sorted of an input array matters (or) affects the time complexity of a
sorting algorithm, then that algorithm is called “Adaptive” sorting algorithm. For example, Insertion
sort is an adaptive sorting algorithm, if input is already sorted then time complexity will be O(n).
Therefore, if input is nearly sorted then go for insertion sort, though this is not the only parameter to
go for Insertion sort over other sorting algorithms.
Merge Sort is an “Non-Adaptive” Sorting algorithm, because the order of the elements in the input
array doesn’t matter, time complexity will always be O(nlogn).
An adaptive algorithm takes advantage of helpful properties of the input, while Non-adaptive doesn't.
A simple example from manual arithmetic is methods for multiplying. Non-adaptive means you
multiply every digit no matter what, adaptive would be taking advantage of shifting left to multiply by
10 and possibly other tricks.
In the context of sorting, a non-adaptive algorithm takes the same amount of time for a given number
of values no matter what. An adaptive algorithm takes advantage of properties of the data. This
usually means taking advantage of any near sorted or already sorted portions. Heap sort and quicksort
are non-adaptive. Non-adaptive algorithms have the advantage of simplicity, Adaptive is often faster,
but the algorithm is more complex.
// Driver code
int main()
{
int arr[] = {64, 34, 25, 12, 22, 11, 90};
int n = sizeof(arr)/sizeof(arr[0]);
bubbleSort(arr, n);
cout<<"Sorted array: \n";
printArray(arr, n);
return 0;
}
For the first position in the sorted list, the whole list is scanned sequentially. The first position where
14 is stored presently, we search the whole list and find that 10 is the lowest value.
So we replace 14 with 10. After one iteration 10, which happens to be the minimum value in the list,
appears in the first position of the sorted list.
Prof. N. S. Kulkarni (Cell: 9890966539/9096194081) 14
B. Sc. II Sem. IV (CBCS) Paper VII - Data Structures using C++ Course Code -DSC12D
For the second position, where 33 is residing, we start scanning the rest of the list in a linear manner.
We find that 14 is the second lowest value in the list and it should appear at the second place. We
swap these values.
After two iterations, two least values are positioned at the beginning in a sorted manner.
The same process is applied to the rest of the items in the array. Number of comparisons : (n-1) + (n-
2) + (n-3) +.....+ 1 = n(n-1)/2 nearly equals to n2. Complexity = O(n2)
Advantages
a. Easy/simple to implement
b. Useful when no. of elements are less
c. Useful when memory is less.
Disadvantages
a. It is slower when no. of elements is large.
b. Performance varies with initial order of input.
Now for each pass, we compare the current element to all its previous elements. So in the first pass,
we start with the second element.
The illustration can be summarized in a tabular form:
Pass Unsorted list comparison Sorted list
1 {12,3,5,10,8,1} {12,3} {3,12,5,10,8,1}
2 {3,12,5,10,8,1} {3,12,5} {3,5,12,10,8,1}
3 {3,5,12,10,8,1} {3,5,12,10} {3,5,10,12,8,1}
4 {3,5,10,12,8,1} {3,5,10,12,8} {3,5,8,10,12,1}
5 {3,5,8,10,12,1} {3,5,8,10,12,1} {1,3,5,8,10,12}
6 {} {} {1,3,5,8,10,12}
As shown in the above illustration, we begin with the 2nd element as we assume that the first element
is always sorted. So we begin with comparing the second element with the first one and swap the
position if the second element is less than the first.
Disadvantages
a. Inefficient for large lists.
#include <iostream>
#include <stdio.h>
template <class t>
using namespace std;
1.5 Searching:
Searching is a process of locating a particular element present in a given set of elements. The element
may be a record, a table, or a file. A search algorithm is an algorithm that accepts an argument ‘a’ and
tries to find an element whose value is ‘a’. It is possible that the search for a particular element in a set
is unsuccessful if that element does not exist. There are number of techniques available for searching
1.5.1 Linear/Sequential Search
Sequential search is also called as Linear Search. Sequential search starts at the beginning of the list
and checks every element of the list. It is a basic and simple search algorithm. Sequential search
compares the element with all the other elements given in the list. If the element is matched, it
returns the value index, else it returns -1.
The above figure shows how sequential search works. It searches an element or value from an array till
the desired element or value is not found. If we search the element 25, it will go step by step in a
sequence order. It searches in a sequence order. Sequential search is applied on the unsorted or
unordered list when there are fewer elements in a list. In case of a sorted list searching starts from
0th element and continues until the element is found from the list or the element whose value is
greater than (assuming the list is sorted in ascending order), the value being searched is reached.
// C++ code to linearly search x in arr[]. If x is present then return its location,
// otherwise return -1
#include <iostream>
using namespace std;
int main(void)
{
int arr[] = { 2, 3, 4, 10, 40 };
int x = 10;
int n = sizeof(arr) / sizeof(arr[0]);
int result = search(arr, n, x);
(result == -1)? cout<<"Element is not present in array"
: cout<<"Element is present at index " <<result;
return 0;
}
• The above array is sorted in ascending order. As we know binary search is applied on sorted lists
only for fast searching.
For example, if searching an element 25 in the 7-element array, following figure shows how binary
search works:
Binary searching starts with middle element. If the element is equal to the element that we are
searching then return true. If the element is less than then move to the right of the list or if the
element is greater than then move to the left of the list. Repeat this, till you find an element.
int main()
{
int arr[] = { 2, 3, 4, 10, 40 };
int x = 10;
int n = sizeof(arr) / sizeof(arr[0]);
int result = binarySearch(arr, 0, n - 1, x);
(result == -1) ? cout << "Element is not present in array"
: cout << "Element is present at index " << result;
return 0;
}
1.6 Stack:
Stack is an abstract data type with a bounded (predefined) capacity. It is a simple data
structure that allows adding and removing elements in a particular order. Every time an element is
added, it goes on the top of the stack and the only element that can be removed is the element that is
at the top of the stack, just like a pile of objects.
Stack is a fundamental data structure which is used to store elements in a linear fashion. A
stack is similar to real-life stack or a pile of things that we stack one above the other. Stack follows
LIFO (last in, first out) order or approach in which the operations are performed. This means that the
element which was added last to the stack will be the first element to be removed from the stack.
Basic Operations
Following are the basic operations that are supported by the stack.
1. push – Adds or pushes an element into the stack.
2. pop – Removes or pops an element out of the stack.
3. peek – Gets the top element of the stack but doesn’t remove it.
4. isFull – Tests if the stack is full.
5. isEmpty – Tests if the stack is empty.
The stacks of elements of any particular type is a finite sequence of elements of that type together
with the following operations:
1. Initialize the stack to be empty
2. Determine whether the stack is empty or not
3. Check whether the stack is full or not
4. If the stack is not full, add or insert a new node at the top of the stack. This operation is
termed as Push Operation
5. If the stack is not empty, then retrieve the node at its top
6. If the stack is not empty, the delete the node at its top. This operation is called as Pop
operation
The stack can be represented in memory with the use of arrays. To do this job, you need to maintain a
linear array STACK, a pointer variable top which contains the top element.
#include <iostream>
#include<stdlib.h>
using namespace std;
class stack {
int stk[5];
int top;
public:
stack()
{
top = -1;
}
void push(int x)
{
if (top > 4) {
cout << "stack overflow";
return;
}
stk[++top] = x;
cout << "inserted " << x;
}
void pop()
{
if (top < 0) {
cout << "stack underflow";
return;
}
cout << "deleted " << stk[top--];
}
void display()
{
int main()
{
int ch;
stack st;
while (1) {
cout << "\n1.push 2.pop 3.display 4.exit\nEnter ur choice: "; cin >> ch;
switch (ch) {
case 1:
cout << "enter the element: "; cin >> ch;
st.push(ch);
break;
case 2:
st.pop();
break;
case 3:
st.display();
break;
case 4:
exit(0);
}
}
}
Applications of stack:
1. Recursion
It is technique of solving any problem by calling same function again and again until some breaking
(base) condition where recursion stops and it starts calculating the solution from there on. Thus in
recursion last function called needs to be completed first. Now Stack is a LIFO data structure and
hence it is used to implement recursion. The High level Programming languages, such as Pascal, C
etc. that provides support for recursion, use stack. In each recursive call, there is need to save the
current values of parameters, local variables and the return address (the address where the
control has to return from the call). Also, as a function calls to another function, first its
arguments, then the return address and finally space for local variables is pushed onto the stack.
2. Well-formed parentheses
One of the most important application of stacks is to check if the parentheses are balanced in a
given expression. The compiler generated an error if the parentheses are not matched. Following
are the steps to find whether a given expression is balanced or unbalanced
i. Input the expression and put it in a character Stack
ii. Scan the character from the expression one by one
iii. If the scanned character is a starting bracket then push it to the stack
2 (a + b) ∗ c ∗+abc ab+c∗
3 a ∗ (b + c) ∗a+bc abc+∗
5 (a + b) ∗ (c + d) ∗+ab+cd ab+cd+∗
1.7 Queue
Queue is an abstract data structure, somewhat similar to Stacks. Unlike stacks, a queue is open at
both its ends. One end is always used to insert data (enqueue) and the other is used to remove
data (dequeue). Queue follows First-In-First-Out methodology, i.e., the data item stored first will
be accessed first.
A real-world example of queue can be a single-lane one-way road, where the vehicle enters first,
exits first. More real-world examples can be seen as queues at the ticket windows and bus-stops.
Queue is a linear data structure where the first element is inserted from one end
called REAR and deleted from the other end called as FRONT. Front points to the beginning of the
queue and Rear points to the end of the queue. Queue follows the FIFO (First - In - First
Out) structure. According to its FIFO structure, element inserted first will also be removed first.
The enqueue() and dequeue() are two important functions used in a queue.
As in stacks, a queue can also be implemented using Arrays, Linked-lists, Pointers and
Structures. For the sake of simplicity, we shall implement queues using one-dimensional array.
As is clear from the name itself, simple queue lets us perform the operations simply.
i.e., the insertion and deletions are performed likewise. Insertion occurs at the rear
(end) of the queue and deletions are performed at the front (beginning) of the queue
list. All nodes are connected to each other in a sequential manner. The pointer of the
first node points to the value of the second and so on.
b. Circular
Unlike the simple queues, in a circular queue each node is connected to the next
node in sequence but the last node’s pointer is also connected to the first node’s
address. Hence, the last node and the first node also gets connected making a circular
link overall.
c. Priority
Priority queue makes data retrieval possible only through a pre-determined priority
number assigned to the data items. While the deletion is performed in accordance to
Prof. N. S. Kulkarni (Cell: 9890966539/9096194081) 27
B. Sc. II Sem. IV (CBCS) Paper VII - Data Structures using C++ Course Code -DSC12D
priority number (the data item with highest priority is removed first), insertion is
performed only in the order.
d. Double ended
The doubly ended queue or dequeue allows the insert and delete operations from
both ends (front and rear) of the queue.
#include<iostream>
#include<process.h>
#define MAX 50
using namespace std;
class Queue
{
int queue_arr[MAX];
int rear,front;
public:
Queue()
{
rear=-1;
front=-1;
}
//This function will insert an element to the queue
void enqueue()
{
int added_item;
if (rear==MAX-1)
{
cout<<"\nQueue Overflow\n";
return;
}
else
}
}
}
public:
Queue(){
front = -1;
rear = -1;
}
bool isFull(){
if(front == 0 && rear == SIZE - 1){
return true;
}
if(front == rear + 1) {
return true;
}
return false;
}
bool isEmpty(){
Prof. N. S. Kulkarni (Cell: 9890966539/9096194081) 30
B. Sc. II Sem. IV (CBCS) Paper VII - Data Structures using C++ Course Code -DSC12D
if(front == -1)
return true;
else
return false;
}
int deQueue(){
int element;
if(isEmpty() ){
cout << "Queue is empty" << endl;
return(-1);
}
else {
element = items[front];
if(front == rear){
front = -1;
rear = -1;
} /* Q has only one element, so we reset the queue after deleting it. */
else {
front=(front+1) % SIZE;
}
return(element);
}
}
void display()
{
/* Function to display status of Circular Queue */
int i;
if(isEmpty()) {
cout << endl << "Empty Queue" << endl;
}
else
{
cout << "Front -> " << front;
Prof. N. S. Kulkarni (Cell: 9890966539/9096194081) 31
B. Sc. II Sem. IV (CBCS) Paper VII - Data Structures using C++ Course Code -DSC12D
cout << endl << "Items -> ";
for(i=front; i!=rear;i=(i+1)%SIZE)
cout << items[i];
cout << items[i];
cout << endl << "Rear -> " << rear;
}
}
};
int main()
{
Queue q;
q.display();
q.enQueue(7);
q.display();
We can see a linked list in which every node contains two parts, data and a pointer to the next
node. The left part of the node which contains data may include a simple data type, an array, or a
structure. The right part of the node contains a pointer to the next node (or address of the next
node in sequence). The last node will have no next node connected to it, so it will store a special
value called NULL. Arrays can be used to store linear data of similar types, but arrays have the
following limitations-
1. The size of the arrays is fixed: So we must know the upper limit on the number of elements in
advance. Also, generally, the allocated memory is equal to the upper limit irrespective of the
usage.
2. Inserting a new element in an array of elements is expensive because the room has to be
created for the new elements and to create room existing elements have to be shifted.
2.1.3 Implementation
A linked list is represented by a pointer to the first node of the linked list. The first node is called
the head. If the linked list is empty, then the value of the head is NULL. Each node in a list consists
of at least two parts:
1) Data
2) Pointer (Or Reference) to the next node.
In C it can be represented as Structure but In C++, Linked List can be represented as a class and a
Node as a separate class. The Linked List class contains a reference of Node class type.
#include <iostream.h>
using namespace std;
class Node {
public:
int data;
Node* next;
};
2.1.4 Application
a) Implementation of stack using linked list.
A stack can be easily implemented through the linked list. In stack Implementation, a stack
contains a top pointer, which is “head” of the stack where pushing and popping items
happens at the head of the list. first node have null in link field and second node link have
first node address in link field and so on and last node address in “top” pointer.
The main advantage of using linked list over an arrays is that it is possible to
implements a stack that can shrink or grow as much as needed. In using array will put a
restriction to the maximum capacity of the array which can lead to stack overflow. Here
each new node will be dynamically allocate, so overflow is not possible.
In linked list implementation of a queue, the last inserted node is always pointed by 'rear' and
the first node is always pointed by 'front'.
Example
In above example, the last inserted node is 50 and it is pointed by 'rear' and the first inserted
node is 10 and it is pointed by 'front'. The order of elements inserted is 10, 15, 22 and 50.
2.2 Trees:
In computer science, a tree is a widely used abstract data type (ADT) that simulates a
hierarchical tree structure, with a root value and sub-trees of children with a parent node,
represented as a set of linked nodes. A tree is a collection of entities called nodes. Nodes are
connected by edges. Each node contains a value or data, and it may or may not have a child node.
The first node of the tree is called the root. If this root node is connected by another node,
the root is then a parent node and the connected node is a child. All Tree nodes are connected by
links called edges. It’s an important part of trees, because it’s manages the relationship
between nodes. Leaves are the last nodes on a tree. They are nodes without children. Like real
trees, we have the root, branches, and finally the leaves. The height of a tree is the length of the
longest path to a leaf. The depth of a node is the length of the path to its root.
Tree is a hierarchical data structure which stores the information naturally in the form of
hierarchy style. Tree is one of the most powerful and advanced data structures. It is a non-linear
data structure compared to arrays, linked lists, stack and queue.
2.2.1 Terminologies
Field Description
Root is a special node in a tree. The entire tree is referenced through it. It does
Root
not have a parent.
Path Path is a number of successive edges from source node to destination node.
Height of a node represents the number of edges on the longest path between
Height of Node
that node and a leaf.
Height of Tree Height of tree represents the height of its root node.
Depth of a node represents the number of edges from the tree's root node to
Depth of Node
the node.
Branch/Internal An internal node (also known as an inner node, inode for short, or branch node)
Node is any node of a tree that has child nodes
External/Leaf An external node (also known as an outer node, leaf node, or terminal node) is
/Terminal Node any node that does not have child nodes.
A descendant node of a node is any node in the path from that node to the
Descendant leaf node (including the leaf node). The immediate descendant of a node is the
“child” node.
An ancestor node of a node is any node in the path from that node to the
Ancestor
root node (including the root node).
It is the number of edges arriving at a node. The root node is the only node that
In-Degree
has an in-degree equal to zero.
b. Complete
A Binary Tree is complete Binary Tree if all levels are completely filled except possibly the last
level and the last level has all keys as left as possible.
c. Perfect
A Binary tree is Perfect Binary Tree in which all internal nodes have exactly two children and all
leaves are at the same level. A Perfect Binary Tree of height h (where height is the number of
nodes on the path from the root to leaf) has 2h – 1 node.
d. Skewed
A Binary tree, which is dominated solely by left child noted or right child nodes, is called a
skewed binary tree, more specifically left skewed binary tree or right skewed binary tree. All
skewed trees are pathological trees (tree where every parent node has only one child either
left or right).
e. Balanced
A binary tree is balanced if the height of the tree is O(Log n) where n is the number of nodes.
For Example, AVL tree maintains O(Log n) height by making sure that the difference between
heights of left and right sub-trees is at most 1. Red-Black trees maintain O(Log n) height by
making sure that the number of Black nodes on every root to leaf paths are same and there
Prof. N. S. Kulkarni (Cell: 9890966539/9096194081) 39
B. Sc. II Sem. IV (CBCS) Paper VII - Data Structures using C++ Course Code -DSC12D
are no adjacent red nodes. Balanced Binary Search trees are performance wise good as they
provide O(log n) time for search, insert and delete.
Three simple formulae allow you to go from the index of the parent to the index of its children and
vice versa:
• if index(parent) = N, index(left child) = 2*N+1
• if index(parent) = N, index(right child) = 2*N+2
• if index(child) = N, index(parent) = (N-1)/2 (integer division with truncation)
• The left sub-tree of a node has a key less than or equal to its parent node's key.
• The right sub-tree of a node has a key greater than to its parent node's key.
Thus, BST divides all its sub-trees into two segments; the left sub-tree and the right sub-tree and
can be defined as − left_subtree (keys) ≤ node (key) ≤ right_subtree (keys)
BST is a collection of nodes arranged in a way where they maintain BST properties. Each
node has a key and an associated value. While searching, the desired key is compared to the keys
in BST and if found, the associated value is retrieved. Following is a pictorial representation of BST
−
We observe that the root node key (27) has all less-valued keys on the left sub-tree and the
higher valued keys on the right sub-tree.
Let us consider that we have a tree T. let our tree T is a binary tree that us complete binary
tree. Then there is an efficient way of representing T in the memory called the sequential
representation or array representation of T. This representation uses only a linear array TREE as
follows:
1. The root N of T is stored in TREE [1].
2. If a node occupies TREE [k] then its left child is stored in TREE [2 * k] and its right child is
stored into TREE [2 * k + 1].
For Example:
Consider the following Tree:
2.4.2 Operations
1. Insertion
Step 1 - Create a newNode with given value and set its left and right to NULL.
Step 2 - Check whether tree is Empty.
Step 3 - If the tree is Empty, then set root to newNode.
Step 4 - If the tree is Not Empty, then check whether the value of newNode is smaller or
larger than the node (here it is root node).
Step 5 - If newNode is smaller than or equal to the node then move to its left child. If
newNode is larger than the node then move to its right child.
Step 6- Repeat the above steps until we reach to the leaf node (i.e., reaches to NULL).
Step 7 - After reaching the leaf node, insert the newNode as left child if the newNode
is smaller or equal to that leaf node or else insert it as right child.
2. Deletion
In a binary search tree, the deletion operation is performed with O(log n) time complexity.
Deleting a node from Binary search tree includes following three cases...
Case 1: Deleting a Leaf node (A node with no children)
We use the following steps to delete a leaf node from BST...
Step 1 - Find the node to be deleted using search operation
Step 2 - Delete the node using free function (If it is a leaf) and terminate the function.
Case 2: Deleting a node with one child
We use the following steps to delete a node with one child from BST...
Step 1 - Find the node to be deleted using search operation
Step 2 - If it has only one child then create a link between its parent node and child
node.
Step 3 - Delete the node using free function and terminate the function.
Case 3: Deleting a node with two children
We use the following steps to delete a node with two children from BST...
Step 1 - Find the node to be deleted using search operation
Step 2 - If it has two children, then find the largest node in its left subtree (OR)
the smallest node in its right subtree.
Step 3 - Swap both deleting node and node which is found in the above step.
Step 4 - Then check whether deleting node came to case 1 or case 2 or else goto step
2
Step 5 - If it comes to case 1, then delete using case 1 logic.
Step 6- If it comes to case 2, then delete using case 2 logic.
Step 7 - Repeat the same process until the node is deleted from the tree.
3. Search
In a binary search tree, the search operation is performed with O(log n) time complexity. The
search operation is performed as follows...
Step 1 - Read the search element from the user.
Step 2 - Compare the search element with the value of root node in the tree.
Step 3 -If both are matched, then display "Given node is found!!!" and terminate the
function
4. Traversal
a. Pre-order
1. Visit the root
2. Traverse the left sub tree i.e. call Preorder (left sub tree)
3. Traverse the right sub tree i.e. call Preorder (right sub tree)
Root → Left → Right
Applications-
• Preorder traversal is used to get prefix expression of an expression tree.
• Preorder traversal is used to create a copy of the tree
b. In-order
Traverse the left sub tree i.e. call Inorder (left sub tree)
1. Visit the root
2. Traverse the right sub tree i.e. call Inorder (right sub tree)
Prof. N. S. Kulkarni (Cell: 9890966539/9096194081) 44
B. Sc. II Sem. IV (CBCS) Paper VII - Data Structures using C++ Course Code -DSC12D
Left → Root → Right
Application-
• Inorder traversal is used to get infix expression of an expression tree.
c. Post-order
1. Traverse the left sub tree i.e. call Postorder (left sub tree)
2. Traverse the right sub tree i.e. call Postorder (right sub tree)
3. Visit the root
Left → Right → Root
Example-
Consider the following example-
Applications-
Example-
Application-
• Level order traversal is used to print the data in the same order as stored in the array
representation of a complete binary tree.