What are Trees?
In computer science, a tree is a widely used data structure that represents a hierarchical structure. It consists of a set of nodes connected by edges. The topmost node in a tree is called the root node, and each node in the tree can have zero or more child nodes.
The tree structure is commonly used to represent hierarchical relationships, such as organization charts, file systems, and family trees.

Properties of Trees
Trees have several important properties:
- Root: The topmost node in a tree.
- Parent: A node that has one or more child nodes.
- Child: A node directly connected to another node when moving away from the root.
- Leaf: A node with no child nodes.
- Height: The number of edges on the longest path from the root to a leaf.
- Depth: The number of edges on the path from a node to the root.
Common Types of Trees
There are various types of trees, each with its own characteristics and applications:
- Binary Tree: A tree in which each node can have at most two children.
- Binary Search Tree: A binary tree in which the left child node is less than the parent node, and the right child node is greater than the parent node.
- AVL Tree: A self-balancing binary search tree with the property that the heights of the two child subtrees of any node differ by at most one.
Understanding the properties and types of trees is essential for efficiently solving problems and implementing algorithms that involve tree structures.
Build your intuition. Fill in the missing part by typing it in.
A ___ is the topmost node in a tree.
Write the missing line below.
Binary Trees
In computer science, a binary tree is a type of tree data structure in which each node has at most two children: the left child and the right child. The left child node is typically smaller than the parent node, and the right child node is typically larger.
Binary trees have various applications in computer science, including:
- Binary Search Trees: A binary tree that is ordered or sorted, allowing for efficient search, insert, and delete operations.
- Expression Trees: A binary tree that represents an arithmetic expression, with the nodes representing operators and operands.
- Huffman Trees: A binary tree used in data compression, where the nodes represent characters and their frequencies.
Understanding binary trees and their implementation is essential for solving problems and implementing algorithms that involve hierarchical data structures.
Let's start by exploring the basic properties and operations of binary trees in C++:
1#include <iostream>
2using namespace std;
3
4// Definition for a binary tree node
5struct TreeNode {
6 int val;
7 TreeNode* left;
8 TreeNode* right;
9 TreeNode(int x) : val(x), left(NULL), right(NULL) {}
10};
11
12int main() {
13 // Replace this code with your own implementation
14 cout << "Binary Trees" << endl;
15 return 0;
16}
In the code snippet above, we define the basic structure of a binary tree node using a C++ struct. Each node has an integer value and pointers to its left and right children, initialized as NULL
.
You can replace the existing code with your own implementation to explore different binary tree operations and algorithms in C++. Happy coding!
xxxxxxxxxx
using namespace std;
int main() {
// Replace this code with your own implementation
cout << "Binary Trees" << endl;
return 0;
}
Try this exercise. Is this statement true or false?
Binary search trees are a type of binary tree where each node's left child is always smaller and its right child is always larger.
Press true if you believe the statement is correct, or false otherwise.
Tree Traversal
Tree traversal refers to the process of visiting or exploring every node of a tree data structure. It allows us to access the data stored in the tree in a specific order.
There are three main types of tree traversal techniques:
- Inorder Traversal: In this traversal, we first traverse the left subtree, then visit the root node, and finally traverse the right subtree.
- Preorder Traversal: In this traversal, we first visit the root node, then traverse the left subtree, and finally traverse the right subtree.
- Postorder Traversal: In this traversal, we first traverse the left subtree, then traverse the right subtree, and finally visit the root node.
Understanding tree traversal techniques is essential for various algorithms and operations on trees, such as searching, inserting, or deleting nodes.
Let's take a look at an example of performing an inorder traversal on a binary tree in C++:
1replace with code logic
In the code snippet above, we define a binary tree structure using a C++ struct. We then implement the inorderTraversal function to perform the inorder traversal using a stack for iterative traversal. At each node, we replace the existing code with our custom logic.
Feel free to replace the existing code with your own implementation and explore other tree traversal techniques and their applications.
xxxxxxxxxx
}
using namespace std;
// Definition for a binary tree node
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
// Function to perform inorder traversal
void inorderTraversal(TreeNode* root) {
if (!root) return;
stack<TreeNode*> s;
TreeNode* curr = root;
while (curr != NULL || !s.empty()) {
while (curr != NULL) {
s.push(curr);
curr = curr->left;
}
curr = s.top();
s.pop();
// Replace this code with your custom logic
Let's test your knowledge. Fill in the missing part by typing it in.
Tree traversal refers to the process of visiting or exploring every node of a tree data structure. It allows us to access the data stored in the tree in a specific order.
There are three main types of tree traversal techniques: 1. Inorder Traversal: In this traversal, we first traverse the left subtree, then visit the root node, and finally traverse the right subtree. 2. Preorder Traversal: In this traversal, we first visit the root node, then traverse the left subtree, and finally traverse the right subtree. 3. Postorder Traversal: In this traversal, we first traverse the left subtree, then traverse the right subtree, and finally visit the root node.
Understanding tree traversal techniques is essential for various algorithms and operations on trees, such as searching, inserting, or deleting nodes.
In the previous lesson, we saw an example of performing an inorder traversal on a binary tree.
Now, let's try a fill in the blank question:
In a preorder traversal, the order of visiting the nodes is _, then traverse the left subtree, and finally traverse the right subtree.
Please fill in the blank with the correct answer.
Write the missing line below.
Binary Search Trees
Binary Search Trees (BSTs) are a type of tree data structure that provide efficient searching and sorting operations. In a BST, each node has at most two child nodes, referred to as the left child and the right child. The key property of a BST is that the value of each node in the left subtree is less than its parent, and the value of each node in the right subtree is greater than its parent.
BSTs are commonly used to store data in sorted order, making it easy to find, insert, and delete elements from the tree.
Operations on Binary Search Trees
- Insert: Adding a new element to the tree in a way that maintains the BST property.
- Search: Finding a particular element in the tree by comparing its value with the values of the nodes.
- Delete: Removing a node from the tree while maintaining the BST property.
To better understand how BSTs work, let's take a look at an example of implementing a BST in C++.
1#include <iostream>
2using namespace std;
3
4struct Node {
5 int data;
6 Node* left;
7 Node* right;
8
9 Node(int value) {
10 data = value;
11 left = nullptr;
12 right = nullptr;
13 }
14};
15
16// Insert function to add a new node to the BST
17Node* insert(Node* root, int value) {
18 if (root == nullptr) {
19 return new Node(value);
20 }
21
22 if (value < root->data) {
23 root->left = insert(root->left, value);
24 } else if (value > root->data) {
25 root->right = insert(root->right, value);
26 }
27
28 return root;
29}
30
31int main() {
32 // Create an empty BST
33 Node* root = nullptr;
34
35 // Insert nodes into the BST
36 root = insert(root, 50);
37 root = insert(root, 30);
38 root = insert(root, 20);
39 root = insert(root, 40);
40 root = insert(root, 70);
41 root = insert(root, 60);
42 root = insert(root, 80);
43
44 // Display the BST
45 cout << "Binary Search Tree: " << root->data << endl;
46 cout << " / \\" << endl;
47 cout << " / \\" << endl;
48 cout << " / \\" << endl;
49 cout << " / \\" << endl;
50 cout << " / \\" << endl;
51 cout << " / \\" << endl;
52
53 return 0;
54}
xxxxxxxxxx
}
using namespace std;
struct Node {
int data;
Node* left;
Node* right;
Node(int value) {
data = value;
left = nullptr;
right = nullptr;
}
};
// Insert function to add a new node to the BST
Node* insert(Node* root, int value) {
if (root == nullptr) {
return new Node(value);
}
if (value < root->data) {
root->left = insert(root->left, value);
} else if (value > root->data) {
root->right = insert(root->right, value);
}
return root;
}
Try this exercise. Is this statement true or false?
Self-balancing binary search trees maintain the height of the tree to ensure efficient search, insert, and delete operations.
Press true if you believe the statement is correct, or false otherwise.
AVL Trees
AVL Trees are a type of self-balancing binary search tree, named after the inventors Adelson-Velsky and Landis. In an AVL tree, the heights of the left and right subtrees of any node differ by at most one.
The balancing property of AVL trees ensures that the tree remains balanced, providing efficient searching, insertion, and deletion operations with a time complexity of O(log n).
Balanced Tree
In an AVL tree, every node satisfies the AVL property, which states that the heights of the left and right subtrees of the node differ by at most one. If the difference exceeds one, the tree is considered unbalanced and requires balancing operations to maintain the AVL property.
Balancing Operations
There are four types of balancing operations: left rotation, right rotation, left-right rotation, and right-left rotation. These operations are performed to restore the balance of the tree when it becomes unbalanced due to insertions or deletions.
C++ Code Implementation
Here's an example of AVL tree implementation in C++:
1#include <iostream>
2using namespace std;
3
4struct Node {
5 int data;
6 Node* left;
7 Node* right;
8 int height;
9
10 Node(int value) {
11 data = value;
12 left = nullptr;
13 right = nullptr;
14 height = 1;
15 }
16};
17
18int main() {
19 // AVL tree code implementation
20
21 return 0;
22}
Are you sure you're getting this? Is this statement true or false?
AVL trees are a type of self-balancing binary search tree.
Press true if you believe the statement is correct, or false otherwise.
Heap Trees
A heap tree, or simply a heap, is a special type of binary tree that satisfies the heap property:
- For a max heap, for any given node, the value of the node is greater than or equal to the values of its children.
- For a min heap, for any given node, the value of the node is less than or equal to the values of its children.
Priority Queues and Heap Trees
Heap trees are commonly used to implement priority queues, which are abstract data types that allow for efficient insertion and removal of elements with associated priorities.
The max heap is often used to implement a max priority queue, where the element with the highest priority is always at the root of the heap. Similarly, the min heap can be used to implement a min priority queue, where the element with the lowest priority is always at the root of the heap.
Example
Let's take a look at an example of creating a max heap from an array using C++ code:
1#include <iostream>
2#include <vector>
3using namespace std;
4
5// Function to swap two elements
6void swap(int& a, int& b) {
7 int temp = a;
8 a = b;
9 b = temp;
10}
11
12// Function to max heapify the subtree with root at given index
13void maxHeapify(vector<int>& arr, int n, int i) {
14 int largest = i; // Initialize the largest element as root
15 int left = 2 * i + 1; // Left child
16 int right = 2 * i + 2; // Right child
17
18 // If left child is larger than root
19 if (left < n && arr[left] > arr[largest])
20 largest = left;
21
22 // If right child is larger than largest so far
23 if (right < n && arr[right] > arr[largest])
24 largest = right;
25
26 // If largest is not root
27 if (largest != i) {
28 swap(arr[i], arr[largest]);
29
30 // Recursively heapify the affected sub-tree
31 maxHeapify(arr, n, largest);
32 }
33}
34
35// Function to convert an array to max heap
36void buildMaxHeap(vector<int>& arr, int n) {
37 // Index of last non-leaf node
38 int startIdx = (n / 2) - 1;
39
40 // Perform max heapify on each non-leaf node
41 // From right to left
42 for (int i = startIdx; i >= 0; i--) {
43 maxHeapify(arr, n, i);
44 }
45}
46
47// Function to print an array
48void printArray(vector<int>& arr, int n) {
49 for (int i = 0; i < n; i++) {
50 cout << arr[i] << " ";
51 }
52 cout << endl;
53}
54
55int main() {
56 vector<int> arr = { 12, 11, 13, 5, 6, 7 };
57 int n = arr.size();
58
59 cout << "Original array: ";
60 printArray(arr, n);
61
62 buildMaxHeap(arr, n);
63
64 cout << "Max Heap: ";
65 printArray(arr, n);
66
67 return 0;
68}
xxxxxxxxxx
}
using namespace std;
// Function to swap two elements
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
// Function to max heapify the subtree with root at given index
void maxHeapify(vector<int>& arr, int n, int i) {
int largest = i; // Initialize the largest element as root
int left = 2 * i + 1; // Left child
int right = 2 * i + 2; // Right child
// If left child is larger than root
if (left < n && arr[left] > arr[largest])
largest = left;
// If right child is larger than largest so far
if (right < n && arr[right] > arr[largest])
largest = right;
// If largest is not root
if (largest != i) {
swap(arr[i], arr[largest]);
Build your intuition. Fill in the missing part by typing it in.
A heap tree is a special type of binary tree that satisfies the _ property.
For a max heap, for any given node, the value of the node is ___ the values of its children.
For a min heap, for any given node, the value of the node is ___ the values of its children.
A heap tree can be used to implement ___ queues.
Write the missing line below.
Generating complete for this lesson!