DAA B.Tech 4th Unit 2 2
DAA B.Tech 4th Unit 2 2
Red-Black Trees
Red-Black tree is a binary search tree in which every node is colored with either red or black. It is a
type of self balancing binary search tree. It has a good efficient worst case running time complexity.
Properties of Red Black Tree:
So if your application involves frequent insertions and deletions, then Red-Black trees should be
preferred.
And if the insertions and deletions are less frequent and search is a more frequent operation, then
AVL tree should be preferred over the Red-Black Tree.
Step 2: END
Solution:
1. Start from the root.
2. Compare the inserting element with root, if less than root, then recurse for left, else recurse
for right.
3. If the element to search is found anywhere, return true, else return false.
we introduced Red-Black trees and discussed how balance is ensured. The hard part is to maintain
balance when keys are added and removed. We have also seen how to search an element from the
red-black tree. We will soon be discussing insertion and deletion operations in coming posts on the
Red-Black tree.
Exercise:
1) Is it possible to have all black nodes in a Red-Black tree?
2) Draw a Red-Black Tree that is not an AVL tree structure-wise?
Logic:
First, you have to insert the node similarly to that in a binary tree and assign a red colour to it. Now,
if the node is a root node then change its colour to black, but if it is not then check the colour of the
parent node. If its colour is black then don’t change the colour but if it is not i.e. it is red then check
the colour of the node’s uncle. If the node’s uncle has a red colour then change the colour of the
node’s parent and uncle to black and that of grandfather to red colour and repeat the same process
for him (i.e. grandfather).If grandfather is root then don’t change grandfather to red colour.
But, if the node’s uncle has black colour then there are 4 possible cases:
Left Left Case (LL rotation):
Right Right
Case (RR rotation):
Example: Creating a red-black tree with elements 3, 21, 32 and 15 in an empty tree.
Solution:
When the
first
element is inserted it is inserted as a root node and as root node has black colour so it acquires the
colour black.
The new
element is always inserted with a red colour and as 21 > 3 so it becomes the part of the right subtree
of the root node.
Now, as we
insert 32 we
see there is
a red father-
child pair
which violates
the Red-
Black tree
rule so we
have to rotate
it.
Moreover, we see the conditions of RR rotation (considering the null node of the root node as
black) so after rotation as the root node can’t be Red so we have to perform recolouring in the tree
resulting in the tree shown above.
Final Tree
Structure:
Augmenting Data Structure
What is an Augmented Data Structure?
Augmenting a Data Structure (or Augmented Data Structure) means adapting an existing data
structure to our needs. This allows us to take advantage of an original data structure that solves our
problem partially and make changes such that it fits to our problem completely.
Examples of Augmenting a Data Structure:
There are many examples of augmenting data structures, and augmenting is simply changing the
existing data structure to solve our problem.
Augmented Queue for Maximum Element: In an augmented queue, each element not only stores
its value but also maintains information about the maximum element in the current queue up
to that point.
Augmented Trie for Prefix Sums: Consider a trie (prefix tree) data structure where each node
stores the sum of values of all elements with the same prefix up to that node.
Augmented AVL Tree for Rank Queries: In an AVL tree (a self-balancing binary search tree),
each node can store the rank of that node in the tree, i.e., the number of nodes in its left
subtree plus one.
Augmented Disjoint Set (Union-Find) for Set Size: In a disjoint set data structure, each set
representative (root) could store the size of its corresponding set.
Naive Approach: A simple way to solve this problem is to use an array or a list to store the integers.
For insertion, you can just append the integer to the end of the list. For the query operation, iterate
through the list and count the elements less than or equal to k. This approach takes linear time for
the query operation.
Augmenting the Data Structure: To improve the efficiency of the query operation, we can augment
the data structure with additional information. One way to do this is by maintaining a sorted order
of elements. This can be achieved using a balanced Binary Search Tree (BST).
Structure of Augmented Tree: Each node in the BST should store the value of the element, the size of
the subtree rooted at that node, and pointers to the left and right children.
1. Insertion:
Insert the element into the BST as you normally would.
While inserting, update the size of each visited node.
2. Query:
Start at the root of the BST.
Traverse the tree:
If the current node’s value is less than or equal to k, add the size of its left subtree
(including itself) to the count.
Move to the left or right child accordingly.
B-Trees
B Tree is a specialized m-way tree that can be widely used for disk access. A B-Tree of order m can
have at most m-1 keys and m children. One of the main reason of using B tree is its capability to
store large number of keys in a single node and large key values by keeping the height of the tree
relatively small.
A B tree of order m contains all the properties of an M way tree. In addition, it contains the
following properties.
It is not necessary that, all the nodes contain the same number of children but, each node must have
m/2 number of nodes.
Searching in B Trees is similar to that in Binary search tree. For example, if we search for an item
49 in the following B Tree. The process will something like following :
1. Compare item 49 with root node 78. since 49 < 78 hence, move to its left sub-tree.
2. Since, 40<49<56, traverse right sub-tree of 40.
3. 49>45, move to right. Compare 49.
4. match found, return.
Searching in a B tree depends upon the height of the tree. The search algorithm takes O(log n) time
to search any element in a B tree.
Inserting
Insertions are done at the leaf node level. The following algorithm needs to be followed in order to
insert an item into B Tree.
1. Traverse the B Tree in order to find the appropriate leaf node at which the node can be
inserted.
2. If the leaf node contain less than m-1 keys then insert the element in the increasing order.
3. Else, if the leaf node contains m-1 keys, then follow the following steps.
Insert the new element in the increasing order of elements.
Split the node into the two nodes at the median.
Push the median element upto its parent node.
If the parent node also contain m-1 number of keys, then split it too by following the
same steps.
Example:
Insert the node 8 into the B Tree of order 5 shown in the following image.
The node, now contain 5 keys which is greater than (5 -1 = 4 ) keys. Therefore split the node from
the median i.e. 8 and push it up to its parent node shown as follows.
Deletion
Deletion is also performed at the leaf nodes. The node which is to be deleted can either be a leaf
node or an internal node. Following algorithm needs to be followed in order to delete a node from a
B tree.
If the the node which is to be deleted is an internal node, then replace the node with its in-order
successor or predecessor. Since, successor or predecessor will always be on the leaf node hence, the
process will be similar as the node is being deleted from the leaf node.
Example 1
Delete the node 53 from the B Tree of order 5 shown in the following figure.
53 is present in the right child of element 49. Delete it.
Now, 57 is the only element which is left in the node, the minimum number of elements that must
be present in a B tree of order 5, is 2. it is less than that, the elements in its left and right sub-tree are
also not sufficient therefore, merge it with the left sibling and intervening element of parent i.e. 49.
Searching an un-indexed and unsorted database containing n key values needs O(n) running time in
worst case. However, if we use B Tree to index this database, it will be searched in O(log n) time in
worst case.
Binomial Heap
The main application of Binary Heap is as implement a priority queue. Binomial Heap is an
extension of Binary Heap that provides faster union or merge operation with other operations
provided by Binary Heap. A Binomial Heap is a collection of Binomial Trees
A Binomial Heap is a set of Binomial Trees where each Binomial Tree follows the Min Heap
property. And there can be at most one Binomial Tree of any degree.
A Binomial Heap with n nodes has the number of Binomial Trees equal to the number of set bits in
the binary representation of n. For example, let n be 13, there are 3 set bits in the binary
representation of n (00001101), hence 3 Binomial Trees. We can also relate the degree of these
Binomial Trees with positions of set bits. With this relation, we can conclude that there are O(Logn)
Binomial Trees in a Binomial Heap with ‘n’ nodes.
A Binomial Heap is a set of Binomial Trees. A Binomial Tree must be represented in a way that
allows sequential access to all siblings, starting from the leftmost sibling (We need this in and
extracting() and delete()). The idea is to represent Binomial Trees as the leftmost child and right-
sibling representation, i.e., every node stores two pointers, one to the leftmost child and the other to
the right sibling.
Fibonacci Heap
A fibonacci heap is a data structure that consists of a collection of trees which follow min heap or
max heap property. These two properties are the characteristics of the trees present on a fibonacci
heap.
In a fibonacci heap, a node can have more than two children or no children at all. Also, it has more
efficient heap operations than that supported by the binomial and binary heaps.
The fibonacci heap is called a fibonacci heap because the trees are constructed in a way such that a
tree of order n has at least Fn+2 nodes in it, where Fn+2 is the (n + 2)th Fibonacci number.
Find Min
The minimum element is always given by the min pointer.
Union
Union of two fibonacci heaps consists of following steps.
1. Concatenate the roots of both the heaps.
2. Update min by selecting a minimum key from the new root lists.
Extract Min
It is the most important operation on a fibonacci heap. In this operation, the node with minimum
value is removed from the heap and the tree is re-adjusted.
The following steps are followed:
1. Delete the min node.
2. Set the min-pointer to the next root in the root list.
3. Create an array of size equal to the maximum degree of the trees in the heap before deletion.
4. Do the following (steps 5-7) until there are no multiple roots with the same degree.
5. Map the degree of current root (min-pointer) to the degree in the array.
6. Map the degree of next root to the degree in array.
7. If there are more than two mappings for the same degree, then apply union operation to
those roots such that the min-heap property is maintained (i.e. the minimum is at the root).
An implementation of the above steps can be understood in the example below.
1. We will perform an extract-min operation on the heap below.
2. Delete the min node, add all its child nodes to the root list and set the min-pointer to the next
root in the root list.
3. The maximum degree in the tree is 3. Create an array of size 4 and map degree of the next
roots with the array.
4. Here, 23 and 7 have the same degrees, so unite them.
s1 = {1, 2, 3, 4}
s2 = {5, 6, 7, 8}
We have two subsets named s1 and s2. The s1 subset contains the elements 1, 2, 3, 4, while s2
contains the elements 5, 6, 7, 8. Since there is no common element between these two sets, we will
not get anything if we consider the intersection between these two sets. This is also known as a
disjoint set where no elements are common. Now the question arises how we can perform the
operations on them. We can perform only two operations, i.e., find and union.
In the case of find operation, we have to check that the element is present in which set. There are
two sets named s1 and s2 shown below:
Suppose we want to perform the union operation on these two sets. First, we have to check whether
the elements on which we are performing the union operation belong to different or same sets. If
they belong to the different sets, then we can perform the union operation; otherwise, not. For
example, we want to perform the union operation between 4 and 8. Since 4 and 8 belong to different
sets, so we apply the union operation. Once the union operation is performed, the edge will be
added between the 4 and 8 shown as below:
When the union operation is applied, the set would be represented as:
s1Us2 = {1, 2, 3, 4, 5, 6, 7, 8}
Suppose we add one more edge between 1 and 5. Now the final set can be represented as:
s3 = {1, 2, 3, 4, 5, 6, 7, 8}
If we consider any element from the above set, then all the elements belong to the same set; it
means that the cycle exists in a graph.
U = {1, 2, 3, 4, 5, 6, 7, 8}
Each vertex is labelled with some weight. There is a universal set with 8 vertices. We will consider
each edge one by one and form the sets.
First, we consider vertices 1 and 2. Both belong to the universal set; we perform the union operation
between elements 1 and 2. We will add the elements 1 and 2 in a set s1 and remove these two
elements from the universal set shown below:
s1 = {1, 2}
The vertices that we consider now are 3 and 4. Both the vertices belong to the universal set; we
perform the union operation between elements 3 and 4. We will form the set s3 having elements 3
and 4 and remove the elements from the universal set shown as below:
s2 = {3, 4}
The vertices that we consider now are 5 and 6. Both the vertices belong to the universal set, so we
perform the union operation between elements 5 and 6. We will form the set s3 having elements 5
and 6 and will remove these elements from the universal set shown as below:
s3 = {5, 6}
The vertices that we consider now are 7 and 8. Both the vertices belong to the universal set, so we
perform the union operation between elements 7 and 8. We will form the set s4 having elements 7
and 8 and will remove these elements from the universal set shown as below:
s4 = {7, 8}
The next edge that we take is (2, 4). The vertex 2 is in set 1, and vertex 4 is in set 2, so both the
vertices are in different sets. When we apply the union operation, then it will form the new set
shown as below:
s5 = {1, 2, 3, 4}
The next edge that we consider is (2, 5). The vertex 2 is in set 5, and the vertex 5 is in set s3, so
both the vertices are in different sets. When we apply the union operation, then it will form the new
set shown as below:
s6 = {1, 2, 3, 4, 5, 6}
Now, two sets are left which are given below:
s4 = {7, 8}
s6 = {1, 2, 3, 4, 5, 6}
The next edge is (1, 3). Since both the vertices, i.e.,1 and 3 belong to the same set, so it forms a
cycle. We will not consider this vertex.
The next edge is (6, 8). Since both vertices 6 and 8 belong to the different vertices s4 and s6, we
will perform the union operation. The union operation will form the new set shown as below:
s7 = {1, 2, 3, 4, 5, 6, 7, 8}
The last edge is left, which is (5, 7). Since both the vertices belong to the same set named s7, a
cycle is formed.
Consider the vertices 5 and 6, i.e., (5, 6) and represent them graphically shown as below:
In the above figure, vertex 5 is the parent of vertex 6.
Now, we consider the vertices 7 and 8, i.e., (7, 8) and represent them through graphically shown as
below:
Now we consider the edge (2, 4). Since 2 and 4 belong to different sets, so we need to perform the
union operation. In the above case, we observe that 1 is the parent of vertex 2 whereas vertex 3 is
the parent of vertex 4. When we perform the union operation on the two sets, i.e., s1 and s2, then 1
vertex would be the parent of vertex 3 shown as below:
The next edge is (2, 5) having weight 6. Since 2 and 5 are in two different sets so we will perform
the union operation. We make vertex 5 as a child of the vertex 1 shown as below:
We have chosen vertex 5 as a child of vertex 1 because the vertex of the graph having parent 1 is
more than the graph having parent 5.
The next edge is (1, 3) having weight 7. Both vertices 1 and 3 are in the same set, so there is no
need to perform any union operation. Since both the vertices belong to the same set; therefore, there
is a cycle. We have detected a cycle, so we will consider the edges further.
Now we will see that how we can represent the sets in an array.
First, we consider the edge (1, 2). When we find 1 in an array, we observe that 1 is the parent of
itself. Similarly, vertex 2 is the parent of itself, so we make vertex 2 as the child of vertex 1. We add
1 at the index 2 as 2 is the child of 1. We add -2 at the index 1 where '-' sign that the vertex 1 is the
parent of itself and 2 represents the number of vertices in a set.
The next edge is (3, 4). When we find 3 and 4 in array; we observe that both the vertices are parent
of itself. We make vertex 4 as the child of the vertex 3 so we add 3 at the index 4 in an array. We
add -2 at the index 3 shown as below:
The next edge is (5, 6). When we find 5 and 6 in an array; we observe that both the vertices are
parent of itself. We make 6 as the child of the vertex 5 so we add 5 at the index 6 in an array. We
add -2 at the index 5 shown as below:
The next edge is (7, 8). Since both the vertices are parent of itself, so we make vertex 8 as the child
of the vertex 7. We add 7 at the index 8 and -2 at the index 7 in an array shown as below:
The next edge is (2, 4). The parent of the vertex 2 is 1 and the parent of the vertex is 3. Since both
the vertices have different parent, so we make the vertex 3 as the child of vertex 1. We add 1 at the
index 3. We add -4 at the index 1 as it contains 4 vertices.
Graphically, it can be represented as
The next edge is ( 2,5 ). When we find vertex 2 in an array, we observe that 1 is the parent of the
vertex 2 and the vertex 1 is the parent of itself. When we find 5 in an array, we find -2 value which
means vertex 5 is the parent of itself. Now we have to decide whether the vertex 1 or vertex 5
would become a parent. Since the weight of vertex 1, i.e., -4 is greater than the vertex of 5, i.e., -2,
so when we apply the union operation then the vertex 5 would become a child of the vertex 1 shown
as below:
In an array, 1 would be added at the index 5 as the vertex 1 is now becomes a parent of vertex 5. We
add -6 at the index 1 as two more nodes are added to the node 1.
The next edge is (1,3). When we find vertex 1 in an array, we observe that 1 is the parent of itself.
When we find 3 in an array, we observe that 1 is the parent of vertex 3. Therefore, the parent of both
the vertices are same; so, we can say that there is a formation of cycle if we include the edge (1,3).
The next edge is (6,8). When we find vertex 6 in an array, we observe that vertex 5 is the parent of
vertex 6 and vertex 1 is the parent of vertex 5. When we find 8 in an array, we observe that vertex 7
is the parent of the vertex 8 and 7 is the parent of itself. Since the weight of vertex 1, i.e., -6 is
greater than the vertex 7, i.e., -2, so we make the vertex 7 as the child of the vertex and can be
represented graphically as shown as below:
We add 1 at the index 7 because 7 becomes a child of the vertex 1. We add -8 at the index 1 as the
weight of the graph now becomes 8.
The last edge to be included is (5, 7). When we find vertex 5 in an array, we observe that vertex 1 is
the parent of the vertex 5. Similarly, when we find vertex 7 in an array, we observe that vertex 1 is
the parent of vertex 7. Therefore, we can say that the parent of both the vertices is same, i.e., 1. It
means that the inclusion (5,7) edge would form a cycle.
Till now, we have learnt the weighted union where we perform the union operation according to the
weights of the vertices. The higher weighted vertex becomes a parent and the lower weighted vertex
becomes a child. The disadvantage of using this approach is that some nodes take more time to
reach its parent. For example, in the above graph, if we want to find the parent of vertex 6, vertex 5
is the parent of vertex 6 so we move to the vertex 5 and vertex 1 is the parent of the vertex 5. To
overcome such problem, we use the concept 'collapsing find'.
How collapsing find technique works?
Consider the above example. Once we know the parent of the vertex 6 which is 1 then we directly
add the vertex 6 to the vertex 1. We will also update the array. In an array, add 1 at the index 6
because the parent of 6 is now 1. The process of directly linking a node to the direct parent of a set
is known as a collapsing find. Similarly, we can link the nodes 8 and 4 to the node 1.