Data Structure-tree
Data Structure-tree
Disadvantages
○ A queue, unlike a stack, cannot be constructed with a single pointer, making queue implementation slightly more involved.
○ If the queue is constructed as an array, it might soon fill up if too many elements are added, resulting in performance concerns
or possibly a crash.
○ When utilising a linked list to implement the queue, the memory overhead of each node can be significant, especially for small
elements.
Operations in Queue
○ Basic queue operations:
a. Enqueue add an element to the back/rear pointer
b. Dequeue remove an element from the front pointer
c. Peek: Returns the front element of the queue.
d. IsFull: Returns true is the queue is full otherwise returns false.
e. IsEmpty: Returns true is the queue is empty otherwise returns false.
Types of Queue
IF REAR = MAX - 1
Write OVERFLOW
Approach: Maintain two pointers, front, and rear. The front points to the first item of the queue and rear points to the last item.
Operations:
1. EnQueue(): This operation adds a new node after the rear and moves the rear to the next node.
2. DeQueue(): This operation removes the front node and moves the front to the next node.
Linked List implementation of Queue- Enqueue
1. Create a new node with the given data. struct Node {
2. If the queue is empty, set the front and rear to the new node.
int data;
3. Else, set the next of the rear to the new node and update the rear.
struct Node* next;
};
Linked List implementation of Queue- DeQueue
● Check if the queue is empty.
● If not empty, store the front node in a temporary variable.
● If the queue has only one element, update pointers to
NULL
● Else Update the front pointer to the next node.
● Free the temporary node.
Circular Queue
● A Circular Queue is an extended version of a normal queue where the last element of
the queue is connected to the first element of the queue forming a circle.
● The operations are performed based on FIFO (First In First Out) principle. It is also
called ‘Ring Buffer’.
ELSE IF REAR = MAX - 1 and FRONT ! = 0 (i.e. rear is filled and front portion is available)
SET REAR = 0 (point to first location)
ELSE
SET REAR = (REAR + 1) % MAX
[END OF IF]
Step 4: EXIT
Array Implementation of DeQueue
Step 1: Check if the queue is Empty
IF FRONT = -1
Write " UNDERFLOW "
Goto Step 4
Types of deque
In input restricted queue, insertion operation can be In output restricted queue, deletion operation can be
performed at only one end, while deletion can be performed at only one end, while insertion can be
performed from both ends.
performed from both ends.
Operations performed on Deque
○ Insertion at front
○ Insertion at rear
○ Deletion at front
○ Deletion at rear
Before performing these operations, we must follow the below two steps:
2. If the deque is empty, reinitialize rear = 0. And, add the new key into
array[rear].
2. If the deque has only one element (i.e. front = rear), set
front = -1 and rear = -1.
3. Else if front is at the last index (i.e. front = n - 1), set
front = 0.
4. Else, front = front + 1.
4. Delete from the Rear
1. Check if the deque is empty.
2. If the deque has only one element (i.e. front = rear), set
n - 1.
Child Node: The node which is the immediate successor of a node is called the
child node of that node.
Root Node: The topmost node of a tree or the node which does not have any parent
node is called the root node. A non-empty tree must contain exactly one root node
and exactly one path from the root to all other nodes of the tree.
Leaf Node or External Node: The nodes which do not have any child nodes are
called leaf nodes.
Ancestor of a Node: Any predecessor nodes on the path of the root to that node
are called Ancestors of that node. {A,B} are the ancestor nodes of the node {E}
Sibling: Children of the same parent node are called siblings. {D,E} are called
siblings.
Level of a node: The count of edges on the path from the root node to that node.
The root node has level 0.
Internal node: A node with at least one child is called Internal Node.
Neighbour of a Node: Parent or child nodes of that node are called neighbors of
that node.
Depth of a node: The depth of a node is defined as the length of the path
from the root to that node. Each edge adds 1 unit of length to the path. So,
it can also be defined as the number of edges in the path from the root of
the tree to the node.
Height of the Tree: The height of a tree is the length of the longest path
from the root of the tree to a leaf node of the tree.
Types of Trees
● Binary Trees: Each node has up to two children, the left child node and the right child node. This structure is the foundation for more
complex tree types like Binary Search Trees and AVL Trees.
● Ternary Tree: A Ternary Tree is a tree data structure in which each node has at most three child nodes, usually distinguished as “left”,
“mid” and “right”.
● N-ary Tree or Generic Tree: Generic trees are a collection of nodes where each node is a data structure that consists of records and a
list of references to its children. Unlike the linked list, each node stores the address of multiple nodes.
Binary Tree
Binary tree is a tree data structure(non-linear) in which each node can have at most
two children which are referred to as the left child and the right child.
struct node
{
int data;
struct node *left;
struct node *right;
}
Types of Binary Tree
Perfect Binary Tree: All the internal nodes have two children and Skewed Binary Tree: the tree is either dominated by the left nodes or the
all leaf nodes are at the same level.
right nodes
Complete Binary Tree: all the levels are completely filled except
Full Binary Tree: Each node has either zero children or two possibly the last level and the last level has all keys as left as
children. possible.
Binary Tree Implementation
#include <stdio.h>
int main() {
#include <stdlib.h>
// Initialize and allocate memory for tree nodes
struct Node* firstNode = createNode(2);
struct Node {
struct Node* secondNode = createNode(3);
int data;
struct Node* thirdNode = createNode(4);
struct Node *left;
struct Node* fourthNode = createNode(5);
struct Node *right;
};
// Connect binary tree nodes
firstNode->left = secondNode;
struct Node* createNode(int d)
firstNode->right = thirdNode;
{
secondNode->left = fourthNode;
struct Node* newNode =
(struct Node*)malloc(sizeof(struct Node));
return 0;
newNode->data = d;
}
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}
Operations On Binary Tree
● Create a Binary Tree
● Traversal in Binary Tree
● Insertion in Binary Tree
● Searching in Binary Tree
● Deletion in Binary Tree
Traversal in Binary Tree
1. Depth-First Search (DFS) algorithms: It explores as far down a branch as possible before backtracking. It is implemented using
recursion.
1. Preorder Traversal (root-left-right): Visits the node first, then left subtree, then right subtree.
2. Inorder Traversal (left-root-right): Visits left subtree, then the node, then the right subtree.
3. Postorder Traversal (left-right-root): Visits left subtree, then right subtree, then the node.
2. Breadth-First Search (BFS) algorithms: BFS explores all nodes at the present depth before moving on to nodes at the next
depth level. It is typically implemented using a queue.
Traversal in Binary Tree- Depth First Search
1. Preorder traversal is defined as a type of tree traversal that follows the Root-Left-Right policy:
● The root node of the subtree is visited first.
● Then the left subtree is traversed.
● At last, the right subtree is traversed.
Used in BST (Binary Search Tree), if any time there is a need to get the nodes in increasing order
Uses: 1. This is used for tree deletion because we need to delete subtrees before deleting the current node.
● All nodes present in the same level are traversed completely before traversing the next level.
● A lot of popular graph algorithms like Dijkstra’s shortest path, Kahn’s Algorithm, and Prim’s algorithm are based on BFS.
● It can be implemented using queue
Output:
1,2,3,4,5
Representation of binary trees
1. Linked List
2. Array
Array representation of binary trees
Complete binary trees are very suitable for array representation, since all the levels are completely filled except possibly the
last level and the last level has all keys as left as possible.
Array representation of binary trees
Advantages
● Arrays are stored in contiguous memory spaces, which is cache-friendly and allows for faster access and traversal.
● It does not require storing pointers, which saves space.
● It allows random access to nodes.
Limitations
● Array storage requires contiguous memory space, so it is not suitable for storing trees with a large amount of data.
● Adding or deleting nodes requires array insertion and deletion operations, which are less efficient.
● When there are many None values in the binary tree, the proportion of node data contained in the array is low, leading to lower
space utilization.
Binary Search Tree
● All nodes of the left subtree are less than the root node and nodes of the right subtree are
struct node {
greater than the root node. int data;
● The In-order traversal of binary search trees gives the values in ascending order. struct node *right_child;
struct node *left_child;
● All the subtrees of BST hold the same properties.
};
● Because the items are maintained in sorted order in a binary search tree, searching becomes
easier.
Operations on BST C
● Search in BST
● Insertion in BST
● Deletion in BST
Search in BST
Search in BST
1. Check if the tree is empty
If Root == NULL
Return NULL;
2. If the data of the Root matches the target number
number == Root->data
Return Root->data;
3. If the target is greater than the key of the current root, recursively call search function with the right subtree of the current root
and the target.
If number > root->data
Return search(root->right)
4. Else if the target is smaller than the key of the current root, recursively call search function with th left subtree of the current root
and the target.
If number < root->data
Return search(root->left)
5. Return NULL if the target isn't present throughout the entire tree.
Insertion in BST
In a binary search tree, the insertion operation is always carried out at the leaf node.
1. If the current node is NULL, Return a new node created with the specified value.
if node == NULL
return createNode(data)
2. If the value is less than the key of the current node, Recursively call insertNode with the left subtree of the current node and
the value.
if (data < node -> data)
node -> left = insertNode(node -> left, data)
3. If the value is greater than the key of the current node, Recursively call insertNode with the right subtree of the current node
and the value.
else if (data > node -> data)
node -> right = insertNode(node -> right, data)
55
Deletion Operation in BST
Deletion Operation in BST
AVL Tree Data Structure
● AVL Tree is invented by GM Adelson - Velsky and EM Landis in 1962. The difference between the heights of the left subtree
and the right subtree for any node is known as the balance factor of the node.
● BALANCE FACTOR = HEIGHT(LEFT SUBTREE) − HEIGHT(RIGHT SUBTREE)
● An AVL tree defined as a self-balancing Binary Search Tree where the difference between heights of left and right subtrees for
any node cannot be more than one. (-1 ,0,1)
● The time taken for all operations in a binary search tree of height h is O(h). However, it can be extended to O(n) if the BST
becomes skewed (i.e. worst case). By limiting this height to log n, AVL tree imposes an upper bound on each operation to be
O(log n) where n is the number of nodes.
1,2,4,8,16,32,
So in general
AVL Tree Data Structure
Operations on an AVL Tree
● Searching
● Traversing
● Insertion
● Deletion
Searching and traversing do not lead to the violation in property of AVL tree.
However, insertion and deletion are the operations which can violate this property and therefore,the tree can be balanced by applying
rotations.
AVL Rotations
1. Single Rotations
a. Left Rotation (RR Rotation)
b. Right Rotation (LL Rotation)
2. Double Rotations
a. Left-Right Rotation (LR Rotation)
b. Right-Left Rotation (RL Rotation)
AVL Rotations: Left Rotation
1. Left Rotation (RR Rotation): Applied when a node is inserted into the right subtree of the right child.
AVL Rotations: Right Rotation
2. Right Rotation (LL Rotation): Applied when a node is inserted into the left subtree of the left child.
AVL Rotations: Left-Right Rotation
3. Left-Right Rotation (LR Rotation): Applied when a node is inserted into the right subtree of the left child.
AVL Rotations- Right-Left Rotation
4. Right-Left Rotation (RL Rotation): Applied when a node is inserted into the left subtree of the right child.
Insertion: Construct an AVL tree having the following elements: H, I, J, B, A, E, C, F, D
1. Insert: H, I, J 2. Insert: B, A
3. Insert E
4. Insert C, F, D
AVL Delete Node
1. Deletion of a leaf node − If the node to be deleted is a leaf node, then it is deleted without any replacement as it does not
disturb the binary search tree property. However, the balance factor may get disturbed, so rotations are applied to restore it.
2. Deletion of a node with one child − If the node to be deleted has one child, replace the value in that node with the value in its
child node. Then delete the child node. If the balance factor is disturbed, rotations are applied.
3. Deletion of a node with two child nodes − If the node to be deleted has two child nodes, replace its value with the inorder
successor value. If the balance factor exceeds 1 after deletion, apply balance algorithms.
AVL Delete Node
1. Delete: 7 (Leaf Node) 2. Delete: 6 (Node with one child)
3. Delete: 2 (Node with two children) 4. Delete: 5 (no child, imbalance) Apply LL rotation
AVL Tree Data Structure
Advantages of AVL Tree:
1. AVL trees can self-balance themselves and therefore provides time complexity as O(Log n) for search, insert and delete.
2. Since it is a BST , so items can be traversed in sorted order.
3. AVL tree is relatively faster, less complex to understand and implement compared to Red Black Trees.
1. It is difficult to implement compared to normal BST and easier compared to Red Black
2. Due to its rather strict balance, AVL trees provide complicated insertion and removal operations as more rotations are
performed.
B Tree
B-trees/ Balanced Tree are a type of self-balancing tree data structure that maintains sorted data and allows for efficient insertion, deletion,
and search operations.
The B-tree is a data structure that is similar to a binary search tree, but allows multiple keys per node
B trees are specialized in m-way searching, since the order of B trees is 'm'. Order of a tree is defined as the maximum number of children a
node can accommodate. Therefore, the height of a b tree is relatively smaller than the height of AVL tree and RB tree.
● Every node in a B Tree will hold a maximum of m children and (m-1) keys, since the order of the tree is m.
● Every node in a B tree, except root and leaf, can hold at least m/2 children
● The root node must have no less than two children.
● All the leaf nodes must be at the same level.
● A B tree always maintains sorted data.
1. Case 1a: If there are more than m/2 keys in the leaf node then delete the desired key from the node.
2. Case 1b:If the leaf node doesn't contain m/2 keys then complete the keys by taking the element from right or left sibling.
a. If the left sibling contains more than m/2 elements then push its largest element up to its parent and move the intervening element
down to the node where the key is deleted.
b. If the right sibling contains more than m/2 elements then push its smallest element up to the parent and move intervening element
down to the node where the key is deleted.
3. Case 1c:If neither of the sibling contain more than m/2 elements then create a new leaf node by joining two leaf nodes and the intervening
element of the parent node.
4. Case 2: In this case, the height of the tree shrinks. If the target key lies in an internal node, and the deletion of the key leads to a fewer
number of keys in the node (i.e. less than the minimum required), then look for the inorder predecessor and the inorder successor. If both the
children contain a minimum number of keys then, borrowing cannot take place. This leads to merging the children. Again, look for the
sibling to borrow a key. But, if the sibling also has only a minimum number of keys then, merge the node with the sibling along with the
parent. Arrange the children accordingly (increasing order).
Case 1a − If the key to be deleted is in a leaf node and the deletion does not violate the minimum key
property, just delete the node.
Case 1b: If the key to be deleted is in a leaf node but the deletion violates the minimum key property, borrow
a key from either its left sibling or right sibling.
Case 1c : If the key to be deleted is in a leaf node but neither of the sibling contain more than m/2 elements then
create a new leaf node by joining two leaf nodes and the intervening element of the parent node. (Delete 53)
35
Case 2 − If the key to be deleted is in an internal node, it is replaced by a key in either left child or right child based on which child has
more keys. But if both child nodes have minimum number of keys, they’re merged together.
Case 2: In this case, the height of the tree shrinks. If the target key lies in an internal node, and the deletion of the key leads to a
fewer number of keys in the node (i.e. less than the minimum required), then look for the inorder predecessor and the inorder
successor. If both the children contain a minimum number of keys then, borrowing cannot take place. This leads to merging the
children.
Again, look for the sibling to borrow a key. But, if the sibling also has only a minimum number of keys then, merge the node with
the sibling along with the parent. Arrange the children accordingly (increasing order).
Applications of B-Trees:
● It is used in large databases to access data stored on the disk
● Searching for data in a data set can be achieved in significantly less time using the B-Tree
● Most of the servers also use the B-tree approach.
● B-Trees are also used in other areas such as natural language processing, computer networks, and cryptography.
Advantages of B-Trees:
● B-Trees have a guaranteed time complexity of O(log n) for basic operations like insertion, deletion, and searching, which makes
them suitable for large data sets and real-time applications.
● Balanced tree structure: B-trees have a balanced tree structure that maintains a logarithmic depth.
● Scalable: B-trees can scale with large datasets.
● Flexibility in node size: B-trees offer flexibility in node size.
● Sequential access: B-trees allow for sequential access and range queries because keys are kept in sorted order
Disadvantages of B-Trees:
● Slow in comparison to other data structures.
● Complex implementation: B-trees can be complex to implement.
Performance degradation with small datasets: B-trees can have performance degradation with small datasets.
● Complex balancing operations: B-trees can have complex balancing operations.
● Require more space: B-tree indexes can require more space than other types of indexes.
● Not efficient for write-heavy workloads: B-tree indexes can be slower for write-heavy workloads
Huffman Coding
The idea is to assign variable-length codes to input characters, lengths of the assigned codes are based on the frequencies of
corresponding characters.
The variable-length codes assigned to input characters are Prefix Codes, means the codes (bit sequences) are assigned in such a way that
the code assigned to one character is not the prefix of code assigned to any other character.
It is used as a component in lossless compressions such as zip, gzip, and png, and even as part of lossy compression algorithms like mp3
and jpeg.
Why Huffman’s Encoding?
1. Fixed length encodings have the advantage of random
access. But it doesn't work efficiently when the elements have
an unequal probability of occurring.
2. Variable-length encodings :
● “ABBA” = 0 1 1 0
Huffman Coding
This algorithm builds a tree in bottom up manner.
16, 45
16, 45
Step 3: Rearrange the nodes and combine min nodes
45
45
Step 4:
45
Step 5:
Steps to print codes from Huffman Tree:
Traverse the tree formed starting from the root. Maintain an auxiliary array. While moving to the left child, write 0 to the array. While moving
to the right child, write 1 to the array. Print the array when a leaf node is encountered.
character Frequency
a 5
b 9
c 12
d 13
e 16
f 45
character code-word
a 1100
b 1101
c 100
d 101
e 111
f 0
Q: string str = "abbcdbccdaabbeeebeab"
Character Frequency
a 4
b 7
c 3
d 2
e 4
Character Frequency/ Code
count
a 4 01
b 7 11
c 3 101
d 2 100
e 4 00
Decoding Huffman Code
1. Start from the left in the Huffman code, and look up each bit Character Frequency/ Code
sequence in the table. count
2. Match each code to the corresponding letter.
3. Continue until the entire Huffman code is decoded.
a 4 01
b 7 11
c 3 101
Example: 11011001100
d 2 100
babdbe
e 4 00