Skip to content

Commit

Permalink
Merge pull request #43 from pavitraag/main
Browse files Browse the repository at this point in the history
Added sorting and recursive algorithms
  • Loading branch information
ajay-dhangar authored Oct 4, 2024
2 parents f00d967 + adcbb0b commit 8548f4e
Show file tree
Hide file tree
Showing 7 changed files with 1,104 additions and 0 deletions.
168 changes: 168 additions & 0 deletions docs/algorithms/Recursive Algorithms/DirectRecursion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
---
id: direct-recursion-algo
sidebar_position: 1
title: Direct Recursion
sidebar_label: Direct Recursion
---

### Definition:

Direct recursion is when a function calls itself directly. The function keeps calling itself with a modified argument until a base case is met, which stops the recursion. Direct recursion is used to solve problems that can be broken down into smaller, similar subproblems.

### Characteristics:

- **Self-Calling Function:**
- A function is directly recursive if it calls itself within its own body.

- **Base Case:**
- A base case is required to stop the recursive calls, preventing infinite recursion.

- **Multiple Calls:**
- The function may call itself once or multiple times depending on the problem.

### Time Complexity:

- **Time Complexity: O(n)**
The time complexity of direct recursion depends on the problem. For simple problems like calculating a factorial, it usually takes linear time `O(n)` where `n` is the input size.

### Space Complexity:

- **Space Complexity: O(n)**
Each recursive call takes up space on the call stack, leading to a space complexity proportional to the depth of the recursion.

### Example Problems:

1. **Factorial Function:**

The factorial of a number `n` is defined as `n! = n * (n-1) * (n-2) * ... * 1`. We can calculate the factorial using direct recursion.

```cpp
#include <iostream>
using namespace std;

int factorial(int n) {
if (n <= 1) return 1; // Base case
return n * factorial(n - 1); // Recursive call
}

int main() {
int num = 5;
cout << "Factorial of " << num << " is " << factorial(num) << endl;
return 0;
}
```
- In this example, the function `factorial()` calls itself until `n` becomes 1, which is the base case.
2. **Sum of First N Natural Numbers:**
We can use direct recursion to find the sum of the first `n` natural numbers.
```cpp
#include <iostream>
using namespace std;
int sum(int n) {
if (n == 0) return 0; // Base case
return n + sum(n - 1); // Recursive call
}
int main() {
int n = 10;
cout << "Sum of first " << n << " natural numbers is " << sum(n) << endl;
return 0;
}
```

- In this example, the function `sum()` calls itself, reducing the value of `n` by 1 at each step until it reaches 0, the base case.

3. **Fibonacci Sequence:**

The Fibonacci sequence is a series where each number is the sum of the two preceding ones, starting with 0 and 1. We can compute the nth Fibonacci number using direct recursion.

```cpp
#include <iostream>
using namespace std;

int fibonacci(int n) {
if (n <= 1) return n; // Base cases
return fibonacci(n - 1) + fibonacci(n - 2); // Recursive calls
}

int main() {
int n = 5;
cout << "Fibonacci of " << n << " is " << fibonacci(n) << endl;
return 0;
}
```
- Here, the function `fibonacci()` calls itself twice to compute the Fibonacci numbers for `n-1` and `n-2`.
### Recursive Tree:
Direct recursion often generates a recursion tree, where each function call spawns new calls, visualizing the branching structure of recursive calls.
### Common Applications:
- Factorial calculation
- Fibonacci sequence
- Tower of Hanoi
- Sum of a series
- Tree traversal
### C++ Implementation:
**Factorial Example (Direct Recursion)**
```cpp
#include <iostream>
using namespace std;
int factorial(int n) {
if (n <= 1) return 1; // Base case
return n * factorial(n - 1); // Recursive call
}
int main() {
int num = 5;
cout << "Factorial of " << num << " is " << factorial(num) << endl;
return 0;
}
```

**Sum of First N Natural Numbers (Direct Recursion)**
```cpp
#include <iostream>
using namespace std;

int sum(int n) {
if (n == 0) return 0; // Base case
return n + sum(n - 1); // Recursive call
}

int main() {
int n = 10;
cout << "Sum of first " << n << " natural numbers is " << sum(n) << endl;
return 0;
}
```
**Fibonacci Example (Direct Recursion)**
```cpp
#include <iostream>
using namespace std;
int fibonacci(int n) {
if (n <= 1) return n; // Base case
return fibonacci(n - 1) + fibonacci(n - 2); // Recursive call
}
int main() {
int n = 5;
cout << "Fibonacci of " << n << " is " << fibonacci(n) << endl;
return 0;
}
```

### Summary:

