Go语言学习之排序算法(快速、堆、希尔)|Go主题月

302 阅读2分钟

作者:看那个码农

公众号:看那个码农

上期内容介绍了Go语言学习之排序算法(选择、插入、冒泡)|Go主题月

  • 选择排序
  • 插入排序
  • 冒泡排序

本篇内容将继续带领大家走进Go语言的世界。

1.本文简介

Go语言学习之排序算法(快速、堆、希尔)

2.快速排序

快速排序是一种高效的排序算法,基本思想把大的数组拆分成小的,小的再拆分成更小的。

其原理如下

对于一组给定的数据,选择数据中的一个值做为支点,通过一轮排序后,将原数组拆分为两个部分,把大于支点的元素放在右边,小于支点的元素放在左边(升序)然后再依次对前后两部分的记录进行快速排序,递归该过程。直到序列中的所有记录均有序为止。

以数组[5,3,7,0,1,4,2]为例,说明一下快速排序的过程。

  • 第一步选择中间的值3做为支点,(基准值可以任意设置,但是选择中间值比较容易理解)此时数组变为5,[3],7,0,1,4,2

  • 第二步按照顺序,将每个元素与支点相比较,形成两个部分,一个是小于“3”的[0,1,2]另外一个是大于“3”的[5,7,4]

  • 第三步对[0,1,2]与[5,7,4]两个部分不断重复第一步与第二步,直到只剩下一个元素为止

  • 此时左边部分已经部分划分后就已经排序好了,所以这部分可以不用管了

  • 所以我们来看看支点右边部分的值[5,7,4],设置5为这部分的分支点,对这部分进行划分,左边比支点5小,右边比支点5大

  • 最后形成[4],5,[7]的形式

  • 支点3的左部分和右部分已经排序好,最后输出出来即可。

具体代码如下:

package main

import (
   "fmt"
)

func sort(array []int,low,high int){
   if(low>=high){return}
   i:=low
   j:=high

   var index int
   index = array[i]
   for i<j{
      for i<j && array[j]>=index{
         j--
      }
      if i<j {
         array[i]=array[j]
         i++
      }
      for i<j&&array[i]<index{
         i++
      }
      if(i<j){
         array[j]=array[i]
         j--
      }
   }
   array[i]=index
   sort(array,low,i-1)
   sort(array,i+1,high)
}

func Quick(array []int)  {
   sort(array,0,len(array)-1)
}

func main(){
   array:=[]int{1,5,3,8,0}
   Quick(array)
   fmt.Printf("{1,5,3,8,0}快速排序的输出为:%v",array)
}

输出为

image.png

3.希尔排序

基本原理如下:

  • 首先将待排序的数组元素分成多个子序列,使得每个子序列的元素个数相对较少。
  • 然后对每个子序列分贝进行直接插入排序,待整个待排序序列“基本有序”后。
  • 最后再对所有元素进行一次直接插入排序。

以数组[13,14,94,33,82,25,59,94,65,23,45,27,73,25,39,10]为例,说明一下希尔排序的过程。

如果我们以步长为5开始进行排序,我们可以通过将这列表放在有5列的表中来更好地描述算法,这样他们就应该看起来是这样:

13 14 94 33 82
25 59 94 65 23
45 27 73 25 39
10

然后我们对每列进行排序:

10 14 73 25 23
13 27 94 33 39
25 59 94 65 82
45

將上述四行数字,依序接在一起时

我们得到:

[10,14,73,25,23,13,27,94,33,39,25,59,94,65,82,45]

这时10已经移至正确位置了,然后再以3为步长进行排序:

10 14 73
25 23 13
27 94 33
39 25 59
94 65 82
45

排序之后变为:

10 14 13
25 23 33
27 25 59
39 65 73
45 94 82
94

最后以1步长进行排序(此时就是简单的插入排序了)。

具体代码如下:

package main

import (
   "fmt"
)

func shell(array []int){
   
   llen:=len(array)
   for h:=llen/2;h>0;h=h/2{
      for i:=h;i<llen;i++{
         temp:=array[i]
         var j int
         for j=i-h;j>=0;j-=h{
            if(temp<array[j]){
               array[j+h]=array[j]
            } else{
               break
            }
         }
         array[j+h]=temp
      }
   }

}
func main(){
   array:=[]int{10,14,73,25,23,13,27,94,33,39,25,59,94,65,82,45}
   shell(array)
   fmt.Printf("{10,14,73,25,23,13,27,94,33,39,25,59,94,65,82,45}\n希尔排序的输出为:\n%v",array)

输出为

image.png

4.堆排序

堆排序是指利用堆这种数据结构所设计的一种排序算法。堆是一种特殊的树形数据结构,其每个结点都有一个值,通常提到的提到的堆都是指一颗完全的二叉树,根节点的值小于(或大于)两个子节点的值,同时,根节点的两个子树也分别是一个堆。

堆排序可以说是一种利用堆的概念来排序的选择排序。

堆排序分为两种方法:

  • 大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;

image.png

  • 小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列;

image.png

堆排序主要有两个过程

  • 创建堆
  • 不断交换堆顶元素与最后一个元素的位置

5.快速、堆、希尔的算法性能对比

排序方法最好时间平均时间辅助存储稳定性
快速排序O(nlogn)O(nlogn)O(logn)不稳定
堆排序O(nlogn)O(nlogn)O(1)不稳定
希尔排序O(n)O(nlogn)O(1)不稳定

如果你觉得这篇内容对你有帮助的话:

1、点赞支持下吧,让更多的人也能看到这篇内容

2、关注公众号:看那个码农,我们一起学习一起进步。

本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情