Table of Contents generated with DocToc
所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作
基本概念
- 稳定:如果 A 原本在 B 前面,而 A=B,排序之后 A 仍然在 B 的前面。
- 不稳定:如果 A 原本在 B 的前面,而 A=B,排序之后 A 可能会出现在 B 的后面。
- 内排序:所有排序操作都在内存中完成。
- 外排序:由于数据太大,因此把数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行。
稳定性:如果a=b,并且a在b的前面,排序后a一定在b的前面,那么称算法是稳定的,如果不一定在前面,那么称算法是不稳定的
序号 排序算法 时间复杂度(平均) 时间复杂度(最坏) 时间复杂度(最优) 空间复杂度 稳定性
1 冒泡排序 O(𝑛2) O(𝑛2) O(𝑛) O(1) 稳定
2 快速排序 O(nlogn) O(𝑛2) O(nlogn) O(nlogn)~O(n) 不稳定
3 插入排序 O(𝑛2) O(𝑛2) O(𝑛) O(1) 稳定
4 希尔排序 O(nlogn)~O(𝑛2) O(𝑛2) O(𝑛1.3) O(1) 不稳定
5 选择排序 O(𝑛2) O(𝑛2) O(𝑛2) O(1) 稳定
6 堆排序 O(nlogn) O(nlogn) O(nlogn) O(1) 不稳定
7 归并排序 O(nlogn) O(nlogn) O(nlogn) O(n) 稳定
8 计数排序 O(n+k) O(n+k) O(n+k) O(k) 稳定
9 桶排序 O(n+k) O(𝑛2) O(𝑛2) O(n+k) 稳定
10 基数排序 O(n*k)] O(n*k) O(n*k) O(n+k) 稳定
对于未排序数据,在已排序序列由后向前扫描,找到相应位置并插入。如 玩纸牌
func insertionSort(arr []int) {
for i := 1; i < len(arr); i++ {
current := arr[i]
preIndex := i - 1
for ; preIndex >= 0 && current < arr[preIndex]; preIndex-- {
arr[preIndex+1] = arr[preIndex]
}
arr[preIndex+1] = current
}
}
是插入排序的优化版
// 希尔排序:是不稳定排序,时间复杂度:O(nlogn),空间复杂度:O(1)
// 常见的增量序列:
// 1.最初Donald Shell提出的增量,即折半降低直到1。据研究,使用希尔增量,其时间复杂度还是O(n2)。
// 2.Hibbard增量:{1, 3, ..., 2k-1},该增量序列的时间复杂度大约是O(n1.5)。
// 3.Sedgewick增量:(1, 5, 19, 41, 109,...),其生成序列或者是94i - 92i + 1或者是4i - 3*2i + 1。
func shellSort(data []int) {
size := len(data)
if size <= 1 {
return
}
for delta := size/2; delta >= 1; delta/=2 {
for i := delta; i < size; i++ {
for j := i; j >= delta && data[j] < data[j-delta]; j-=delta {
data[j], data[j-delta] = data[j-delta], data[j]
}
}
}
}
选择排序(Selection Sort)是一种简单直观的排序算法。它的工作原理是:首先在序列中找到最小元素,放在序列的首位,然后再从剩下的序列中寻找最小元素,放到已排序序列的末尾。
func selectionSort(arr []int) {
for i := 0; i < len(arr); i++ {
min := i
for j := i + 1; j < len(arr); j++ {
if arr[j] < arr[min] {
min = j
}
}
arr[min], arr[i] = arr[i], arr[min]
}
}
步骤
func mergeSort(nums []int, start,end int) {
if start < end {
mid := (start+end)/2
mergeSort(nums,start,mid) // 左边排序
mergeSort(nums,mid+1,end) // 右边排序
merge(nums,start,mid,end) // 合并数组
}
}
func merge(nums []int, start, mid, end int) {
i,j := start,mid+1
ret := []int{}
for i <= mid && j <= end {
if nums[i] <= nums[j] {
ret = append(ret, nums[i])
i++
} else {
ret = append(ret, nums[j])
j++
}
}
ret = append(ret, nums[i:mid+1]...)
ret = append(ret, nums[j:end+1]...)
for k, v := range ret {
nums[start+k] = v
}
}
是插入排序的优化版,算法过程:
- 找出待排序的数组中最大和最小的元素
- 统计数组中每个值i出现的次数,存入计数数组的第i项
- 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1