Quick Sort Algorithm
1. Algorithm Explanation
Quick Sort is a divide-and-conquer, comparison-based sorting algorithm. It works by selecting a pivot element from the array and partitioning the other elements into two sub-arrays, according to whether they are less than or greater than the pivot. The sub-arrays are then sorted recursively.
Steps:
- Choose a pivot (e.g., first element, last element, or median-of-three).
- Partition: Rearrange elements so that those less than the pivot come before it and those greater come after it.
- Recursively apply Quick Sort to the sub-array of elements less than the pivot and the sub-array of elements greater than the pivot.
Time Complexity
- Average case:
O(n × log n)
- Worst case:
O(n2)
(when the smallest or largest element is always chosen as pivot)
Memory Complexity
- In-place partitioning:
O(log n)
for recursion stack (average) - Worst-case stack depth:
O(n)
2. Easy Problems
-
2.1 Sort an Array of Integers
Given an array of integers, sort it in ascending order.
#include <iostream> #include <vector> void quickSort(std::vector<int>& arr, int low, int high) { if (low < high) { int pivot = arr[high]; int i = low - 1; for (int j = low; j < high; ++j) { if (arr[j] < pivot) { std::swap(arr[++i], arr[j]); } } std::swap(arr[i + 1], arr[high]); int pi = i + 1; quickSort(arr, low, pi - 1); quickSort(arr, pi + 1, high); } } int main() { std::vector<int> arr = {3, 6, 8, 10, 1, 2, 1}; quickSort(arr, 0, arr.size() - 1); for (int x : arr) std::cout << x << " "; return 0; }
-
2.2 Sort an Array of Strings
Given an array of strings, sort them lexicographically.
#include <iostream> #include <vector> #include <string> void quickSort(std::vector<std::string>& arr, int low, int high) { if (low < high) { std::string pivot = arr[high]; int i = low - 1; for (int j = low; j < high; ++j) { if (arr[j] < pivot) { std::swap(arr[++i], arr[j]); } } std::swap(arr[i + 1], arr[high]); int pi = i + 1; quickSort(arr, low, pi - 1); quickSort(arr, pi + 1, high); } } int main() { std::vector<std::string> arr = {"apple", "orange", "banana", "pear"}; quickSort(arr, 0, arr.size() - 1); for (const auto& s : arr) std::cout << s << " "; return 0; }
3. Intermediate Problems
-
3.1 Find the k-th Smallest Element (Quickselect)
Given an unsorted array, find the k-th smallest element.
#include <iostream> #include <vector> int partition(std::vector<int>& arr, int low, int high) { int pivot = arr[high]; int i = low; for (int j = low; j < high; ++j) { if (arr[j] < pivot) std::swap(arr[i++], arr[j]); } std::swap(arr[i], arr[high]); return i; } int quickSelect(std::vector<int>& arr, int low, int high, int k) { if (low == high) return arr[low]; int pi = partition(arr, low, high); int count = pi - low + 1; if (count == k) return arr[pi]; if (k < count) return quickSelect(arr, low, pi - 1, k); return quickSelect(arr, pi + 1, high, k - count); } int main() { std::vector<int> arr = {7, 10, 4, 3, 20, 15}; int k = 3; std::cout << "The " << k << "-th smallest element is " << quickSelect(arr, 0, arr.size() - 1, k); return 0; }
-
3.2 Sort 2D Points by X-coordinate
Given a list of 2D points, sort them by their x-coordinate.
#include <iostream> #include <vector> #include <utility> void quickSort(std::vector<std::pair<int,int>>& pts, int low, int high) { if (low < high) { auto pivot = pts[high]; int i = low - 1; for (int j = low; j < high; ++j) { if (pts[j].first < pivot.first) { std::swap(pts[++i], pts[j]); } } std::swap(pts[i + 1], pts[high]); int pi = i + 1; quickSort(pts, low, pi - 1); quickSort(pts, pi + 1, high); } } int main() { std::vector<std::pair<int,int>> pts = {{3,4}, {1,2}, {5,0}, {2,3}}; quickSort(pts, 0, pts.size() - 1); for (auto& p : pts) std::cout << "(" << p.first << "," << p.second << ") "; return 0; }
4. Hard Problem
4.1 Sort a Singly Linked List
Implement in-place Quick Sort for a singly linked list.
#include <iostream>
struct Node {
int data;
Node* next;
Node(int v) : data(v), next(nullptr) {}
};
Node* partition(Node* head, Node* end, Node** newHead, Node** newEnd) {
Node* pivot = end;
Node *prev = nullptr, *cur = head, *tail = pivot;
while (cur != pivot) {
if (cur->data < pivot->data) {
if (!*newHead) *newHead = cur;
prev = cur;
cur = cur->next;
} else {
if (prev) prev->next = cur->next;
Node* tmp = cur->next;
cur->next = nullptr;
tail->next = cur;
tail = cur;
cur = tmp;
}
}
if (!*newHead) *newHead = pivot;
*newEnd = tail;
return pivot;
}
Node* quickSortRecur(Node* head, Node* end) {
if (!head || head == end) return head;
Node *newHead = nullptr, *newEnd = nullptr;
Node* pivot = partition(head, end, &newHead, &newEnd);
if (newHead != pivot) {
Node* tmp = newHead;
while (tmp->next != pivot) tmp = tmp->next;
tmp->next = nullptr;
newHead = quickSortRecur(newHead, tmp);
tmp = getTail(newHead);
tmp->next = pivot;
}
pivot->next = quickSortRecur(pivot->next, newEnd);
return newHead;
}
Node* getTail(Node* cur) {
while (cur && cur->next) cur = cur->next;
return cur;
}
int main() {
Node* head = new Node(30);
head->next = new Node(3);
head->next->next = new Node(4);
head->next->next->next = new Node(20);
head->next->next->next->next = new Node(5);
head = quickSortRecur(head, getTail(head));
for (Node* cur = head; cur; cur = cur->next) std::cout << cur->data << " ";
return 0;
}