NOTE
3.14 Quick Sort
Quick sort, its characteristics, partitions, and implementations.
This is a historical learning note and may contain outdated or incomplete understanding.
1. Quick Sort
It uses the divide-and-conquer idea: divide a large problem into smaller problems and solve them recursively. Quick sort selects a pivot, moves values smaller than it to the left and values larger than it to the right, and then performs the same processing on the smaller arrays on the left and right. If the key to merge sort is merging, the key to quick sort is partitioning.
2. Efficiency
- Stability: unstable
- In-place sorting: yes
- Complexity
- Time: average O(nlogn), worst O(n²)
- Space: O(logn)
3. Process
4. Implementation
4.1. One-Way Quick Sort
//O(NlogN)
func QuickSort(data []model.Comparable) {
quickSort(data, 0, len(data)-1)
}
func quickSort(data []model.Comparable, left int, right int) {
if left >= right {
return
}
p := partition(data, left, right)
quickSort(data, left, p-1)
quickSort(data, p+1, right)
}
func partition(data []model.Comparable, left int, right int) int {
// data[left+1...j] < v; data[j+1...i] >= v
j := left
for i := left + 1; i <= right; i++ {
if data[i].CompareTo(data[left]) < 0 {
j++
util.Swap(data, i, j)
}
}
util.Swap(data, left, j)
return j
}
4.1.1. Test
func TestQuickSort(t *testing.T) {
e1 := model.NewElement(1)
e2 := model.NewElement(2)
e3 := model.NewElement(3)
data := []model.Comparable{e2, e1, e3}
fmt.Println(data)
QuickSort(data)
fmt.Println(data)
}
4.1.2. Optimization
- For a sorted array, each partition splits off only one element, so efficiency drops to O(N²)
- Add randomization
func partition(data []model.Comparable, left int, right int) int {
// Generate a random index in [l, r]
p := left + util.RandInt(0, right-left)
util.Swap(data, left, p)
// data[left+1...j] < v; data[j+1...i] >= v
j := left
for i := left + 1; i <= right; i++ {
if data[i].CompareTo(data[left]) < 0 {
j++
util.Swap(data, i, j)
}
}
util.Swap(data, left, j)
return j
}
4.2. Two-Way Quick Sort
//O(NlogN)
func QuickSort2(data []model.Comparable) {
quickSort2(data, 0, len(data)-1)
}
func quickSort2(data []model.Comparable, left int, right int) {
if left >= right {
return
}
p := partition2(data, left, right)
quickSort2(data, left, p-1)
quickSort2(data, p+1, right)
}
func partition2(data []model.Comparable, left int, right int) int {
// Generate a random index in [l, r]
p := left + util.RandInt(0, right-left)
util.Swap(data, left, p)
// data[left+1...j] <= v; data[j+1...i] >= v
i := left + 1
j := right
for {
for i <= j && data[i].CompareTo(data[left]) < 0 {
i++
}
for j >= i && data[j].CompareTo(data[left]) > 0 {
j--
}
if i >= j {
break
}
util.Swap(data, i, j)
i++
j--
}
util.Swap(data, left, j)
return j
}
4.2.1. Test
func TestQuickSort2(t *testing.T) {
e1 := model.NewElement(1)
e2 := model.NewElement(2)
e3 := model.NewElement(3)
data := []model.Comparable{e2, e1, e3}
fmt.Println(data)
QuickSort2(data)
fmt.Println(data)
}
4.3. Three-Way Quick Sort
//O(NlogN)
func QuickSort3(data []model.Comparable) {
quickSort3(data, 0, len(data)-1)
}
func quickSort3(data []model.Comparable, left int, right int) {
if left >= right {
return
}
// Generate a random index in [l, r]
p := left + util.RandInt(0, right-left)
util.Swap(data, left, p)
// data[l+1, lt] < v, data[lt+1, i-1] == v, data[gt, r] > v
lt := left
i := left + 1
gt := right + 1
for i < gt {
if data[i].CompareTo(data[left]) < 0 {
lt++
util.Swap(data, i, lt)
i++
} else if data[i].CompareTo(data[left]) > 0 {
gt--
util.Swap(data, i, gt)
} else {
i++
}
}
util.Swap(data, left, lt)
quickSort3(data, left, lt-1)
quickSort3(data, gt, right)
}
4.3.1. Test
func TestQuickSort3(t *testing.T) {
e1 := model.NewElement(1)
e2 := model.NewElement(2)
e3 := model.NewElement(3)
data := []model.Comparable{e2, e1, e3}
fmt.Println(data)
QuickSort3(data)
fmt.Println(data)
}
4.4. Common Implementation
package sort
import (
"my_algorithm/model"
)
//O(NlogN)
func QuickSort2Again(data []model.Comparable) {
quickSort2Again(data, 0, len(data)-1)
}
func quickSort2Again(data []model.Comparable, left int, right int) {
if left >= right {
return
}
p := partition2Again(data, left, right)
quickSort2Again(data, left, p-1)
quickSort2Again(data, p+1, right)
}
func partition2Again(data []model.Comparable, left int, right int) int {
pivot := data[left]
for left < right {
for left < right && data[right].CompareTo(pivot) >= 0 {
right--
}
data[left] = data[right]
for left < right && data[left].CompareTo(pivot) <= 0 {
left++
}
data[right] = data[left]
}
data[left] = pivot
return right
}
4.4.1. Test
func TestQuickSort2Again(t *testing.T) {
e1 := model.NewElement(1)
e2 := model.NewElement(2)
e3 := model.NewElement(3)
data := []model.Comparable{e2, e1, e1, e3}
fmt.Println(data)
QuickSort2Again(data)
fmt.Println(data)
}



Discussion
Sign in with GitHub to comment. Discussions are stored as GitHub Issues.View on GitHub