“排序是计算机的核心内容。事实上,从很多方面看,如果没有排序,计算机就不会变成现实。”《算法之美:指导工作与生活的算法》
算法
|
最坏运行时间
|
平均运行时间
|
是否稳定
|
原址排序
|
插入排序
|
Θ(n^2)
|
Θ(n^2)
|
是
|
是
|
归并排序
|
Θ(nlgn)
|
Θ(nlgn)
|
是
|
否
|
堆排序
|
O(nlgn)
|
----
|
否
|
是
|
快速排序
|
Θ(n^2)
|
Θ(nlgn)
|
否
|
是
|
计数排序
|
Θ(n+k)
|
Θ(n+k)
|
是
|
否
|
基数排序
|
Θ(d(n+k))
|
Θ(d(n+k))
|
是
|
否
|
桶排序
|
Θ(n^2)
|
Θ(n)
|
是
|
否
|
|
|
|
|
|
1. 插入排序
-
黄色代表尚未实现排序的元素
-
绿色代表已经排序好的元素
-
每一轮循环确定一个元素的位置
-
箭头代表元素之间的比较,如果比较发现左边的元素大于右边的该元素,则两个位置进行交换,如果小於则退出本轮循环
func insertSort(arr []int){
size := len(arr)
if size == 0 || size == 1{
return
}
for j:=1;j<=size-1;j++{
current := j
for i:=j-1;i>=0;i--{
if arr[current] < arr[i] {
arr[current], arr[i] = arr[i],arr[current]
current = i
}else{
break
}
}
}
}
2. 归并排序
-
分解: 将待排序的n个元素序列切分为两个n/2的子序列
-
解决: 使用同样的算法归并排序递归排序两个子序列
-
合并: 合并两个已经排序的子序列用以差生已排序的答案
func mergeSort(arr []int) []int{
size := len(arr)
if size < 2 {
return arr
}
left := mergeSort(arr[0:size/2])
right := mergeSort(arr[size/2:])
leftSize := len(left)
rightSize := len(right)
i := 0
j := 0
var result []int
for i < leftSize && j <rightSize{
if left[i] < right[j]{
result = append(result, left[i])
i++
}else{
result = append(result, right[j])
j++
}
}
if i < leftSize {
result = append(result, left[i:]...)
}else if j < rightSize{
result = append(result, right[j:]...)
}
return result
}
3. 堆排序
-
构建堆结构(Build), 从一个普通数组转换为具有堆性质的数组
-
维护堆结构(Heapify),只是针对其中一个节点,保持节点以及子树为一个堆的过程,用于维护堆的性质(大顶或小顶),时间复杂度为O(logn)
-
堆排序(HeapSort): 对一个数组实现其原址排序。
-
我们选择处理的元素为1
-
由于元素1的两个子元素为8和3,均大于1,我们选择最大8与当前的元素1进行交换
-
交换完成后元素1下移到8的位置。
-
比较元素1和新的两个子元素,继续重复相同的流程,直到当前的节点满足大顶的要求
func heapify(arr []int,size int , index int){
left := 2 * index
right := 2 * index +1
max := index-1
if size >= left && arr[max] < arr [left-1]{
max = left-1
}
if size >= right && arr[max] < arr[right-1]{
max = right-1
}
if max != index-1 {
arr[max], arr[index-1] = arr[index-1], arr[max]
heapify(arr, size, max+1)
}
}
func heapSort(arr []int){
size := len(arr)
for i:= size/2; i>=1; i--{
heapify(arr,size, i)
}
lenOfArr := size
for i:=size-1; i >=1 ;i--{
arr[i], arr[0] = arr[0], arr[i]
heapify(arr,lenOfArr-1, 1)
lenOfArr--
}
}
4. 快速排序算法
-
分解: 数组划分为两个子数组,其中左数组中所有元素都小于等于Arr[x], 右数组中所有元素都大于等于Arr[x], x为开始选择的其中一个元素索引。
-
解决: 通过递归调用快速排序,对于其左数组和右数组进行不断的切分和排序
-
合并: 子数组为原址排序,因此本身就已经是排序好的,无需类似于归并排序一样的合并操作。
func quickSort(a []int) []int{
size := len(a)
if size < 2 {
return a
}
left, right := 0, size-1
for i:=0; i< size-1; i++{
if a[i] < a[right]{
a[left], a[i] = a[i], a[left]
left++
}
}
a[left], a[right] = a[right], a[left]
quickSort(a[:left])
quickSort(a[left+1:])
return a
}
func quickSort(a []int) []int{
size := len(a)
if size < 2 {
return a
}
left, right := 0, size-1
pivot := rand.Int() % size
a[pivot], a[right] = a[right], a[pivot]
for i:=0; i< size-1; i++{
if a[i] < a[right]{
a[left], a[i] = a[i], a[left]
left++
}
}
a[left], a[right] = a[right], a[left]
quickSort(a[:left])
quickSort(a[left+1:])
return a
}
5. 计数排序算法
-
初始化一个[0..k]的计数数组,用于存储n个数中每个不同的数出现的次数
-
循环迭代n数组中的元素,并统计每个数的个数进行累加
-
最后循环计数数组产生输出结果
func countSort(arr []int, max int) []int{
size := len(arr)
if size < 2 {
return arr
}
countArr := make([]int, max+1)
result := make([]int, len(arr))
for _, v := range arr{
countArr[v]++
}
for i:=1; i< max+1 ;i ++{
countArr[i] = countArr[i-1]+countArr[i]
}
for i:=size-1;i>=0;i--{
result[countArr[arr[i]]-1] =arr[i]
countArr[arr[i]]--
}
return result
}
6. 基数排序算法
- 第一次排序的时候仅仅排序个位数上的数组,形成排序结果。
- 第二次排序在上一次排序基础上再对于十位数上数字进行排序,
- 最后一次排序对于百位数进行排序。我们排序完成后可以看到整个的排序已经完成了。
func radixSort(arr []int)[]int {
largestNum := findLargestNum(arr)
size := len(arr)
significantDigit := 1
semiSorted := make([]int, size, size)
for largestNum / significantDigit > 0 {
bucket := [10]int{0}
for i := 0; i < size; i++ {
bucket[(arr[i] / significantDigit) % 10]++
}
for i := 1; i < 10; i++ {
bucket[i] += bucket[i - 1]
}
for i := size - 1; i >= 0; i-- {
bucket[(arr[i] / significantDigit) % 10]--
semiSorted[bucket[(arr[i] / significantDigit) % 10]] = arr[i]
}
for i := 0; i < size; i++ {
arr[i] = semiSorted[i]
}
significantDigit *= 10
}
return arr
}
7. 桶排序算法
func bucketSort(arr []float64){
buckets := make([][]float64,10)
for _, v := range arr{
bucketIndex := int(v * 10) % 10
buckets[bucketIndex]= append(buckets[bucketIndex], v)
}
for _ , bucket := range buckets{
sort.Float64s(bucket)
}
currentIndex := 0
for _, bucket := range buckets{
for _, v := range bucket{
arr[currentIndex] = v
currentIndex++
}
}
}