golang冒泡、选择、插入、快速、堆、奇偶、归并、希尔 排序思路和代码
- 冒泡排序算法
func BubbleSort(arr []int) {
// 最外层的循环表示循环几轮
for i := 0; i < len(arr); i++ {
// 内侧是循环几次,注意比较的时候索引越界
// 所以我们在比较的时候只需要走到数组长度的前一个
// 因为内侧比较的时候已经加1
// 所以倒数第二个也会倒数第一个数据作比较
for j := 0; j < len(arr)-1; j++ {
// 如果数组内的数据不满足条件就交换
if arr[j] > arr[j+1] {
arr[j], arr[j+1] = arr[j+1], arr[j]
}
}
}
}
- 选择排序法
func SelectSortData(arr []int) {
// 最外侧也是循环几轮
for i := 0; i < len(arr); i++ {
// 因为全部都要比较,选择数组的第一个下标为最小的数字
min := i
// 自己和自己比较没有意义,所以让前一个和后一个比较
for j := i + 1; j < len(arr); j++ {
if arr[min] > arr[j] {
min = j
}
}
// 如果一轮比较完了,最小的小标在循环内被修改过了
// 说明还不是最小的下标,
// 就要交换他俩索引上的数据
if min != i {
arr[min], arr[i] = arr[i], arr[min]
}
}
}
- 插入排序法
// 下边的思想是升序,数据从后往前移
// 每轮指移动一个数据
func InsertSort(arr []int) {
// 第一轮如果从0开始,满足不了第二个循环的条件,所以下标直接开始是1
for i := 1; i < len(arr); i++ {
backup := arr[i] // 开始先备份第二个数字
// 然后让备份的数据和前一个数据比较
j := i - 1
// 下标是有效的索引且要往前移动的数据必须小于前面的数据
for j >= 0 && backup < arr[j] {
// 让后面的数据复制为前面的数据
arr[j+1] = arr[j]
// 然后让数据继续往前走,
j--
}
// 如果数据不满足上边的循环条件,那就是前一个数据刚好是合适的位置
arr[j+1] = backup
}
}
- 快速排序法
// 快速排序法就是选择一个数据,
// 然后按照这个数据把这堆数据分为三类
// 比自己小、等于自己的、比自己大的,然后递归调用,最后把数据拼接到一起
// 但是递归调用数量大的时候避免击穿,可以改为伪递归,伪递归自行百度
func QuickSort(arr []int) []int {
// 既然要递归调用就要找好出口
// 数据长度再剩下1个或者小于一个的时候就开始返回
if len(arr) <= 1 {
return arr
}
capData := arr[0]
gt := []int{}
lt := []int{}
mid := []int{capData} //自己肯定等于自己,就不用从0开始比较了
for i := 1; i < len(arr); i++ {
if capData > arr[i] {
lt = append(lt, arr[i])
} else if capData < arr[i] {
gt = append(gt, arr[i])
} else {
mid = append(mid, arr[i])
}
}
// 递归调用,然后重组数据并返回新的数组
lt, gt = QuickSort(lt), QuickSort(gt)
sorted := append(append(lt, mid...), gt...)
return sorted
}
- 堆排序算法
// 可以想象成一个二叉树,从最外层的节点开始比较
// 拿到每个节点的叶子数据的方法是:左节点(叶子):2*i+1 右节点(叶子):2*i+2
// 所以遍历的形式就是由树的底层向根节点遍历
// 根节点你可以理解为是数组下标为0的数据
// 拿到最大值后根节点的值和最后一个叶子节点的值交换
// 让长度不断的缩小数组的长度,然后不断的交换
// 每次把重新缩短的数组头的数据和头尾的数据交换沉底
// 还要防止数组越界,因为有肯能这个节点只有左子树没有右子树
func HeapSort(arr []int) []int {
lenght := len(arr)
for i := 0; i < lenght; i++ {
lastLen := lenght - i
HeapSortMax(arr, lastLen)
if i < lenght {
arr[0], arr[lastLen-1] = arr[lastLen-1], arr[0]
}
}
return arr
}
func HeapSortMax(arr []int, lenght int) []int {
depth := lenght/2 - 1
for i := depth; i >= 0; i-- {
topMax := i // 节点顶部的元素
leftchild := 2*i + 1 // 左子树
rightchild := 2*i + 2 // 右子树
if leftchild <= lenght-1 && arr[leftchild] > arr[topMax] { // 如果左子树没有越界或者节点上的数据大于根节点的数据,需要交换,相等的不需要交换,永远让根节点最大
topMax = leftchild
}
if rightchild <= lenght-1 && arr[rightchild] > arr[topMax] {
topMax = rightchild
}
if topMax != i {// 如果判断过后根节点的下标和原来的不一样,说明根节点的数据不是最大,需要交换
arr[i], arr[topMax] = arr[topMax], arr[i]
}
}
return arr
}
- 奇偶排序
func OddEven(arr []int) []int {
isSorted := false
for isSorted == false {// 当数据还需要排序的时候就是false
isSorted = true // 如果数据不需要排序了就是true,数据就不会走到俩个循环中的if条件中,那最终就不会再进入这个外层的循环
for i := 1; i < len(arr)-1; i += 2 {
if arr[i] > arr[i+1] {
arr[i], arr[i+1] = arr[i+1], arr[i]
isSorted = false
}
}
for i := 0; i < len(arr)-1; i += 2 {
if arr[i] > arr[i+1] {
arr[i], arr[i+1] = arr[i+1], arr[i]
isSorted = false
}
}
}
return arr
}
- 归并排序
// 归并的思想是分而治之,就是经常面试中问到排序一个大于内存的数据的时候就可以使用当前的归并思想,
// 分开数据递归排序,然后合并到一起
func MergerSort(arr []int) []int {
if len(arr) <= 1 {
return arr
}
lenght := len(arr)
mid := lenght / 2
leftarr := MergerSort(arr[:mid])
rightarr := MergerSort(arr[mid:])
return merger(leftarr, rightarr)
}
// 左边的数据和右边的数据比较,哪边的小就把哪边的数据放入一个新的切片中,相等的数据都需要放入新的切片中,然后让索引往后移动
// 如果俩边的数据长度不相等,一个数据的索引已经走到数组的最大长度了,就把剩余另外一边的数据都添加到新的数组当中,因为我们在外边已经递归的排好序了,所以可以放心的加入
// 然后把新的数组返回给原来的数组,这里的数组是切片,如果你使用的数组的话记得返回指针,要不然你的数据特别大的时候返回数组做的是数据的备份,就会特别慢
func merger(left []int, right []int) []int {
leftIndex := 0
rightIndex := 0
lastArr := []int{}
for leftIndex < len(left) && rightIndex < len(right) {
if left[leftIndex] < right[rightIndex] {
lastArr = append(lastArr, left[leftIndex])
leftIndex++
} else if left[leftIndex] > right[rightIndex] {
lastArr = append(lastArr, right[rightIndex])
rightIndex++
} else {
lastArr = append(lastArr, left[leftIndex])
lastArr = append(lastArr, right[rightIndex])
leftIndex++
rightIndex++
}
}
if leftIndex < len(left) {
lastArr = append(lastArr, left[leftIndex:]...)
}
if rightIndex < len(right) {
lastArr = append(lastArr, right[rightIndex:]...)
}
return lastArr
}
- 希尔排序
func ShellSort(arr []int) {
// tmp := 0
// 刚开始每俩个分为一组,然后在继续除以2再分组
for gap := len(arr) / 2; gap > 0; gap /= 2 {
//然后分为组后需要执行几轮
for i := gap; i < len(arr); i++ {
// 再然后是遍历每一轮的元素
for j := i - gap; j >= 0; j -= gap {
if arr[j] > arr[j+gap] {
// tmp = arr[j]
arr[j], arr[j+gap] = arr[j+gap], arr[j]
}
}
}
}
}
- 基数排序
package main
import "fmt"
func main() {
var arr [3][]int
myarr := []int{1, 2, 3, 1, 1, 2, 2, 2, 2, 2, 3}
// 可以看家基数排序法是典型的以空间换时间的算法,大家可以把arr打印出来看看,就是把相同的数据放到一个桶里,最终你需要把每个桶里的数据一遍一遍的拿出来放进去
for i := 0; i < len(myarr); i++ {
arr[myarr[i]-1] = append(arr[myarr[i]-1], myarr[i])
}
fmt.Println(arr)// [[1 1 1] [2 2 2 2 2 2] [3 3]]
}
__EOF__

本文作者:从零单排
本文链接:https://www.cnblogs.com/baixiaoyong/p/16051129.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
本文链接:https://www.cnblogs.com/baixiaoyong/p/16051129.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通