Skip to content

Commit

Permalink
Merge branch 'main' into dev-1
Browse files Browse the repository at this point in the history
  • Loading branch information
ajay-dhangar authored Oct 2, 2024
2 parents 59a7123 + 7036c4b commit 8eb58d1
Show file tree
Hide file tree
Showing 7 changed files with 355 additions and 4 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ We aim to:

## Website

This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator.
This website is built using [Docusaurus 3](https://docusaurus.io/), a modern static website generator.

## Installation

Expand Down
123 changes: 123 additions & 0 deletions docs/algorithms/Searching algorithms/BinarySearch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
---
id: binary-search-algo
sidebar_position: 2
title: Binary Search
sidebar_label: Binary Search
---

### Definition:

Binary search is an efficient algorithm for finding a specific element in a sorted array or list. It works by repeatedly dividing the search interval in half. If the target value is less than the middle element, the search continues in the lower half; if it's greater, the search continues in the upper half. This process continues until the target is found or the interval is empty.

### Characteristics:

- **Divides and Conquers:**
- The algorithm follows the divide-and-conquer paradigm. It breaks the problem into smaller subproblems (halves of the array) and solves them independently.

- **Sorted Data:**
- The input array must be sorted beforehand. If the array is unsorted, binary search will not work correctly.

- **Can be Implemented Recursively or Iteratively:**
- Binary search can be implemented using either a recursive function or an iterative approach.

- **No Duplicates Handling:**
- The basic binary search implementation does not handle duplicates well; it will only find one instance of the target.

### Time Complexity:
- **Best Case: O(1)**
The best-case scenario occurs when the target element is found at the middle of the array on the first check.

- **Average Case: O(logn)**
On average, binary search will cut the search space in half with each iteration. This logarithmic growth means that as the size of the dataset n increases, the number of operations grows very slowly.

- **Worst Case: O(logn)**
The worst-case scenario occurs when the target element is not present in the array. The algorithm will still narrow down the search space until it exhausts all possibilities, leading to a logarithmic number of comparisons.

### Space Complexity:
- **Iterative Approach: O(1)**
The iterative version of binary search uses a constant amount of space, as it only requires a few variables (like left, right, and mid) to keep track of indices. It does not require additional storage proportional to the size of the input.

- **Recursive Approach: O(logn)**
The recursive version of binary search uses stack space for recursive function calls. The maximum depth of the recursion is proportional to the logarithm of the number of elements in the array, leading to a space complexity of O(logn).

### C++ Implementation:

**Iterative Approach**
```cpp
#include <iostream>
using namespace std;

int binarySearchIterative(int arr[], int size, int target) {
int left = 0;
int right = size - 1;

while (left <= right) {
int mid = left + (right - left) / 2; // Prevents overflow

if (arr[mid] == target) {
return mid; // Target found
} else if (arr[mid] < target) {
left = mid + 1; // Search in the right half
} else {
right = mid - 1; // Search in the left half
}
}
return -1; // Target not found
}

int main() {
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // Sorted array
int size = sizeof(arr) / sizeof(arr[0]);
int target = 7;

int result = binarySearchIterative(arr, size, target);

if (result != -1) {
cout << "Element found at index: " << result << endl;
} else {
cout << "Element not found." << endl;
}

return 0;
}

```
**Recursive Approach**
```cpp
#include <iostream>
using namespace std;
int binarySearchRecursive(int arr[], int left, int right, int target) {
if (left > right) {
return -1; // Base case: target not found
}
int mid = left + (right - left) / 2; // Prevents overflow
if (arr[mid] == target) {
return mid; // Target found
} else if (arr[mid] < target) {
return binarySearchRecursive(arr, mid + 1, right, target); // Search in the right half
} else {
return binarySearchRecursive(arr, left, mid - 1, target); // Search in the left half
}
}
int main() {
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // Sorted array
int size = sizeof(arr) / sizeof(arr[0]);
int target = 7;
int result = binarySearchRecursive(arr, 0, size - 1, target);
if (result != -1) {
cout << "Element found at index: " << result << endl;
} else {
cout << "Element not found." << endl;
}
return 0;
}
```
76 changes: 76 additions & 0 deletions docs/algorithms/Searching algorithms/LinearSearch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
---
id: linear-search-algo
sidebar_position: 1
title: Linear Search
sidebar_label: Linear Search
---

### Definition:

A linear search algorithm is a simple method for finding a specific element in a list or array. It works by sequentially checking each element until the desired element is found or the end of the list is reached.

### Characteristics:

- **Simplicity:**
- The algorithm is easy to understand and implement. It requires minimal code and logic, making it accessible for beginners.

- **No Sorting Required:**
- Linear search can be performed on unsorted arrays or lists. This makes it versatile since it doesn't need any preprocessing of the data.

- **Multiple Occurrences:**
- If multiple occurrences of the target value exist in the list, the linear search will return the index of the first occurrence. It can be modified to find all occurrences if needed.

- **Best for Small Datasets:**
- Linear search is efficient for small to medium-sized datasets. As the dataset grows, its inefficiency becomes more pronounced compared to more advanced search algorithms.

### Linear Search Algorithm:

**Steps:**
1. Start at the beginning of the list.
2. Check each element in the list one by one:
- If the current element matches the target value, return the index of that element.
- If it does not match, move to the next element.
3. If the end of the list is reached and no match is found, return a value indicating that the target is not in the list (e.g., -1).

### Time Complexity:

- **Worst-case: O(n)**
- This occurs when the target element is not present or is at the last position.

- **Best-case: O(1)**
- This occurs when the target element is the first element in the list.

The space complexity of the linear search algorithm is O(1), which means it uses a constant amount of additional space regardless of the input size.

### C++ Implementation:

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

int linearSearch(int arr[], int size, int target) {
for (int index = 0; index < size; index++) {
if (arr[index] == target) {
return index; // Return the index if the target is found
}
}
return -1; // Return -1 if the target is not found
}

int main() {
int arr[] = {5, 3, 8, 4, 2};
int size = sizeof(arr) / sizeof(arr[0]);
int target = 4;

int result = linearSearch(arr, size, target);

if (result != -1) {
cout << "Element found at index: " << result << endl;
} else {
cout << "Element not found." << endl;
}

return 0;
}

```
8 changes: 8 additions & 0 deletions docs/algorithms/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"label": "Algoritms",
"position": 4,
"link": {
"type": "generated-index",
"description": "5 minutes to learn the most important algorithms."
}
}
2 changes: 1 addition & 1 deletion docs/arrays/2d-arrays.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,4 @@ Write a program to multiply two matrices of dimensions `m x n` and `n x p`.

## Conclusion

Two-dimensional arrays are a foundational data structure in computer science, used in a variety of real-world applications, including graph theory, dynamic programming, and game development. By understanding how to declare, traverse, and manipulate 2D arrays, you can effectively solve complex problems in DSA.
Two-dimensional arrays are a foundational data structure in computer science, used in a variety of real-world applications, including graph theory, dynamic programming, and game development. By understanding how to declare, traverse, and manipulate 2D arrays, you can effectively solve complex problems in DSA.
144 changes: 144 additions & 0 deletions docs/data-structures/shortest_path_algo/shortestpath.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
---
id: shortest-path-algorithm
title: Shortest Path Algorithm (Dijkstra's Algorithm)
sidebar_label: Dijkstra's Algorithm
tags:
- Graph
- Greedy
- Algorithm
- Shortest Path
description: Given a graph represented by nodes and weighted edges, find the shortest path from a given source node to all other nodes using Dijkstra's Algorithm.
---

## Problem Statement

Given a graph with `n` nodes and weighted edges, the task is to find the shortest path from a given source node to all other nodes using Dijkstra's algorithm.

### Examples

*Example 1:*

```plaintext
Input:
Number of vertices: 5
Edges: {(0, 1, 2), (0, 4, 8), (1, 2, 3), (1, 3, 5), (2, 3, 1), (4, 3, 4)}
Source: 0
Output: [0, 2, 5, 6, 8]
Explanation:
The shortest path from node 0 to node 3 is 6.
```

*Example 2:*
```plaintext
Input:
Number of vertices: 3
Edges: {(0, 1, 1), (1, 2, 2), (0, 2, 4)}
Source: 0
Output: [0, 1, 3]
Explanation:
The shortest path from node 0 to node 2 is 3.
```

### Constraints
```plaintext
1 <= number of vertices <= 1000
1 <= weight of edges <= 100
```
### Solution
Dijkstra’s algorithm is a well-known greedy algorithm used to find the shortest path between nodes in a graph, which can either be directed or undirected. The algorithm works by maintaining a set of nodes whose shortest path distance from the source is known. It picks the closest unvisited node, calculates its distance through its neighbors, and updates the shortest paths accordingly.

## Approach: Dijkstra's Algorithm
### Algorithm
1) Create a priority queue (min-heap) to store nodes and their minimum distance from the source node.
2)
Initialize the distance of all nodes to infinity, except the source node which is set to 0.
3) While the priority queue is not empty:
- Extract the node with the minimum distance from the queue.
- For each neighboring node, calculate the distance via the current node and update the neighbor’s distance
4) if it's smaller than the previously known distance.
Repeat until all nodes have been processed or the queue is empty.
### Implementation

```cpp
#include <iostream>
#include <vector>
#include <queue>
#include <climits>

using namespace std;

typedef pair<int, int> pii; // {distance, node}

vector<int> dijkstra(int V, vector<vector<pii>>& adj, int source) {
// Create a distance vector, initialized to infinity
vector<int> dist(V, INT_MAX);

// Min-heap priority queue to store {distance, node}
priority_queue<pii, vector<pii>, greater<pii>> pq;

// Set the distance of the source to 0 and add it to the queue
dist[source] = 0;
pq.push({0, source});

while (!pq.empty()) {
int currentDist = pq.top().first;
int currentNode = pq.top().second;
pq.pop();

// If this distance is already larger than the known shortest, skip
if (currentDist > dist[currentNode]) {
continue;
}

// Process each neighbor
for (auto& neighbor : adj[currentNode]) {
int nextNode = neighbor.first;
int weight = neighbor.second;

// Calculate new potential distance
int newDist = currentDist + weight;

// If the new distance is shorter, update and push to queue
if (newDist < dist[nextNode]) {
dist[nextNode] = newDist;
pq.push({newDist, nextNode});
}
}
}

return dist;
}

int main() {
int V = 5;
vector<vector<pii>> adj(V);

// Adding edges (node1, node2, weight)
adj[0].push_back({1, 2});
adj[0].push_back({4, 8});
adj[1].push_back({2, 3});
adj[1].push_back({3, 5});
adj[2].push_back({3, 1});
adj[4].push_back({3, 4});

int source = 0;
vector<int> shortestPaths = dijkstra(V, adj, source);

cout << "Shortest distances from node " << source << ": ";
for (int dist : shortestPaths) {
cout << dist << " ";
}

return 0;
}
```
## Complexity Analysis
- **Time complexity:** `$O((V + E) \log V)$`, where `V` is the number of vertices and `E` is the number of edges.
- Inserting and extracting from the priority queue takes `$O(\log V)$`, and each - edge is processed at most once.
- **Space complexity**: `$O(V + E)$` for the adjacency list and the distance array.
## Conclusion
Dijkstra’s algorithm efficiently finds the shortest path from a source node to all other nodes in a graph. The algorithm works best with non-negative weights, and its performance can be optimized using min-heaps or priority queues.
4 changes: 2 additions & 2 deletions src/components/Homepage/HeroSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const HeroSection: React.FC = () => {
{/* Call to Action Buttons */}
<div className="flex flex-col md:flex-row items-center justify-center space-y-4 md:space-y-0 md:space-x-6">
<a
href="#explore"
href="/algo/docs/"
className="px-6 py-3 text-lg font-medium text-white bg-blue-600 hover:bg-blue-700 rounded-lg transition duration-300 ease-in-out"
>
Explore Algorithms
Expand All @@ -41,4 +41,4 @@ const HeroSection: React.FC = () => {
);
};

export default HeroSection;
export default HeroSection;

0 comments on commit 8eb58d1

Please sign in to comment.