package Sort
import (
"fmt"
"math/rand"
"testing"
"time"
)
/*
快速排序 前奏
Partition 过程
给定一个数组arr,和一个整数num。请把小于等于num的数放在数组的左边,大于num的数放在数组的右边。不需要有序
要求:额外空间复杂度O(1),时间复杂度O(N)
\
<= 区域 | [ 5 3 7 2 3 4 1 ] num = 3
/ 下标 0 1 2 3 4 5 6
1. [i] <= num 当前数和 <=区下一个数交换, <= 区右扩,i++
2. [2] > num i++
*/
func Partition(arr []int, L, R int) int {
if L > R {
return -1
}
if L == R {
return L
}
lessEqual := L - 1
for index := L; index < R; index++ {
if arr[index] <= arr[R] { // 先默认arr[R]为参照值
lessEqual++
Swap(arr, index, lessEqual)
}
}
lessEqual++
Swap(arr, lessEqual, R)
return lessEqual
}
func TestPartition(t *testing.T) {
arr := []int{12, 83, 2, 1, 0, 23, 344, 2, 1, -100, -200, -32, 4, 30, 5, 6, -1}
fmt.Println(Partition(arr, 0, len(arr)-1))
fmt.Println(arr)
}
/*
1.0
在数组上 做分区
<=x >x
保证小于等于区域 最后一个 一定是x,当然小于等于区域可能
还存在x
左侧右侧同时递归,总会有排完序的时候
*/
func QuickSort1(arr []int) {
if arr == nil || len(arr) < 2 {
return
}
processQ1(arr, 0, len(arr)-1)
}
func processQ1(arr []int, L, R int) {
if L >= R {
return
}
M := Partition(arr, L, R) //M对应的值被固定下来,即:有序了
processQ1(arr, L, M-1)
processQ1(arr, M+1, R)
}
/*
NetherlandsFlag
荷兰国旗问题 给定数组和num <num 的放左边 =num 的放中间 >num 的放右边
\ /
\ [3,4,5,0,4,6,7,2] |
> | = \ >
区 / 区 \ 区
荷兰国旗问题 (三色问题) 给定一个数组arr和一个数num,将该数组划分三个区域 小于num在左边 等于num的在中间 大于num在右边
1) 当前数 == num , i++
2) 当前数 < num 当前数与小于区域右侧第一个数交换,小于区域向右扩,i++
3) 当前数 > num 当前数与大于区域左侧第一个数交换,大于区域向左扩, i 停在原地
4) i和大于区域边界重合则停止
arr[L..R]上玩荷兰国旗的划分,以arr[R]作为划分值 ,返回等于区域的左右边界
*/
func NetherlandsFlag(arr []int, L, R int) []int {
if L > R {
return []int{-1, -1}
}
if L == R {
return []int{L, R}
}
less, more, index := L-1, R, L
for index < more {
if arr[index] == arr[R] {
index++
} else if arr[index] < arr[R] {
less++
Swap(arr, index, less)
index++
} else {
more--
Swap(arr, index, more)
}
}
Swap(arr, more, R)
//fmt.Println(arr)
return []int{less + 1, more}
}
func TestNetherLandsFlag(t *testing.T) {
arr := []int{6, 3, 2, 1, 4, 3}
//1 2 3 3 4 6
//fmt.Println(NetherlandsFlag(arr,0,len(arr)-1))
//Partition(arr,0,len(arr)-1)
QuickSort2(arr)
fmt.Println(arr)
}
/*
2.0 利用荷兰国旗问题,
<x ==x >x ==x 不用动
*/
func processQ2(arr []int, L, R int) {
if L >= R {
return
}
equalArea := NetherlandsFlag(arr, L, R) // 中间部分是相等的,被固定下来了, 所以只要考虑< 区域和 > 区域就可以
processQ2(arr, L, equalArea[0]-1)
processQ2(arr, equalArea[1]+1, R)
}
func QuickSort2(arr []int) {
processQ2(arr, 0, len(arr)-1)
}
/*
快排 1,2 都是O(n^2)的复杂度
原先用arr[R]左划分值
3.0 随机选一个数,i位置,和最后一个
做交换,其余都是2.0的 逻辑
时间复杂度收敛于O(N*logN),空间复杂度收敛于O(logN)
快排非递归版本需要的辅助类
要处理的是什么范围上的排序
快排3.0 及 非递归版本
*/
func QuickSort3(arr []int) {
processQ3(arr, 0, len(arr)-1)
}
// 随机选一个数作为划分值
// 最好的情况,左右两侧规模差不多时候
// 所有情况求概率累加,长期期望的结果是O(N*logN)
// 空间复杂度 好的情况 O(logN) 坏情况O(N) 同样最终结果是概率累加的结果
func processQ3(arr []int, L, R int) { //时间复杂度:O(N*logN) 额外空间复杂度:O(logN)
if L >= R {
return
}
rand.Seed(time.Now().UnixNano()) //随机选一个位置
Swap(arr, L+rand.Int()%(R-L+1), R)
equalArea := NetherlandsFlag(arr, L, R)
processQ3(arr, L, equalArea[0]-1)
processQ3(arr, equalArea[1]+1, R)
}
func TestQuickSort3(t *testing.T) {
arr := []int{6, 3, 2, 1, 4, 3}
QuickSort3(arr)
fmt.Println(arr)
}
// 非递归版本
func quickSort4(arr []int) {
if arr == nil || len(arr) < 2 {
return
}
type Op struct {
l, r int
}
N := len(arr)
rand.Seed(time.Now().UnixNano())
Swap(arr, rand.Int()%N, N-1)
equalArea := NetherlandsFlag(arr, 0, N-1)
el, er, stack := equalArea[0], equalArea[1], new(Stack)
stack.Push(Op{0, el - 1}) // 0 ~ 等于区左边界
stack.Push(Op{er + 1, N - 1}) // 等于区有边界到R
for !stack.IsEmpty() {
op := stack.Pop().(Op) // op.l ... op.r
if op.l < op.r { // 折腾 l < r 上的数
Swap(arr, op.l+(rand.Int()%(op.r-op.l+1)), op.r)
equalArea = NetherlandsFlag(arr, op.l, op.r)
el, er = equalArea[0], equalArea[1] //同理
stack.Push(Op{op.l, el - 1})
stack.Push(Op{er + 1, op.r})
}
}
}
type Stack struct {
Value []interface{}
}
func (this *Stack) Push(v interface{}) {
this.Value = append(this.Value, v)
}
func (this *Stack) Pop() (v interface{}) {
if len(this.Value) >= 1 {
v = this.Value[len(this.Value)-1]
this.Value = this.Value[:len(this.Value)-1]
}
return v
}
func (this *Stack) IsEmpty() bool {
return len(this.Value) == 0
}
func TestQuickSort4(t *testing.T) {
arr := []int{12, 3, 2, 1, 0, 23, 344, 2, 1, -100, -200, -32, 4, 3, 5, 6, 9}
quickSort4(arr)
fmt.Println(arr)
}
排序——快排
于 2021-10-23 19:38:14 首次发布