In this video lesson we will study how the Quick Sort algorithm works, we will analyze its time and space complexities and then we will implement it:
Problem - Quick Sort:
Given an array of integers nums, sort it in ascending order using Quick Sort
Example 1:
Input: nums =[3, 1, 3, 2, 5, 4]
Output:[1, 2, 3, 3, 4, 5]
Your algorithm should run in O(n log n) time and use O(log n) extra space.
def quick_sort(arr):
# Helper function to perform the partitioning
def partition(low, high):
pivot = arr[high] # Choose the last element as pivot
i = low - 1 # Pointer for the greater element
for j in range(low, high):
# If current element is smaller than or equal to pivot
if arr[j] <= pivot:
i += 1 # Increment the pointer
arr[i], arr[j] = arr[j], arr[i] # Swap elements
arr[i + 1], arr[high] = arr[high], arr[i + 1] # Swap the pivot element
return i + 1
# Helper function to perform quick sort
def quick_sort_recursive(low, high):
if low < high:
pi = partition(low, high) # Partition the array
quick_sort_recursive(low, pi - 1) # Sort the left part
quick_sort_recursive(pi + 1, high) # Sort the right part
quick_sort_recursive(0, len(arr) - 1) # Initial call to quick sort
# Example usage
nums = [3, 1, 3, 2, 5, 4]
quick_sort(nums)
print(nums) # Output: [1, 2, 3, 3, 4, 5]
### Key Parts of the Code
- **Partition Function**: This function rearranges the elements around the pivot.
- **Recursive Function**: This function applies Quick Sort to the sub-arrays.
## Complexity Analysis
- **Time Complexity**:
- Average Case: O(n log n)
- Worst Case: O(n^2) (when the pivot is the smallest or largest element)
- **Space Complexity**: O(log n) due to the recursion stack.
### Improvements Over Naive Approach
Quick Sort is significantly faster than naive sorting algorithms like Bubble Sort and Insertion Sort, especially for large datasets.
## Edge Cases
- **Empty Array**: The algorithm should handle an empty array gracefully.
- **Array with One Element**: The algorithm should return the array as is.
- **Array with All Identical Elements**: The algorithm should handle this without unnecessary swaps.
### Example Edge Cases
- **Input**: `[]`
- **Output**: `[]`
- **Input**: `[1]`
- **Output**: `[1]`
- **Input**: `[2, 2, 2, 2]`
- **Output**: `[2, 2, 2, 2]`
## Testing
To test the solution comprehensively, consider the following test cases:
- **Simple Case**: `[3, 1, 3, 2, 5, 4]`
- **Empty Array**: `[]`
- **Single Element**: `[1]`
- **All Identical Elements**: `[2, 2, 2, 2]`
- **Already Sorted**: `[1, 2, 3, 4, 5]`
- **Reverse Sorted**: `[5, 4, 3, 2, 1]`
### Testing Frameworks
You can use Python's built-in `unittest` framework to automate the testing process.
## Thinking and Problem-Solving Tips
- **Understand the Problem**: Break down the problem into smaller parts.
- **Choose the Right Algorithm**: Consider the time and space complexity.
- **Practice**: Solve similar problems to improve your understanding.
## Conclusion
Quick Sort is a powerful and efficient sorting algorithm that is widely used in practice. Understanding its mechanics and implementation can significantly improve your problem-solving skills.
## Additional Resources
- [Quick Sort on Wikipedia](https://en.wikipedia.org/wiki/Quicksort)
- [Sorting Algorithms - GeeksforGeeks](https://www.geeksforgeeks.org/sorting-algorithms/)
- [LeetCode Sorting Problems](https://leetcode.com/tag/sorting/)
By mastering Quick Sort, you can tackle a wide range of sorting problems efficiently and effectively. Happy coding!