快排
原理:先取第一个数为分水岭。。判断v[i]与分水岭得大小,小于和head互换,i++,head++ 。大于和tail互换,tail--。最终得到小于分水岭+分水岭+大于分水岭得数组,再对左边递归,得到最终结果。但是如果第一个数字的数值不好的情况下,可能复杂度到o(n^2)
右边递归,得到最终结果。
func QuickSort(values []int) []int{
length := len(values)
if length <= 1 {
return values
}
mid, i := values[0], 1 // 取第一个元素作为分水岭,i下标初始为1,即分水岭右侧的第一个元素的下标
head, tail := 0, length-1 // 头尾的下标
// 如果头和尾没有相遇,就会一直触发交换
for head < tail {
fmt.Println(values, head, tail, i)
if values[i] > mid {
// 如果分水岭右侧的元素大于分水岭,就将右侧的尾部元素和分水岭右侧元素交换
values[i], values[tail] = values[tail], values[i]
tail-- // 尾下标左移一位
} else {
// 如果分水岭右侧的元素小于等于分水岭,就将分水岭右移一位
values[i], values[head] = values[head], values[i]
head++ // 头下标右移一位
i++ // i下标右移一位
}
fmt.Printf("----{head:%d,tail:%d,i:%d,mid:%d} values:%v\n", head, tail, i, mid, values)
}
// 分水岭左右的元素递归做同样处理
QuickSort(values[:head])
QuickSort(values[head+1:])
return values
}
堆排序
func sortArray(arr []int)[]int {
length := len(arr)
// 下沉建堆,从最后一个结点的父节点开始,往前遍历,执行建堆操作。。。。。大根堆
for i := (length-1)/2;i>=0;i--{
heapify(arr,length,i)
}
fmt.Println("构建大根堆结束",arr)
//排序
for k := length-1;k >= 0;k--{
arr[0],arr[k] = arr[k],arr[0]//先交换首位,然后砍掉尾巴,做heapify
heapify(arr,k,0)
fmt.Println("排序过程",arr)
}
return arr
}
func heapify(arr []int,n,i int) {
if i >= n{
return
}
c1 := 2*i+1
c2 := 2*i+2
max := i
if(c1 < n && arr[c1] > arr[max]){
max = c1
}
if (c2 < n && arr[c2] > arr[max]) {
max = c2
}
if max != i{
arr[max],arr[i] = arr[i],arr[max]
heapify(arr,n,max)
}
}
func main() {
var length = 10
var tree []int
for i := 0; i < length; i++ {
tree = append(tree, int(rand.Intn(20)))
}
fmt.Println("原始数据",tree)
arr := sortArray(tree)
fmt.Println("排序完成",arr)
}
给定一个无序数组,首先通过heapify函数把它构造成大根堆。注意采用下沉建堆,从最后一个结点的父节点开始,往前遍历,执行建堆操作。。。。。大根堆。
heapify过程,传入arr,arr长度,构造大根堆父节点下标i。子节点大于父节点就互换位置,互换完位置,对子节点继续递归构造。。
构造完大根堆就去排序。。思路 对length进行for-循环。。先把首位互换,最大值扔到末尾,去构造新的大根堆。 注意这里的去尾操作不用刻意经行。在heapfy操作里,对子节点进行大小限制,c2 < n n就是最后一位的下标.
构建大根堆的时候,heapify的n带入length,i代表要处理位置的下标,所有的下标要小于length , c2 < n ,c1 < n
排序的时候,heapifiy的n带k:=length-1,,因为存在c2 < n ,c1 < n ,所以默认把大根的数的最后一个值给排除在外了。。
直接调用库函数
func sortArray(nums []int) []int {
sort.Slice(nums,func(i,j int)bool{
return nums[i]<nums[j]
})
return nums
}
选择排序
两个for循环 ,去比较,找到小的值
func selectionSort(arr []int)[]int {
n := len(arr)
for i := 0;i<n-1;i++{
min := i
for j := i;j<n;j++ {
if arr[j] < arr[min]{
min = j
}
}
arr[i],arr[min] = arr[min],arr[i]
}
return arr
}
冒泡排序
func Bubbles(arr []int) {
n := len(arr)
for i := n-1;i>0;i--{
for j := 0;j<n-1;j++{
if arr[j] > arr[j+1]{
arr[j],arr[j+1] = arr[j+1],arr[j]
}
}
}
}
大for逆序,小for正序
第一轮
第二轮
第三轮
第四轮
第五轮
插入排序
func insertionSort(arr []int)[]int {
if arr == nil || len(arr) < 2{
return arr
}
//0-0有序 0-i想有序
for i := 1;i<len(arr);i++{
for j := i-1;j >= 0 && arr[j]>arr[j+1];j-- {
swap(arr,j,j+1)
}
}
return arr
}
就是前边递增,用新来的和前边有序数组进行比较,从后往前比较,啥时候小于他就互换位置
大for递增,小for递减 j := i-1;j >= 0 && arr[j]>arr[j+1];j--
归并排序
package main
import "fmt"
//双指针
//o(nlogn)
//先在中间位置把数组分开,给左右两边分别排序 之后再归并起来 归并之后的每一块都是有序的
func MergeSort(arr []int) []int {
lenth := len(arr)
//数组为空或者只有一个元素返回
if lenth <= 1{
return arr
}
mid := lenth/2
leftArr := MergeSort(arr[:mid])
rightArr := MergeSort(arr[mid:])
return merge(leftArr,rightArr)
}
func merge(left []int,right []int)[]int {
var result []int
for len(left) != 0 && len(right) != 0{
if left[0] < right[0]{
result = append(result,left[0])
left = left[1:]
}else {
result = append(result,right[0])
right = right[1:]
}
}
//把没有结束的归并过来
for len(left) != 0 {
result = append(result,left[0])
left = left[1:]
}
for len(right) != 0 {
result = append(result,right[0])
right = right[1:]
}
return result
}
func main() {
arr := []int{20,5,3,1,2000,5,30}
arr = MergeSort(arr)
fmt.Println(arr)
}