golang实现常用排序算法 --- 快速排序、堆排序等

简单选择排序

原理阐述:从未排序的数组序列中,选择最大或者最小元素添加入已排序数组 最开始已排序数组为空

import (
    "fmt"
)
//简单选择排序
func simpleSelectSort(nums []int) {
    for i := 0; i < len(nums); i++ {
        min := i
        for j := i + 1; j < len(nums); j++ {
            if nums[min] > nums[j] {
                min = j
            }
        }
        if min != i {
            tmp := nums[min]
            nums[min] = nums[i]
            nums[i] = tmp
        }
    }
}
//test
func main()
{
    var nums = []int{7, 8, 11, 4, 9, 3, 15}
    fmt.Println("nums before insertSort:%s", nums)
    simpleSelectSort(nums)
    fmt.Println("nums after insertSort:%s", nums)
}

直接插入排序

原理阐述:从未排序的数组元素中,取数据填写到以排序的数组中,并且形成已排序数组,数组长度为1的数组为以排序数组

import (
    "fmt"
)
//插入排序
func insertSort(nums []int) {
    for i := 1; i < len(nums); i++ {
        for j := 0; j < i; j++ {
            if nums[i] < nums[j] {
                tmp := nums[i]
                nums[i] = nums[j]
                nums[j] = tmp
            }
        }
    }
}
//test
func main()
{
    var nums = []int{7, 8, 11, 4, 9, 3, 15}
    fmt.Println("nums before insertSort:%s", nums)
    insertSort(nums)
    fmt.Println("nums after insertSort:%s", nums)
}

冒泡排序

原理阐述:相邻两个元素进行对比,顺序相反则互换。经过一轮的对比后,最大或者最小的元素“浮”到顶端,经过len(nums)-1轮后,nums变为有序数组

import (
    "fmt"
)
//冒泡排序
func bubbleSort(nums []int) {
    for i := 1; i < len(nums); i++ { //经过了len(nums)-1轮冒泡
        for j := 0; j < len(nums)-i; j++ {
            if nums[j] > nums[j+1] {
                tmp := nums[j]
                nums[j] = nums[j+1]
                nums[j+1] = tmp
            }
        }
    }
}
//test
func main()
{
    var nums = []int{7, 8, 11, 4, 9, 3, 15}
    fmt.Println("nums before insertSort:%s", nums)
    bubbleSort(nums)
    fmt.Println("nums after insertSort:%s", nums)
}

快速排序

原理阐述:分而治之
实现步骤:

  • 先从数列中取出一个数作为基准数。
  • 分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
  • 再对左右区间重复第二步,直到各区间只有一个数(各个区间都为有序)
import (
    "fmt"
)
//快速排序
func quickSort(nums []int, start int, end int) {
    //结束条件
    if start >= end {
        return
    }
    tmp := nums[start] //选择第一个数为分区标志
    left := start
    right := end
    //调整结构
    for left < right {
        for tmp < nums[right] && left < right {
            right = right - 1
        }
        //here,tmp<=nums[right]  ---> tmp == nums[left]
        nums[left] = nums[right]
        //now, nums[right] is empty
        for tmp > nums[left] && left < right {
            left = left + 1
        }
        //here, tmp >=nums[left]    ---> tmp = nums[right]
        nums[right] = nums[left]
        //now, nums[left] is empty
    }
    nums[left] = tmp

    quickSort(nums, start, left-1) //left array sort
    quickSort(nums, left+1, end)   //right array sort
}

//test
func main()
{
    var nums = []int{7, 8, 11, 4, 9, 3, 15}
    fmt.Println("nums before insertSort:%s", nums)
    quickSort(nums, 0, lens(nums))
    fmt.Println("nums after insertSort:%s", nums)
}

合并排序

原理阐述:分而治之
实现步骤:

  • 将数组对分至若干有序数组(数组元素为一个的数组为有序数组)
  • 将有序数组逐次两两合并为有序数组,直至合并为一个数组
