排序——快排

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)
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

metabit

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值