NOTE

3.14 快速排序

1. 快速排序 采用了分而治之的思想,就是说把一个大的问题分成小的问题,然后递归求解 快速排序想选取一个pivot,比他小的移动到左边,比他大的移动到右边, 对左边的小数组和右边的小数组做同样的处理 如果说归并排序的关键在于合并,那么快速排序的关键在于拆分 2. 效率 - 稳定性:不稳定 - 原地排

Data Structures & Algorithms创建于 更新于 historical

这是历史学习笔记,可能存在过时或不完整的理解。

1. 快速排序

采用了分而治之的思想,就是说把一个大的问题分成小的问题,然后递归求解 快速排序想选取一个pivot,比他小的移动到左边,比他大的移动到右边, 对左边的小数组和右边的小数组做同样的处理 如果说归并排序的关键在于合并,那么快速排序的关键在于拆分

2. 效率

  • 稳定性:不稳定
  • 原地排序:是
  • 复杂度
    • 时间:平均O(nlogn),最坏O(n²)
    • 空间:O(logn)

3. 过程

4. 实现

4.1. 单路快排

//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. 测试

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. 优化

  • 对于有序数组每次只会拆分一个,效率下降到O(N²)
  • 添加随机化
func partition(data []model.Comparable, left int, right int) int {
	//生成[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. 双路排序

//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 {
	//生成[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. 测试

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. 三路排序


//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
	}
	//生成[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. 测试

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. 常见的实现

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. 测试

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)
}

5. 参考