Direct recursion is a simple yet powerful tool for solving problems that involve repetitive or self-similar subproblems. The key challenge lies in identifying the base case to prevent infinite recursion and understanding the problem well enough to break it down recursively.
184 changes: 184 additions & 0 deletions docs/algorithms/Recursive Algorithms/IndirectRecursion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
---
id: indirect-recursion-algo
sidebar_position: 2
title: Indirect Recursion
sidebar_label: Indirect Recursion
---

### Definition:

Indirect recursion occurs when a function calls another function, and eventually, the second function calls the first function back. This process forms a cycle of function calls between two or more functions, instead of a single function calling itself directly.

### Characteristics:

- **Mutual Call:**
- In indirect recursion, two or more functions call each other in a cyclic manner.

- **Base Case:**
- Each recursive cycle must include a base case to prevent infinite loops and ensure termination.

- **Multiple Functions:**
- Indirect recursion involves more than one function. A function calls another, which in turn calls the first one back.

### Time Complexity:

- **Time Complexity: O(n)**
- The time complexity of indirect recursion depends on the number of recursive calls. For simple problems, it is typically linear `O(n)`.

### Space Complexity:

- **Space Complexity: O(n)**
- Each recursive call uses stack space, leading to a space complexity proportional to the depth of the recursion.

### Example Problems:

1. **Odd and Even Numbers:**

In this example, we use two functions: one for checking even numbers and another for odd numbers. The function `isEven()` calls `isOdd()`, and `isOdd()` calls `isEven()` until the base case is reached.

```cpp
#include <iostream>
using namespace std;

bool isEven(int n);
bool isOdd(int n);

bool isEven(int n) {
if (n == 0) return true; // Base case
return isOdd(n - 1); // Call isOdd
}

bool isOdd(int n) {
if (n == 0) return false; // Base case
return isEven(n - 1); // Call isEven
}

int main() {
int num = 5;
if (isEven(num)) {
cout << num << " is even." << endl;
} else {
cout << num << " is odd." << endl;
}
return 0;
}
```
- Here, `isEven()` calls `isOdd()`, and `isOdd()` calls `isEven()`. This continues until the base case is met.
2. **Mutually Recursive Functions:**
Another classic example of indirect recursion is mutually recursive functions, where one function calls another, and the second function calls the first function back in a loop.
```cpp
#include <iostream>
using namespace std;
void functionA(int n);
void functionB(int n);
void functionA(int n) {
if (n > 0) {
cout << "In Function A: " << n << endl;
functionB(n - 1); // Call functionB
}
}
void functionB(int n) {
if (n > 0) {
cout << "In Function B: " << n << endl;
functionA(n / 2); // Call functionA
}
}
int main() {
int num = 10;
functionA(num); // Start the recursion chain
return 0;
}
```

- In this example, `functionA()` calls `functionB()`, and `functionB()` calls `functionA()`. The base case for each function ensures termination.

### Recursive Tree:

Just like direct recursion, indirect recursion forms a recursion tree. However, the branches of this tree involve multiple functions that call each other in cycles. Each function call is part of a chain, leading back to earlier calls.

### Applications:

Indirect recursion is often used in:
- State machines
- Parsing algorithms
- Handling mutually exclusive conditions (like odd/even checks)

### Common Challenges:

- **Tracking Function Calls:**
- Indirect recursion can be more challenging to understand and debug because multiple functions are involved, and keeping track of the flow of execution can be complex.

- **Base Case Design:**
- Designing appropriate base cases for each function in the recursion cycle is crucial to ensure that the recursion terminates.

### C++ Implementation:

**Odd and Even Checker (Indirect Recursion)**
```cpp
#include <iostream>
using namespace std;

bool isEven(int n);
bool isOdd(int n);

bool isEven(int n) {
if (n == 0) return true; // Base case
return isOdd(n - 1); // Call isOdd
}

bool isOdd(int n) {
if (n == 0) return false; // Base case
return isEven(n - 1); // Call isEven
}

int main() {
int num = 5;
if (isEven(num)) {
cout << num << " is even." << endl;
} else {
cout << num << " is odd." << endl;
}
return 0;
}
```
**Mutually Recursive Functions (Indirect Recursion)**
```cpp
#include <iostream>
using namespace std;
void functionA(int n);
void functionB(int n);
void functionA(int n) {
if (n > 0) {
cout << "In Function A: " << n << endl;
functionB(n - 1); // Call functionB
}
}
void functionB(int n) {
if (n > 0) {
cout << "In Function B: " << n << endl;
functionA(n / 2); // Call functionA
}
}
int main() {
int num = 10;
functionA(num); // Start the recursion chain
return 0;
}
```

### Summary:

Indirect recursion occurs when two or more functions call each other in a cycle. It's an important concept in recursive algorithms, but it can be harder to follow due to the involvement of multiple functions. The base cases for each function in the cycle must be carefully designed to ensure the recursion terminates.
Loading

0 comments on commit 8548f4e

Please sign in to comment.