quicksort
python
sorting algorithm
programming
computer science

Quicksort with Python

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

Quicksort is a highly efficient sorting algorithm and is one of the most widely used algorithms for sorting data. It was developed by Tony Hoare in 1960 and is an example of the divide-and-conquer algorithmic paradigm. Quicksort is popular due to its simplicity and its O(nlogn)O(n \log n) average-case performance comparison.

In this article, we'll delve deep into the mechanics of the Quicksort algorithm, demonstrate how you can implement it in Python, and compare it with other sorting techniques.

Understanding the Algorithm

Quicksort works by selecting a 'pivot' element from the array and partitioning the other elements into two sub-arrays: those less than the pivot and those greater than the pivot. It then recursively sorts the sub-arrays.

Steps of the Algorithm

  1. Choose a Pivot: A central element of the data array is chosen as the pivot.
  2. Partitioning: Rearrange the array so that all elements with values less than the pivot come before the pivot, while all elements with values greater than the pivot come after it. After this, the pivot is in its final position.
  3. Recursively Apply the above steps to the sub-array of elements with smaller values and the sub-array of elements with greater values.

Choosing a Pivot

Selecting the correct pivot is crucial for optimal performance. Common strategies include:

  • First Element: Simple and efficient for pre-sorted arrays.
  • Last Element: Similarly simple but not as efficient for sorted arrays in reverse.
  • Random Element: An unbiased approach that helps in reducing the chances of encountering worst-case performance.
  • Median-of-Three: Choose the median of the first, middle, and last elements.

Example Python Implementation

Here’s how you can implement the Quicksort algorithm in Python:

python
1def quicksort(array):
2    if len(array) <= 1:
3        return array
4    else:
5        pivot = array[len(array) // 2]
6        left = [x for x in array if x < pivot]
7        middle = [x for x in array if x == pivot]
8        right = [x for x in array if x > pivot]
9        return quicksort(left) + middle + quicksort(right)
10
11# Example usage
12unsorted_array = [3, 6, 8, 10, 1, 2, 1]
13sorted_array = quicksort(unsorted_array)
14print(sorted_array)

Technical Explanation

  • The function quicksort sorts an array. If the array has one or zero elements, it is already sorted.
  • The pivot is chosen as the middle element.
  • The list is partitioned into three lists: left, middle, and right.
  • The algorithm is recursively applied to the left and right sub-lists.
  • The results are concatenated together to produce the sorted list.

Time Complexity

Time ComplexityBestAverageWorst
QuicksortO(nlogn)O(n \log n)O(nlogn)O(n \log n)O(n2)O(n^2)
  • Best and Average Case: O(nlogn)O(n \log n) – occurs when the pivot divides the array into two nearly equal halves.
  • Worst Case: O(n2)O(n^2) – occurs when the smallest or largest element is always picked as the pivot resulting in highly unbalanced splits. This can particularly happen when the input is already sorted.

Key Characteristics

  • In-Place Sorting: Quicksort rearranges elements within the input data structure. However, the simple Python implementation above is not in-place due to list comprehensions.
  • Recursive: Utilizes the call stack for recursive calls, which can lead to stack overflow in languages or environments with limited stack size.
  • Unstable: Does not guarantee the initial order of equal elements.

Enhancements and Optimizations

Tail Recursion Elimination

To optimize recursive calls and prevent stack overflow, especially for large datasets, tail recursion elimination or iterative methods can be used.

Three-Way Partitioning

Another optimization is a three-way partitioning technique that handles duplicate keys more efficiently by dividing the array into three parts:

  1. Elements less than the pivot.
  2. Elements equal to the pivot.
  3. Elements greater than the pivot.

Hybrid Approaches

In practice, many languages and libraries employ hybrid algorithms that switch to simpler algorithms like insertion sort when the data size is sufficiently small, as insertion sort provides less overhead for small datasets.

Conclusion

Quicksort is an elegant and efficient algorithm for sorting datasets, balancing its average-case efficiency with the elegance of its design. Although its worst-case performance is sub-optimal, diverse optimizations and hybrid approaches mitigate this, making Quicksort a formidable choice in computational sorting applications.

By understanding its implementation and deepening our knowledge of optimization strategies, Quicksort remains relevant and commandingly effective in modern computing contexts. Whether you are a beginner learning sorting algorithms or an advanced developer optimizing software, mastering Quicksort can significantly enhance your algorithm toolkit.


Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.