稳定:排序不改变相等元素的相对位置关系;如a=b,a原本在b前面,排序后a任然在b后面。
不稳定:排序可能改变相等元素的相对位置关系;如a=b,a原本在b前面,排序后a可能在b后面。
内排序:所有排序都在内存中完成。
外排序:数据太大,因此把数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行。
n:数据规模。
k:“桶”个数。
In-place:占用常数内存,不占用额外内存。
Out-place:占用额外内存。
冒泡排序
算法描述:
比较相邻元素并交换。
每次都会将最大的元素放到正确的位置。
一共要进行n-1
趟比较。
最好情况:o(n)
最坏情况: o ( n 2 ) o(n^2) o(n2)
平均情况: o ( n 2 ) o(n^2) o(n2)
func BubbleSort(input []int) []int {
n := len(input)
for i := 0; i < n-1; i++ {
for j := 0; j < n-1-i; j++ {
if input[j] > input[j+1] {
input[j], input[j+1] = input[j+1], input[j]
}
}
}
return input
}
选择排序
算法描述:
从当前元素开始,找到最小的元素与当前元素交换。
选择最小的与第一个元素交换,选择次小的与第二个元素交换…
一共需要比较n-1
趟。
最稳定的排序算法之一,无论什么数据都是 o ( n 2 ) o(n^2) o(n2)的时间复杂度,数据规模越小越好。
最佳、最坏、平均都是: o ( n 2 ) o(n^2) o(n2)
func SelectSort(input []int) []int {
n, min := len(input), 0
for i := 0; i < n; i++ {
min = i
for j := i+1; j < n; j++ {
if input[j] < input[min] {
min = j
}
}
input[i], input[min] = input[min], input[i]
}
return input
}
冒泡排序和选择排序都是在做交换。
插入排序
算法描述:
以当前元素为基准,向前扫描,比当前元素大的都向后移动一位,遇到比当前元素小的就把它放到这个元素后面。
也就是当前元素之前都是有序的,然后将当前元素插入到有序集合的适当位置。
需要比较n-1
趟。
需要o(1)的额外空间。
最好情况:o(n)
最坏情况: o ( n 2 ) o(n^2) o(n2)
平均情况: o ( n 2 ) o(n^2) o(n2)
func InsertSort(input []int) []int {
n, cur, index := len(input), 0, 0
for i := 1; i < n; i++ {
cur, index = input[i], i - 1
for index >= 0 && input[index] > cur {
input[index+1] = input[index]
index--
}
input[index+1] = cur
}
return input
}
插入排序是在做移动。
希尔排序(缩小增量排序)
算法描述:
首先选择一个间隔(gap)对数据进行分组,[i, i+gap, i+2×gap, i+3×gap…]
为一组,共分为gap组;
分别对每一组进行选择排序;
缩小间隔gap,重复上述过程,直到gap = 1;
gap的取法,每次取gap = gap/2;或每次取gap = gap/3 + 1
希尔排序也是一种插入排序
func ShellSort(input []int) []int {
n := len(input)
for gap := n / 2; gap > 0; gap /= 2 {
for i := gap; i < n; i++ {
cur, j := input[i], i-gap
for j >= 0 && input[j] > cur {
input[j+gap] = input[j]
j -= gap
}
input[j+gap] = cur
}
}
return input
}
归并排序
算法描述:
将原数组拆成两个序列然后归并
递归的进行
需要额外的空间
func MergeSort(input []int) []int {
n := len(input)
if n < 2 {
return input
}
mid := n / 2
left, right := input[0:mid], input[mid:]
return merge(MergeSort(left), MergeSort(right))
}
func merge(left, right []int) (output []int) {
for i, j := 0, 0; i < len(left) || j < len(right); {
if i >= len(left) {
output = append(output, right[j])
j++
} else if j >= len(right) {
output = append(output, left[i])
i++
} else if left[i] < right[j] {
output = append(output, left[i])
i++
} else {
output = append(output, right[j])
j++
}
}
return
}
快速排序
算法描述:
每次找一个基准数,将大于基准数的元素放到基准数右边,小于基准数的元素放到基准数左边,这一趟下来就相当于是把基准数放到它应该在的位置上。
具体来说,首先选择最左边的元素作为基准,然后j从最后一个元素开始向后找比基准小的数,i从第一个元素开始找比基准大的数,然后将它们交换,每次必须j先行动!
如果i、j相遇就将它与基准交换,这样基准就在正确的位置上了,然后以基准为界,左右两边分别同样处理。
func QuickSort(input []int, left, right int) []int {
if left < right {
index := left + 1
for i := index; i <= right; i++ {
if input[i] < input[left] {
input[i], input[index] = input[index], input[i]
index++
}
}
input[left], input[index-1] = input[index-1], input[left]
QuickSort(input, left, index-2)
QuickSort(input, index, right)
}
return input
}
堆排序
算法描述:
用数组构建一个堆,然后依次删除堆顶元素组成有序数组。
func HeapSort(input []int) (output []int) {
h := heap.NewMinHeap(input...)
for !h.Empty() {
if data, err := h.Get(); err == nil {
output = append(output, data)
}
}
return
}
计数排序
算法描述:
将每个元素作为下标映射到数组,数组中存的是下标对应数字出现的次数
适合大量重复且范围有限的数组
稳定排序算法,时间复杂度和空间复杂度都是o(n+k),速度快于任何比较排序算法
func CountSort(input []int) (output []int) {
max := input[0]
for i := range input {
if input[i] > max {
max = input[i]
}
}
bucket := make([]int, max+1, max+1)
for _, v := range input {
bucket[v]++
}
for i := range bucket {
for bucket[i] > 0 {
output = append(output, i)
bucket[i]--
}
}
return
}
桶排序
算法描述:
定义一定数量的空桶,每个桶表示一个范围,gap=(max-min)/桶数+1
将数据装到对应范围的桶中,下标=(num-min)/gap
对非空桶内的数据排序
最好情况下为o(n)时间复杂度,主要取决于桶内数据排序的时间复杂度
桶划分的越小,桶内数据越少,时间越短,空间消耗越大
func BucketSort(input []int) (output []int) {
min, max, size := input[0], input[0], len(input)/2
for _, v := range input {
if v < min {
min = v
}
if v > max {
max = v
}
}
gap := (max-min)/size + 1
bucket := make([][]int, size, size)
for _, v := range input {
index := (v - min) / gap
bucket[index] = append(bucket[index], v)
}
for i := 0; i < size; i++ {
if len(bucket[i]) > 0 {
bucket[i] = InsertSort(bucket[i])
}
}
for i := 0; i < size; i++ {
output = append(output, bucket[i]...)
}
return
}
基数排序
算法描述:
先按个位大小排序,再按十位大小排序,依次直到最高位
相当于各个位的优先级是不同的,先按低优先级排序,再按高优先级排序,最后就是高优先级在低优先级之前,高优先级相同的,低优先级高的在前
以各个位为基准进行计数排序,直到最高位
func RadixSort(input []int) []int {
max := input[0]
for _, v := range input {
if v > max {
max = v
}
}
bits := len(strconv.Itoa(max))
bucket := make([][]int, 10, 10)
for i, mod := 0, 1; i < bits; i, mod = i+1, mod*10 {
for _, v := range input {
index := v / mod % 10
bucket[index] = append(bucket[index], v)
}
pos := 0
for j := 0; j < 10; j++ {
for len(bucket[j]) > 0 {
input[pos] = bucket[j][0]
bucket[j] = bucket[j][1:]
pos++
}
}
}
return input
}