Golang实现快速排序 && pivot选取的性能比较

递归完成所有元素的快速排序,根据基准值pivot的选取方式不同,有两种实现方案:


 (1).pivot每次选取第一个元素,这样递归栈的长度是n:

func qSort(nums []int) {
	length := len(nums)
	if length <= 1 {
		return
	}

	low, high := 0, length-1
	pivot := low
	for low < high {
		for low < high && nums[high] > nums[pivot] {
			high--
		}

		for low < high && nums[low] < nums[pivot] {
			low++
		}

		nums[low], nums[high] = nums[high], nums[low]
          high-- } qSort(nums[:low]) qSort(nums[low+1:]) }

  

 

 (2).pivot从中间选取,这样递归栈的长度小于n:

func getPivot(nums []int, low, high int) int {
	pivot := nums[low]
	for low < high {
		for low < high && nums[high] >= pivot {
			high--
		}
		nums[low] = nums[high]

		for low < high && nums[low] <= pivot {
			low++
		}
		nums[high] = nums[low]
	}
	nums[low] = pivot
	return low
}

func qSort(nums []int) {
	var backTrack func(num []int, low, high int)
	backTrack = func(num []int, low, high int) {
		if high > low {
			pivot := getPivot(num, low, high)
			backTrack(num, low, pivot)
			backTrack(num, pivot+1, high)
		}
	}

	backTrack(nums, 0, len(nums)-1)
}

 

对长度为10的int切片,排序一百万次,两种快速排序进行性能比较:

func main() {
	x := []int{4, 2, 8, 6, 0, 5, 1, 7, 3, 9}
	tmp := make([]int, 10)
	
	// 第一种方法
	start := time.Now()
	for i := 0; i < 1000000; i++ {
		copy(tmp, x)
		qSort1(tmp)
	}
	cost := time.Since(start)
	fmt.Printf("方法一用时:[%v]\n", cost)

	// 第二种方法
	start = time.Now()
	for i := 0; i < 1000000; i++ {
		copy(tmp, x)
		qSort(tmp)
	}
	cost = time.Since(start)
	fmt.Printf("方法二用时:[%v]\n", cost)
}

  输出几组结果如下:

 

 

 

 

  经过比较,pivot从中间选取,是要比pivot每次取第一个的性能要好的,优化程度大概在8%~15%之间,

  如何理解这个原因呢?是因为pivot每次选第一个时,递归栈的高度是n,见《算法图解》中的下图:

  pivot每次选第一个的递归栈高度:

 

  pivot随机选取时的递归栈高度:

 

 

 

posted @ 2022-03-06 15:58  J0nathan1ei  阅读(114)  评论(0)    收藏  举报