归并排序

时间复杂度: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,就递归的在分区的第一个元素里面去找。