go_排序算法_快速排序(三种方法)

1.4 快速排序

1.4.1 快排介绍

​ 基本思想:通过一趟排序将要排序的数据分隔成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

1.4.2 算法描述

快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下:

  • 从数列中挑出一个元素,称为 “基准”(pivot);
  • 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
  • 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
1.4.3 动图演示

img

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

posted @ 2021-03-05 10:13  天下医者不自医  阅读(1737)  评论(0编辑  收藏  举报