归并排序
时间复杂度:nlog(n) (在任何情况下都是这个)
缺点 : 它不是一个原地的排序算法
空间复杂度 : n+logn (n是申请的切片的空间,logn是递归用的空间)
它是一个稳定的排序算法(这个只要在我们代码实现的时候注意一下位置就好)
下面是实现代码:
//归
func mergeSort(arr []int) []int {
if len(arr) < 2 {
return arr
}
mid := len(arr) / 2
left := mergeSort(arr[:mid])
right := mergeSort(arr[mid:])
result := merge(left, right)
return result
}
//并
func merge(left, right []int) []int {
fmt.Println(left, right)
temp := make([]int, 0)
i, j := 0, 0
for i < len(left) && j < len(right) {
if left[i] <= right[j] {
temp = append(temp, left[i])
i++
} else {
temp = append(temp, right[j])
j++
}
}
if i < len(left) {
temp = append(temp, left[i:]...)
}
if j < len(right) {
temp = append(temp, right[j:]...)
}
return temp
}
快速排序
时间复杂度 : 一般都为nlogn,特殊的情况下为n的平方
特殊情况:当一个切片为已经排完序的切片的时候,每一次选取的那一个值为最后的那一个值,那么复杂度就变为n的平方
空间复杂度 :logn,最坏为n
它不是一个稳定的排序算法
package main
import "fmt"
func partition(array []int, i int, j int) int {
//第一次调用使用数组的第一个元素当作基准元素
//使用的是双路快速排序
pivot := array[i]
l := i + 1
r := j
for {
for l<=r &&array[l]<pivot{
l ++
}
for r >= l&&array[r]>pivot{
r --
}
if l>=r{
break
}
array[l],array[r]=array[r],array[l]
l ++
r --
}
array[i],array[r]=array[r],array[i]
return r
}
func quicksort(array []int, low int, high int) {
var pivotPos int //划分基准元素索引
if low < high {
pivotPos = partition(array, low, high)
quicksort(array, low, pivotPos-1)
quicksort(array, pivotPos+1, high)
}
}
func main() {
var arr = []int{5, 2, 1, 4, 3}
quicksort(arr, 0, len(arr)-1)
fmt.Println(arr)
}
这里给一个问题,怎么才能在n的时间复杂度内去找到一个无序数组中的第k大的元素呢?
我们可以通过快速排序中分区的思想,选择一个数组随机序列p,然后把一个切片进行分区,分为3个区,如果p+1=k,则p代表的位置就是想找到的第k大的元素,如果k>p+1,那么就递归在分区的第3个部分去找,如果k<p+1,就递归的在分区的第一个元素里面去找。