pdqsort | 青训营笔记

77 阅读2分钟
package main

import "fmt"

// pdqsort 使用pdqsort算法对整数切片进行原地排序
func pdqsort(arr []int) {
	const (
		threshold = 16 // 阈值,当数组大小小于该值时,切换到插入排序
		insertion = 8  // 插入排序的阈值
	)

	// 插入排序函数
	insertionSort := func(begin, end int) {
		for i := begin + 1; i < end; i++ {
			for j := i; j > begin && arr[j] < arr[j-1]; j-- {
				arr[j], arr[j-1] = arr[j-1], arr[j] // 交换元素
			}
		}
	}

	// 快速排序函数
	quickSort := func(begin, end int) {
		// 切换到插入排序
		if end-begin <= threshold {
			insertionSort(begin, end)
			return
		}

		// 三数取中法选择主元
		m := begin + (end-begin)/2
		if arr[m] < arr[begin] {
			arr[m], arr[begin] = arr[begin], arr[m]
		}
		if arr[end-1] < arr[begin] {
			arr[end-1], arr[begin] = arr[begin], arr[end-1]
		}
		if arr[end-1] < arr[m] {
			arr[end-1], arr[m] = arr[m], arr[end-1]
		}

		// 将主元放到倒数第二个位置
		arr[m], arr[end-2] = arr[end-2], arr[m]
		pivot := arr[end-2]

		// 快速排序的划分过程
		i, j := begin, end-2
		for {
			for arr[i] < pivot {
				i++
			}
			for pivot < arr[j] {
				j--
			}
			if i >= j {
				break
			}
			arr[i], arr[j] = arr[j], arr[i]
			i++
			j--
		}
		arr[i], arr[end-2] = arr[end-2], arr[i]

		// 递归对左右两部分进行排序
		quickSort(begin, i)
		quickSort(i+1, end)
	}

	quickSort(0, len(arr))
}

func main() {
	arr := []int{9, 3, 7, 5, 1, 6, 8, 2, 4}
	fmt.Println("Before sorting:", arr)
	pdqsort(arr)
	fmt.Println("After sorting:", arr)
}
  • 在函数pdqsort中,设置了常量thresholdinsertion,分别表示切换到插入排序的阈值和插入排序的阈值。

  • 函数insertionSort是插入排序的实现,根据传入的起始位置和结束位置,对该

范围内的元素进行插入排序。

  • 函数quickSort是快速排序的实现,根据传入的起始位置和结束位置,对该范围内的元素进行快速排序。

  • quickSort函数中,通过三数取中法选择主元,并将主元放到倒数第二个位置。

  • 接下来,使用双指针的方式进行划分过程,左指针从起始位置开始,右指针从结束位置的前一个位置开始,分别向中间移动,直到两指针相遇。

  • 在划分过程中,左指针找到大于等于主元的元素,右指针找到小于等于主元的元素,然后交换这两个元素。

  • 最后,递归地对左右两个划分进行快速排序。

  • 在主函数main中,定义了一个整数切片arr,并输出排序前的原始数组。

  • 调用pdqsort函数对切片进行排序。

  • 最后,输出排序后的数组。