冒泡排序
思路:将每轮比较的最大值放在最右边,时间复杂度O(n²),空间复杂度O(1),稳定,不会栈溢出
package main
import (
"fmt"
)
func main() {
slice := []int{2, 1, 3, 5, 4}
effervescence(slice)
fmt.Print(slice)
}
func effervescence(slice []int) []int {
if len(slice) < 2 {
return slice
}
// 考虑到切片不需要排序的情况[]int{1,2,3,4,5}
flag := true
// 切片里有n个数,要做(n-1)轮比较,将每一轮选出的最大值放最右边
for i := 0; i < len(slice)-1; i++ {
// 每一轮需要做len(slice)-1-i次比较。举例:5个数(0,1,2,3,4),第0轮,4次比较(0,1,2,3分别和1,2,3,4比较)
for j := 0; j < len(slice)-i-1; j++ {
if slice[j] > slice[j+1] {
// 确保max在最右边
slice[j], slice[j+1] = slice[j+1], slice[j]
flag = false
}
}
// 一轮比较后,flag值没有改变,则说明不需要排序
if flag == true {
return slice
}
}
return slice
}
快速排序
时间复杂度O(nlogn),空间复杂度O(nlogn),不稳定,可能会栈溢出.使用了递归和分治的思想
思路:随机选一个作为中间值,放尾巴处,然后从最左边开始左边大于中间值,放在尾巴-1(-N)的地方,小于放在头+1(+N)的地方,=时不变.终止条件是用于判断终止条件L和more相遇,less和more是用于记录边界条件的=<>,其中R只有在less=more时,才会交换.slice[R]要和除了自己以外的所有元素比
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
slice := []int{3, 2, 8, 5, 9, 0, 2, 3, 1, 5, 6, 4, 7, 8}
quickSort(slice, 0, len(slice)-1)
fmt.Println(slice)
}
func quickSort(slice []int, L, R int) {
if L < R {
//设置随机数
rand.Seed(time.Now().UnixNano())
//随机选择一个数作为靶心,并与数组的最后一位数交换,实现概率性问题,防止了刻意地制造最差时间复杂度
random := L + rand.Intn(R-L+1)
swap(slice, random, R)
//得到一个长度为2的数组,p[0]表示等于靶心的左边界,p[1]表示等于靶心的右边界
p := partition(slice, L, R)
quickSort(slice, L, p[0]-1) //小于靶心的区域
quickSort(slice, p[1]+1, R) //大于靶心的区域
}
}
func swap(slice []int, a, b int) {
if a != b {
slice[a] = slice[a] ^ slice[b]
slice[b] = slice[a] ^ slice[b]
slice[a] = slice[a] ^ slice[b]
}
}
// 这是一个处理slice[L...R]的函数
// 默认以slice[R]做划分,slice[R]→p <p ==p >p
// 返回等于区域(左边界,右边界),所以返回一个长度为2的数组res, res[0],res[1]
func partition(slice []int, L, R int) []int {
//小于靶心的范围
less := L
//大于靶心的范围
more := R
for L < more { //L表示当前数的位置slice[R]→划分值
if slice[L] < slice[R] { //当前数 < 划分值
swap(slice, less, L)
less++
L++
} else if slice[L] > slice[R] { //如果当前数 > 划分值
more--
swap(slice, more, L)
} else {
L++
}
}
swap(slice, more, R)
return []int{less, more}
}