版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yang731227/article/details/85061419
title: Go数据结构与算法-希尔排序
tags: go,算法
介绍
希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
- 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率;
- 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位;
基本思想
先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
算法复杂度
一般来说时间复杂度为:O(Nlog2N)
排序过程
希尔排序是插入排序的优化版本,同属于插入类排序。优化:插入排序只能比较相邻元素,大距离移动元素开销大,比如 [1, 2, 3, 4, 0]
中把 0 挪到第一位就需要交换四次。
希尔排序是将跨步的分组进行组内排序,使数组在大体上基本有序(小元素在前,大元素在后),当步长减少到 1 时无序元素将极少。“步长” 是希尔排序的特性。
[UNSORTED]: [4 1 3 0 2]
[DEBUG step]: 2
[DEBUG]: [3 1 4 0 2] # 4 3 -> 3 4
[DEBUG]: [3 0 4 1 2] # 1 0 -> 0 1
[DEBUG]: [2 0 3 1 4] # 4 2 -> 2 4 # 2 3 4 与 0 1 均有序
[DEBUG step]: 1
[DEBUG]: [0 2 3 1 4] # 2 0 -> 0 2
[DEBUG]: [0 2 3 1 4]
[DEBUG]: [0 1 2 3 4] # 2 3 1 -> 1 2 3
[DEBUG]: [0 1 2 3 4] # step == 0 排序完毕
[SORTED]: [0 1 2 3 4]
实用场景
若初始步长不是 1,希尔排序就比插入排序快,选取适当步长效率更高。和插入排序一样,适用于小数据量、或基本有序的大数据量集合,实际上因为效率常常会使用快排代替希尔排序。
演示
package main
import (
"algorithms"
"fmt"
)
func main() {
arr := algorithms.GetArr(5, 20)
//arr = []int{4, 1, 3, 0, 2}
fmt.Println("[UNSORTED]: ", arr)
n := len(arr)
if n <= 1 {
fmt.Println("[ALREADY SORTED]: ", arr)
return
}
step := n / 2
// 步长减少到 0 则排序完毕
for step > 0 {
fmt.Println("[DEBUG step]: ", step)
// 遍历第一个步长区间之后的所有元素
for i := step; i < n; i++ {
j := i
// 前一个元素更大则交换值
// j >= step // 避免向下越界
for j >= step && arr[j-step] > arr[j] {
arr[j-step], arr[j] = arr[j], arr[j-step]
j -= step
}
fmt.Println("[DEBUG]: ", arr)
}
step /= 2
}
fmt.Println("[SORTED]: ", arr)
}