import (
    "fmt"
)
//合并排序
func mergeSort(nums []int, start int, boundce int, end int) {
    if start >= end { //结束边界
        return
    }
    mergeSort(nums, start, start+(boundce-start)/2, boundce) //数组拆分前半部分
    mergeSort(nums, boundce+1, boundce+(end-boundce)/2, end) //数组拆分后半部分
    var tmp = make([]int, end-start+1, end-start+1)
    i := 0
    //拷贝数组
    for i <= end-start {
        tmp[i] = nums[i+start]
        i = i + 1
    }
    //数组合并过程
    i = 0                                      //左半部分数组的起始地址
    j := boundce - start + 1                   //右半部分的起始地址
    ii := start                                //终选数组的起始地址
    for i <= boundce-start && j <= end-start { //结束条件
        /*在左半部分选取较小元素填充目标数组*/
        for i <= boundce-start && tmp[i] <= tmp[j] {
            nums[ii] = tmp[i]
            ii = ii + 1
            i = i + 1
        }
        //here --> tmp[i] > tmp[j]
        /*在右半部分选取较小数据填充目标数组*/
        for j <= end-start && tmp[j] <= tmp[i] {
            nums[ii] = tmp[j]
            ii = ii + 1
            j = j + 1
        }
    }
    //结束判断
    //左数组先结束
    if i == boundce-start+1 {
        for j <= end-start {
            nums[ii] = tmp[j]
            ii = ii + 1
            j = j + 1
        }
    }
    //右数组先结束
    if j == end-start+1 {
        for i <= boundce-start {
            nums[ii] = tmp[i]
            ii = ii + 1
            i = i + 1
        }
    }
}

//test
func main()
{
    var nums = []int{7, 8, 11, 4, 9, 3, 15}
    fmt.Println("nums before insertSort:%s", nums)
    mergeSort(nums, 0, len(nums)/2-1, len(nums)-1)
    fmt.Println("nums after insertSort:%s", nums)
}

堆排序

原理
堆排序的几个操作: 1. 建堆 2. 堆调整 3. 堆排序
具体原理参见《白话经典算法系列之七 堆与堆排序》

package main

import (
    "fmt"
)
//调整方式:当父节点的数据变化时,子节点的数据必须做相应调整
//2*n + 1 左子节点, 2*n + 2 右子节点
func adjust(nums []int, pos int, len int) {
    tmp := pos
    j := 2*pos + 1
    for j < len {
        //寻找较大子节点
        if j+1 < len {
            if nums[j+1] > nums[j] {
                j++
            }
            if nums[tmp] < nums[j] {
                nums[tmp], nums[j] = nums[j], nums[tmp]
            }
        } else {
            if nums[tmp] < nums[j] {
                nums[tmp], nums[j] = nums[j], nums[tmp]
            }
        }
        //遍历此节点的子节点,调整
        tmp = j
        j = j*2 + 1
    }
}

//建立堆栈
func buildHeap(nums []int) {
    len := len(nums)
    for i := len/2 - 1; i >= 0; i-- { //可以理解为先为子树构建“堆”,再在子树“堆”上构建父堆, len/2 为第一个非叶子节点,叶子节点肯定是“堆”
        adjust(nums, i, len) //每次都为全局调整
    }
}

/**
* 堆排序
*/
func heapSort(nums []int) {
    tmp := len(nums)
    if tmp == 0 {
        return
    }
    buildHeap(nums)
    for i := 0; i < len(nums); i++ {
        nums[tmp-1], nums[0] = nums[0], nums[tmp-1] //提取堆顶
        tmp--
        adjust(nums, 0, tmp) //数组尾部是已经排序部分,不再做调整
    }
}

//test
func main() {
    var nums = []int{7, 8, 11, 4, 9, 3, 15}
    fmt.Println("nums before insertSort:%s", nums)
    heapSort(nums)
    fmt.Println("nums after insertSort:%s", nums)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值