快速排序也使用了分治的思想,在待排序序列中选择一个基准值,然后将小于基准值的数字放在基准值左边,大于基准值的数字放在基准值右边,然后左右两边递归排序,整个排序过程中最关键部分就是寻找基准值在待排序序列中的索引位置。快速排序由于其时间复杂度优于大部分的排序算法,因而命名为快速排序。
时间复杂度
快速排序的最优情况下时间复杂度为O(nlogn),最坏时间复杂度为O(n^2),平均时间复杂度为O(nlogn)。
算法思想
首先先从原始数组中找到一个基准,这里我们选择第一个元素,然后使用两个哨兵i和j,如果i和j不相交,也就是不相等,那么j从数组的最右边先出发,依次往左找到第一个小于基准值的元素停下,然后i从数组的基准值之后的元素出发,找到第一个大于基准的元素,然后将两个元素进行交换,交换之后,如果i还是小于j,j继续往左找第一个小于基准的元素找到后停下,i继续向右出发找第一个大于基准的元素,找到后停下,继续交换,如果过程中出现了i不小于j,也就是i和j橡胶,那么这时将i指向的元素与基准元素进行交换,这样就可以保证基准值左边的元素都比基准值小,基准值右边的元素逗比基准值大。然后利用分治,递归来拆分数组粒度,最后完成有序数组。下面以数组[9,5,2,7,12,4,3,1,11]看图示:
第一轮扫描结束后,接下来将基准值左右两边拆成两个数组,然后采用分治来分别按照上述思想来进行排序,直到不能继续拆分
代码实现
package quicksort
import "fmt"
func privot(arr []int, left, right int) int {
base := arr[left]
i, j := left, right
for i < j {
for arr[j] >= base && i < j {
j--
}
for arr[i] <= base && i < j {
i++
}
if i < j {
fmt.Printf("arr[i]:%v,arr[j]:%v\n", arr[i], arr[j])
arr[i], arr[j] = arr[j], arr[i]
}
}
arr[i], arr[left] = arr[left], arr[i]
return i
}
func quicksort(arr []int, left, right int) {
if left >= right {
return
}
mid := privot(arr, left, right)
quicksort(arr, left, mid-1)
quicksort(arr, mid+1, right)
}
func main() {
arr := []int{9, 5, 2, 7, 12, 4, 3, 1, 11}
fmt.Println("arr:", arr)
quicksort(arr, 0, len(arr)-1)
fmt.Println("sort:", arr)
}