Skip to content

Commit

Permalink
Trees 🌳 (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
Rishabh672003 authored Oct 29, 2023
2 parents 95f173d + a3e77ae commit 457b72e
Show file tree
Hide file tree
Showing 13 changed files with 728 additions and 0 deletions.
33 changes: 33 additions & 0 deletions Data-Structures/Trees/01-intro.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
## Tress - A hierarchical Data Struture

Trees are hierarchical data structures consisting of nodes.

A tree consits of root node, parent nodes, children nodes, leaf-nodes, sub-tree and ancestors.

```
1 <-- root node
/ \
2 3 <-- Child node
/ \ / \
4 5 6 7
/ / \
8 9 10 <-- Leaf node
```

---

### Binary Search Tree

A Binary tree is a type of tree where each parent node consists of at **max 2** child nodes.

**Types of Binary tree :**

1. **Fully Binary tree :** Every node will either have 0 or 2 children nodes.

2. **Complete Binary Tree :** All levels of tree should be completely filled. If not completely filled, then the last level should have all nodes as left as possible.

3. **Perfect Binary Tree :** All leaf nodes are at same level.

4. **Blnced Binary Tree :** The tree can at max have a height of **Log<sub>2</sub>(n)**, where n is number of nodes.

5. **Degenerate Tree :** When every node only have a single child or parent node. This type resembles to a Linked List.
39 changes: 39 additions & 0 deletions Data-Structures/Trees/02-basics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
## Representation of a Tree in C++

```
1 <-- data
left pointer --> / \ <-- right pointer
2 3
/ \
4 NULL
```

---

### Implementation :

```cpp
struct Node {
int data;
struct Node *left;
struct Node *right;
// constructor
Node(int value){
data = value;
left = right = NULL; // initially pointing to null
}
}

// Tree Creation
int main() {
// calling constructor and passing root's value.
struct Node *root = new Node(1);

root->left = new Node(2);
root->right = new Node(3);

root->left->left = new Node(4);

return 0;
}
```
66 changes: 66 additions & 0 deletions Data-Structures/Trees/03-travsersals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
## Traversing in a Tree

There are two ways to traverse in a Binary search tree :

1. **Depth-First-Search [DFS] :**
In this method, the tree is traversed through it's entire height / length.

There are 3 types of DFS :-

a. _In-order Traversal_ (left-**root**-right) : Start form the root, if there exists a left, go left, if no further left, print left, go back, print the root and now look for right, if right exists, apply the same logic.

```
1
/ \
2 3
/ \ / \
4 5 6 7
/ / \
8 9 10
```

In above BST, if we apply In-order traversal, we get :

```
4 2 8 5 1 6 3 9 7 10
```

---

b. _Pre-Order-Traversal_ (**root**-left-right) : Start from the root, print root, if left exists, go left & print left, if no further left, go back, check for right, if right exists, apply the same logic.

In above BST, if we apply Pre-order traversal, we get :

```
1 2 4 5 8 3 6 7 9 10
```

---

c. _Post-Order-Traversal_ (left-right-**root**) : Start from the root, if left exists, go to left, print left, if no further left, go back, check if right exists, if exists print right, go back and print root.

In above BST, if we apply Pre-order traversal, we get :

```
4 5 8 2 6 7 9 10 7 3 1
```

---

2. **Breadth-first-Search [BFS] :** In this method, we traverse the tree level by level, through it's entire breadth.

```
--> 1
/ \
--> 2 3
/ \ / \
--> 4 5 6 7
/ / \
--> 8 9 10
```

**BFS in Above Tree :**

```
1 2 3 4 5 6 7 8 9 10
```
26 changes: 26 additions & 0 deletions Data-Structures/Trees/04-in-order-recur.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
## In-Order-Traversal ~ Recursive approach C++ Implementation

```
1
/ \
2 3
/ \ / \
4 5 6 7
/ / \
8 9 10
```

### Implemantation :

```cpp
void inorder(int node){
if (node == NULL) { // base case
return;
}
inorder(node->left); // recursion
cout << node->data << endl;
inorder(node->right); // recursion
}
```
pattern : left --> print --> right
26 changes: 26 additions & 0 deletions Data-Structures/Trees/05-pre-order-recur.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
## Pre-Order-Traversal ~ Recursive approach C++ Implementation

```
1
/ \
2 3
/ \ / \
4 5 6 7
/ / \
8 9 10
```

### Implemantation :

```cpp
void preorder(int node){
if (node == NULL) { // base case
return;
}
cout << node->data << endl;
preorder(node->left); // recursion
preorder(node->right); // recursion
}
```
pattern : print --> left --> right
26 changes: 26 additions & 0 deletions Data-Structures/Trees/06-post-order-recur.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
## Post-Order-Traversal ~ Recursive approach C++ Implementation

```
1
/ \
2 3
/ \ / \
4 5 6 7
/ / \
8 9 10
```

### Implemantation :

```cpp
void postorder(int node){
if (node == NULL) { // base case
return;
}
postorder(node->left); // recursion
postorder(node->right); // recursion
cout << node->data << endl;
}
```
pattern : left --> right --> print
148 changes: 148 additions & 0 deletions Data-Structures/Trees/07-level-order.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
## Level Order Traversal [BFS] C++ Implementation

==> We'll need two data sructures, A queue and a vector of vectors.

--> The Queue will hold the roots of tree.

--> vector will hold the levels

Step 1 : Push the root node of the tree to the queue.

Step 2: Check if there exists any left or right branch for that node.

Step 3: If there exists any left or right, push them to queue.

Step 4: Once performed Step 2 & 3 for a node, push that node into the vector.

Step 5 : Now iterate over the next queue elements and take them out, and repeat from Step 2. Check for their left and right, push their left / right to the queue and finally push the previous queue elements into the vector

---

Example :

```
--> 1
/ \
--> 2 3
/ \ / \
--> 4 5 6 7
```

Step 1 :

The queue becomes :

```
1
```

Step 2, Step 3 : Root node 1 has child nodes 2 and 3 as it's left and right, so push them to the queue.

The queue becomes :

```
1 2 3
```

Step 4 :

Push Root node 1 into the vector.

The vector becomes :

```
1
```

Step 5 :

Once we've performed these operations for Node 1, take child node 2 and 3 out of the queue and check if they have any left / right child nodes.

2 and 3 have 4 5 6 7 as their child nodes, push them to the queue.

The queue becomes :

```
1 2 3 4 5 6 7
```

Now Push the child nodes 2 & 3 into the vector.

The vector becomes :

```
1, 2 3
```

Once we've performed these operations for Child nodes 2 & 3, take child node 4, 5, 6 and 7 out of the queue and check if they have any left / right child nodes.

4 5 6 7 doesn't have any child nodes to push into the queue, so push them to the vector

The vector becomes :

```
1, 2 3, 4 5 6 7
```

**So the Level order traversal prints `1 2 3 4 5 6 7`**

---

![Visualization](https://github.com/Rishabh672003/Programming-Notes/assets/53911515/596d45d5-7510-4b23-946b-215811a55ab0)

---

### Approach :

- Declare a vector of vectors (ans).
- if root == NULL, return ans.
- declare a queue, push the root into it.
- while the queue is not empty,
- calculate it's size to traverse.
- declare a vector to store levels (levels).
- traverse the current nodes inside the queue.
- declare a node and initialize it to q.front().
- pop the node out of the queue and check if it's left and right exists.
- If exists, push them to queue
- push the node's value into the (level) vector.
- push the (level) vector to (ans) vector.

---

### Implementation :

```cpp
/* Defination for binary tree :
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode() : val(x), left(nullptr), right(nullptr) {}
TreeNode(int x): val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode *left, TreeNode *right): val(x), left(left), right(right) {}
}
*/

class Solution {
public:
vector<vector<int>> levelOrder(TreeNode *root){
vector<vector<int>> ans; // vector of vector
if (root == NULL) return ans;
queue<TreeNode*> q; // queue
q.push(root);
while(!q.empty()){
int size = q.size();
vector<int> level;
for (int i = 0; i < size; i++){
TreeNode *node = q.front();
q.pop();
if (node->left != NULL) q.push(node->left);
if (node->right != NULL) q.push(node->right);
level.push_back(node->value);
}
ans.push_back(level);
}
return ans;
}
};
```
Loading

0 comments on commit 457b72e

Please sign in to comment.