go_排序算法_快速排序(三种方法)
1.4 快速排序
1.4.1 快排介绍
基本思想:通过一趟排序将要排序的数据分隔成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
1.4.2 算法描述
快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下:
- 从数列中挑出一个元素,称为 “基准”(pivot);
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
- 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
1.4.3 动图演示
1.4.4 代码如下
package main
import (
"fmt"
)
func QuickSort(arr []int) []int {
if len(arr) <= 1 {
return arr
}
splitdata := arr[0] //第一个数据为基准
low := make([]int, 0, 0) //比我小的数据
hight := make([]int, 0, 0) //比我大的数据
mid := make([]int, 0, 0) //与我一样大的数据
mid = append(mid, splitdata) //加入一个
for i := 1; i < len(arr); i++ {
if arr[i] < splitdata {
low = append(low, arr[i])
} else if arr[i] > splitdata {
hight = append(hight, arr[i])
} else {
mid = append(mid, arr[i])
}
}
low, hight = QuickSort(low), QuickSort(hight) //切割递归处理
myarr := append(append(low, mid...), hight...)
return myarr
}
//快读排序算法
func main() {
arr := []int{1, 9, 10, 30, 2, 5, 45, 8, 63, 234, 12}
fmt.Println(QuickSort(arr))
}
快排的第二种写法:
快排的第二种写法:
package main
import (
"fmt"
"math/rand"
"time"
)
//快速排序
//1、left表示数组左边的下标
//2、right表示数组右边的下标
func QuickSort(left, right int, array *[80000]int) {
l := left
r := right
pivot := array[(left+right)/2]
//for循环的目标是将比pivot小的数放在左边,比pivot大的数放在右边
for l < r {
//从pivot左边找到一个大于等于pivot的值
for array[l] < pivot {
l++
}
//从pivot右边找到小于等于pivot的值
for array[r] > pivot {
r--
}
//表明本次分解任务完成
if l >= r {
break
}
//交换
array[l], array[r] = array[r], array[l]
//优化
if array[l] == pivot {
r--
}
if array[r] == pivot {
l++
}
// fmt.Printf("%v\n", *array)
}
//可注释以下代码做测试
//如果l==r,在移动下
if l == r {
l++
r--
}
//向左递归
if left < r {
QuickSort(left, r, array)
}
//向右递归
if right > l {
QuickSort(l, right, array)
}
}
//快读排序算法
func main() {
//arr := [11]int{-1, 9, 10, 30, 2, 5, 45, 8, 63, 234, 12}
//slcie := arr[:]
//fmt.Printf("%T\n", slcie)
var arr [80000]int
for i := 0; i < 80000; i++ {
arr[i] = rand.Intn(900000)
}
start := time.Now().Unix()
//fmt.Println("初始", arr)
QuickSort(0, len(arr)-1, &arr)
end := time.Now().Unix()
fmt.Printf("快排耗时:%ds", end-start)
//fmt.Println("main", arr)
}
快速排序的第三种写法
快速排序的第三种写法
package main
import (
"fmt"
"math/rand"
)
//swap
func swap(arr []int, left, right int) {
arr[left], arr[right] = arr[right], arr[left]
}
//插入排序
func SortForMerge(arr []int, left, right int) {
for i := left; i <= right; i++ {
temp := arr[i]
var j int
for j = i; j > left && arr[j-1] > temp; j-- { //定位
arr[j] = arr[j-1]
}
arr[j] = temp
}
}
//递归快速排序
func QuickSortX(arr []int, left, right int) {
if right-left < 2 {
SortForMerge(arr, left, right)
} else {
//随机找一个数字,放在第一个位置
swap(arr, left, rand.Int()%(right-left+1)+left)
vdata := arr[left] //坐标数组,小的放左边,大的放右边
fmt.Println(vdata)
lt := left //arr[left+1,lt] < vdata
gt := right + 1 //arr[gt... right] > vdata
i := left + 1 //arr[lt+1,...i] == vdata
for i < gt {
if arr[i] < vdata {
swap(arr, i, lt+1)
lt++
i++
fmt.Println("left:", arr)
} else if arr[i] > vdata {
swap(arr, i, gt-1)
gt--
fmt.Println("right:", arr)
} else {
i++
}
}
swap(arr, left, lt) //交换头部位置
QuickSortX(arr, left, lt-1) //递归处理左边部分
QuickSortX(arr, gt, right) //递归处理右边部分
fmt.Println(arr)
}
}
//快排核心
func QuicksortPlus(arr []int) {
QuickSortX(arr, 0, len(arr)-1)
}
func main() {
arr := []int{9, 0, 2, 6, 7, 4, 3, 8, 1, 5}
QuicksortPlus(arr)
fmt.Println(arr)
}
参考网站:
https://www.bilibili.com/video/BV114411D768
https://www.bilibili.com/video/BV1hJ411j7gD?p=25