-
Notifications
You must be signed in to change notification settings - Fork 275
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ed88315
commit 0dbb276
Showing
6 changed files
with
431 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
# Merge Sort Algorithm | ||
|
||
## **Merge Sort** | ||
|
||
### **Input** | ||
An unsorted array `A` of size `n`. | ||
|
||
### **Output** | ||
A sorted array `A` in ascending order. | ||
|
||
--- | ||
|
||
## **Algorithm Description** | ||
|
||
1. **Base Case** | ||
- If the size of the array `A` is 1 or less, it is already sorted. Return the array. | ||
|
||
2. **Divide Step** | ||
- Find the middle index `mid` of the array: | ||
$ \text{mid} = \text{start} + \frac{\text{end} - \text{start}}{2} $. | ||
- Split the array `A` into two subarrays: | ||
- Left subarray: `A[start...mid]` | ||
- Right subarray: `A[mid+1...end]`. | ||
|
||
3. **Conquer Step** | ||
- Recursively apply Merge Sort on the left subarray `A[start...mid]`. | ||
- Recursively apply Merge Sort on the right subarray `A[mid+1...end]`. | ||
|
||
4. **Merge Step** | ||
- Merge the two sorted subarrays `A[start...mid]` and `A[mid+1...end]` into a single sorted array. | ||
- Compare elements from both subarrays. | ||
- Place the smaller element into the result array and move the pointer of the corresponding subarray. | ||
- Repeat this process until all elements are merged. | ||
- If one subarray is exhausted, append the remaining elements from the other subarray to the result. | ||
|
||
5. **Return Step** | ||
- Once all recursive calls are complete and merging is done, the entire array `A` will be sorted. | ||
|
||
--- | ||
|
||
## **Time Complexity** | ||
|
||
- **Best Case**: \(O(n \log n)\) | ||
This occurs when the array is already sorted but still requires dividing and merging steps. | ||
|
||
- **Average Case**: \(O(n \log n)\) | ||
Most inputs result in balanced divisions and regular merging. | ||
|
||
- **Worst Case**: \(O(n \log n)\) | ||
Even in the worst-case scenario, all divisions and merging steps require consistent work. | ||
|
||
--- | ||
|
||
## **Space Complexity** | ||
|
||
- **Auxiliary Space**: \(O(n)\) | ||
Merge Sort requires extra memory to store temporary arrays during the merging step. | ||
|
||
--- | ||
|
||
## **Example Walkthrough** | ||
|
||
### Input Array: | ||
`[38, 27, 43, 3, 9, 82, 10]` | ||
|
||
### Step-by-Step Process: | ||
|
||
1. **Initial Split**: | ||
- Divide `[38, 27, 43, 3, 9, 82, 10]` into `[38, 27, 43]` and `[3, 9, 82, 10]`. | ||
|
||
2. **Recursive Splitting**: | ||
- `[38, 27, 43]` becomes `[38]`, `[27]`, and `[43]`. | ||
- `[3, 9, 82, 10]` becomes `[3]`, `[9]`, `[82]`, `[10]`. | ||
|
||
3. **Merging Subarrays**: | ||
- Merge `[38]` and `[27]` into `[27, 38]`. | ||
- Merge `[27, 38]` with `[43]` into `[27, 38, 43]`. | ||
- Similarly, merge `[3]`, `[9]`, `[82]`, `[10]` into `[3, 9, 10, 82]`. | ||
|
||
4. **Final Merge**: | ||
- Merge `[27, 38, 43]` with `[3, 9, 10, 82]` into `[3, 9, 10, 27, 38, 43, 82]`. | ||
|
||
### Output: | ||
`[3, 9, 10, 27, 38, 43, 82]` | ||
|
||
--- | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
def merge_sort(arr): | ||
""" | ||
Function to perform Merge Sort on a given list. | ||
Args: | ||
arr (list): Unsorted list to be sorted. | ||
Returns: | ||
list: Sorted list in ascending order. | ||
""" | ||
if len(arr) > 1: | ||
# Finding the middle of the array to divide it | ||
mid = len(arr) // 2 | ||
|
||
# Dividing the array into two halves | ||
left_half = arr[:mid] | ||
right_half = arr[mid:] | ||
|
||
# Recursively sorting both halves | ||
merge_sort(left_half) | ||
merge_sort(right_half) | ||
|
||
# Initializing pointers for left, right, and the merged array | ||
i = j = k = 0 | ||
|
||
# Merging the two sorted halves into a single sorted array | ||
while i < len(left_half) and j < len(right_half): | ||
if left_half[i] < right_half[j]: | ||
arr[k] = left_half[i] | ||
i += 1 | ||
else: | ||
arr[k] = right_half[j] | ||
j += 1 | ||
k += 1 | ||
|
||
# Checking if any element remains in left_half | ||
while i < len(left_half): | ||
arr[k] = left_half[i] | ||
i += 1 | ||
k += 1 | ||
|
||
# Checking if any element remains in right_half | ||
while j < len(right_half): | ||
arr[k] = right_half[j] | ||
j += 1 | ||
k += 1 | ||
|
||
return arr | ||
|
||
# Example usage: | ||
if __name__ == "__main__": | ||
example_arr = [38, 27, 43, 3, 9, 82, 10] | ||
print("Original Array:", example_arr) | ||
sorted_arr = merge_sort(example_arr) | ||
print("Sorted Array:", sorted_arr) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
# Merge Sort Algorithm Documentation | ||
|
||
## <u>Introduction</u> | ||
|
||
Merge Sort is a classic, comparison-based sorting algorithm that uses the **divide-and-conquer** paradigm. It divides the input array into smaller subarrays, recursively sorts those subarrays, and then merges them back together to form the final sorted array. Known for its stability and predictable performance, Merge Sort is an essential tool in many computational applications. | ||
|
||
--- | ||
|
||
## <u>Core Concept</u> | ||
|
||
The core principle of Merge Sort involves breaking the problem into smaller, manageable parts: | ||
1. **Divide**: The input array is divided into two halves until subarrays of size 1 are achieved. | ||
2. **Conquer**: Each subarray is sorted recursively. | ||
3. **Merge**: The sorted subarrays are merged into a single sorted array. | ||
|
||
This approach ensures that sorting is both systematic and efficient. | ||
|
||
--- | ||
|
||
## <u>Advantages</u> | ||
|
||
1. **Stability**: Merge Sort preserves the relative order of elements with equal keys. | ||
2. **Predictable Performance**: Its time complexity is consistent, making it suitable for large datasets. | ||
3. **Well-Suited for Linked Lists**: Unlike Quick Sort, Merge Sort is ideal for sorting linked lists as it doesn’t rely on random access. | ||
|
||
--- | ||
|
||
## <u>Limitations</u> | ||
|
||
1. **Space Complexity**: Requires additional memory for temporary arrays during the merging process. | ||
2. **Slower for Small Arrays**: Merge Sort’s overhead can make it less efficient than simpler algorithms like Insertion Sort for small datasets. | ||
|
||
--- | ||
|
||
## <u>Performance</u> | ||
|
||
### **Time Complexity** | ||
- **Best Case**: \(O(n \log n)\) | ||
- **Average Case**: \(O(n \log n)\) | ||
- **Worst Case**: \(O(n \log n)\) | ||
|
||
### **Space Complexity** | ||
- Merge Sort requires \(O(n)\) additional memory for temporary arrays, making it less memory-efficient compared to in-place sorting algorithms like Quick Sort. | ||
|
||
--- | ||
|
||
## <u>How It Works</u> | ||
|
||
### Example Walkthrough | ||
|
||
#### Input Array: `[38, 27, 43, 3, 9, 82, 10]` | ||
|
||
1. **Step 1: Divide** | ||
- Split the array into two halves: `[38, 27, 43]` and `[3, 9, 82, 10]`. | ||
|
||
2. **Step 2: Recursively Divide** | ||
- `[38, 27, 43]` becomes `[38]`, `[27]`, `[43]`. | ||
- `[3, 9, 82, 10]` becomes `[3]`, `[9]`, `[82]`, `[10]`. | ||
|
||
3. **Step 3: Merge** | ||
- Merge `[38]` and `[27]` into `[27, 38]`. | ||
- Merge `[27, 38]` with `[43]` into `[27, 38, 43]`. | ||
- Similarly, merge the second half `[3]`, `[9]`, `[82]`, `[10]` into `[3, 9, 10, 82]`. | ||
- Finally, merge `[27, 38, 43]` and `[3, 9, 10, 82]` into `[3, 9, 10, 27, 38, 43, 82]`. | ||
|
||
#### Output: `[3, 9, 10, 27, 38, 43, 82]` | ||
|
||
--- | ||
|
||
## <u>Comparison with Other Sorting Algorithms</u> | ||
|
||
1. **Quick Sort**: While Quick Sort is faster for in-place sorting, Merge Sort guarantees \(O(n \log n)\) performance, even in the worst case. | ||
2. **Heap Sort**: Merge Sort is more stable and predictable but uses more memory compared to the in-place nature of Heap Sort. | ||
3. **Insertion Sort**: For smaller datasets, Insertion Sort can outperform Merge Sort due to its lower overhead. | ||
|
||
--- | ||
|
||
## <u>Applications</u> | ||
|
||
1. **Sorting Linked Lists**: Merge Sort is well-suited for linked lists, as it doesn’t require random access. | ||
2. **External Sorting**: Ideal for large datasets stored in external memory, where limited RAM necessitates efficient merging techniques. | ||
|
||
--- | ||
|
||
## <u>Optimization Techniques</u> | ||
|
||
1. **Hybrid Sorting**: For smaller subarrays (e.g., size < 10), switch to a simpler algorithm like Insertion Sort to reduce overhead. | ||
2. **In-Place Merge Sort**: While challenging to implement, in-place techniques reduce additional memory requirements. | ||
|
||
--- | ||
|
||
## <u>Real-World Example</u> | ||
|
||
Consider an e-commerce platform that processes millions of transactions daily. To analyze trends, these transactions must be sorted by date or value. Merge Sort is ideal here due to its stability and consistent time complexity, even for large datasets. | ||
|
||
--- | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
|
||
Purpose | ||
|
||
Quick Sort is a highly efficient divide-and-conquer sorting algorithm. | ||
It is commonly used because of its performance, simplicity, and ability to work in-place without requiring additional memory. | ||
The algorithm works by partitioning the array around a pivot element and recursively sorting the subarrays. | ||
|
||
|
||
|
||
algorithm:- | ||
|
||
-> Input | ||
An unsorted array arr[] of size n. | ||
Two indices start and end representing the segment of the array to be sorted. | ||
|
||
-> Output | ||
A sorted version of the array arr[] in ascending order. | ||
|
||
QuickSort(arr, start, end): | ||
Base Condition: | ||
If start is greater than or equal to end, return (the array segment is already sorted). | ||
|
||
Partitioning: | ||
Call the Partition() function to partition the array into two segments: | ||
Elements smaller than or equal to the pivot. | ||
Elements greater than the pivot. | ||
The function returns the index of the pivot (pivotIndex), where the pivot is in its correct position. | ||
|
||
Recursive Sorting: | ||
|
||
Recursively sort the left subarray (start to pivotIndex - 1). | ||
Recursively sort the right subarray (pivotIndex + 1 to end). | ||
|
||
Termination: | ||
The recursion terminates when all subarrays are reduced to size 1 or 0, and the entire array is sorted. | ||
|
||
Partition(arr, start, end): | ||
Select the pivot element, typically the last element of the segment: | ||
pivot ← arr[end]. | ||
|
||
Initialize a pointer partitionIndex to start. This will keep track of the position where the next smaller element should be placed. | ||
|
||
Iterate through the array segment from start to end - 1: | ||
|
||
For each element: | ||
If the element is smaller than or equal to the pivot: | ||
Swap the element with the element at partitionIndex. | ||
Increment partitionIndex. | ||
|
||
After the loop, place the pivot in its correct position by swapping it with the element at partitionIndex. | ||
|
||
Return the partitionIndex, which is the final position of the pivot. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
def quick_sort(arr, start, end): | ||
""" | ||
Quick Sort algorithm: Sorts the array in ascending order. | ||
Parameters: | ||
arr (list): The list of elements to be sorted. | ||
start (int): The starting index of the array segment. | ||
end (int): The ending index of the array segment. | ||
""" | ||
if start < end: | ||
# Partition the array and get the pivot index | ||
pivot_index = partition(arr, start, end) | ||
|
||
# Recursively sort the left subarray | ||
quick_sort(arr, start, pivot_index - 1) | ||
|
||
# Recursively sort the right subarray | ||
quick_sort(arr, pivot_index + 1, end) | ||
|
||
|
||
def partition(arr, start, end): | ||
""" | ||
Partitions the array around a pivot such that all elements smaller than | ||
or equal to the pivot are on the left, and all elements greater are on the right. | ||
Parameters: | ||
arr (list): The list of elements to be partitioned. | ||
start (int): The starting index of the array segment. | ||
end (int): The ending index of the array segment (pivot). | ||
Returns: | ||
int: The index of the pivot element after partitioning. | ||
""" | ||
pivot = arr[end] # Choose the last element as the pivot | ||
partition_index = start # Initialize the partition index | ||
|
||
for i in range(start, end): | ||
if arr[i] <= pivot: | ||
# Swap if the current element is smaller than or equal to the pivot | ||
arr[i], arr[partition_index] = arr[partition_index], arr[i] | ||
partition_index += 1 | ||
|
||
# Place the pivot element at the correct position | ||
arr[partition_index], arr[end] = arr[end], arr[partition_index] | ||
return partition_index | ||
|
||
|
||
# Example Usage | ||
if __name__ == "__main__": | ||
# Input array | ||
array = [8, 3, 1, 7, 0, 10, 2] | ||
print("Original Array:", array) | ||
|
||
# Perform Quick Sort | ||
quick_sort(array, 0, len(array) - 1) | ||
|
||
# Output sorted array | ||
print("Sorted Array:", array) |
Oops, something went wrong.