关于排序
通常所说的排序是指内部排序,即在内存里进行排序。相对应的有外部排序,当待排序数据比较多时,排序过程需要使用闪存。
排序算法大体可分为两种:
一种是比较排序,时间复杂度O(nlogn) ~ O(n^2),主要有:冒泡排序,选择排序,插入排序,归并排序,堆排序,快速排序等。
另一种是非比较排序,时间复杂度可以达到O(n),主要有:计数排序,基数排序,桶排序等。
排序算法稳定性说明:如果待排序序列A中两个元素相等,即Ai = Aj,排序前Ai在Aj之前,排序后Ai还在Aj之前,则称这种排序算法是稳定的。就是保证排序前后两个相等的元素的相对顺序不变
以下为各算法的时间复杂度等对比
排序 | 平均 | 最优 | 最差 | 辅助空间 | 是否稳定 |
冒泡排序 | O(n2) | O(n) | O(n2) | O(1) | 稳定 |
简单选择排序 | O(n2) | O(n2) | O(n2) | O(1) | 不稳定 |
直接插入排序 | O(n2) | O(n) | O(n2) | O(1) | 稳定 |
快速排序 | O(nlogn) | O(nlogn) | O(n2) | O(logn)-O(n) | 不稳定 |
希尔排序 | O(nlogn)-O(n2) | O(n1.3) | O(n2) | O(1) | 不稳定 |
归并排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | 稳定 |
堆排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | 不稳定 |
一些共用方法
main包用来执行,myAlgo包为具体方法实现
//以下为共用方法
//交换两个元素位置
package myAlgo
func exchange(arr []int, a int, b int) {
temp := arr[a]
arr[a] = arr[b]
arr[b] = temp
}
//返回序列最小值下标
func selectMin(arr []int, i int) int {
length := len(arr)
minKey := i
minValue := arr[minKey]
//从下标为i及之后的元素中找出值最小的元素
for k := minKey + 1; k < length; k++ {
if minValue > arr[k] {
//修改下标
minKey = k
minValue = arr[k]
}
}
return minKey
}
1、冒泡排序
冒泡排序算法运行方式如下:
假设待排序序列有n个元素
第一次循环
1.从首元素开始比较相邻的元素,如果顺序不对,就把它们两个调换位置,直至最后一个,此时可以保证最后一个元素是最大的(或最小的)
2.重复以上操作,每次循环都可以将无序序列(序列无序元素数量每次循环后都在减少)最大(最小)的一个元素移至最右边,所以第k次循环后前n-k个元素是无序的,后k个元素是有序且依次递增(递减)的
示意图
package main
import (
"fmt"
"myAlgo"
)
func main() {
arr := []int{15, 45, 42, 25, 20, 63, 23, 20, 29, 100, 9}
myALgo.BubbleSort(arr);
}
package myAlgo
import "fmt"
func bubbleSort(arr []int) {
length := len(arr)
for j := length - 1; j > 0; j-- {
//外层循环控制循环次数
for i := 0; i < j; i++ {
//内层循环控制交换
if arr[i] > arr[i+1] {
//交换顺序
exchange(arr, i, i+1)
}
}
fmt.Println(arr)
}
}
结果如下
2、简单选择排序
思路如下:
1.首先,找到序列中最小的那个元素,将它和第一个元素交换位置。
2.在剩下的元素中找到最小元素,将它与序列的第二个元素交换位置
3.按照以上方式如此往复,直至将整个序列排序。
因为它在不断的选择剩余元素之中的最小者,所以叫选择排序。
示意图
go实现
package main
import "fmt"
func main() {
arr := []int{15, 45, 42, 25, 20, 63, 23, 20, 29, 100, 9}
fmt.Println(arr)
myAlgo.SelectSort(arr)
}
package myAlgo
import "fmt"
func SelectSort(arr []int) {
fmt.Println("开始排序")
length := len(arr)
for i := 0; i < length; i++ {
//每循环一次都找出当前未排序元素中的最小值,和当前元素进行交换
minKey := selectMin(arr, i)
exchange(arr, i, minKey)
}
fmt.Println(arr)
}
执行结果
3、直接插入排序
这个类似于玩扑克牌,一张一张的将牌拿出来插到部分已经有序序列中的合适位置,具体如下:
1.第一个元素可以看成是有序的
2.从有序序列下一个元素开始,用这个元素a从后向前,依次和有序序列元素b进行比较,如果元素a小于元素b,则将元素a插入到元素b之前,原有序序列b之后的元素均向后移动一个位置,此时生成一个新的有序序列。
3.重复操作2
示意图
go实现
package main
import (
"fmt"
"myAlgo"
)
func main() {
arr := []int{15, 45, 42, 25, 20, 63, 23, 20, 29, 100, 9}
fmt.Println(arr)
myAlgo.InsertSort(arr)
}
package myAlgo
import "fmt"
func InsertSort(arr []int) {
fmt.Println("开始排序")
//获取当前数组长度
length := len(arr)
for i := 1; i < length; i++ {
//当前值
now := arr[i]
//如果当前元素小于之前序列中的某一个元素的值,则序列从此元素向后整体移动一位
for j := i - 1; j >= 0; j-- {
if now < arr[j] {
arr[j+1] = arr[j]
arr[j] = now
} else {
arr[j+1] = now
break
}
}
fmt.Println(arr)
}
}
运行结果
快速排序
算法原理:
将未排序元素根据一个作为基准的“主元”(Pivot)分为两个子序列,其中一个子序列的记录均大于主元,而另一个子序列均小于主元,然后递归地对这两个 子序列用类似的方法进行排序。本质上,快速排序使用分治法,将问题的规模减小,然后再分别进行处理。
示意图
go实现
package main
import (
"fmt"
"myAlgo"
)
func main() {
arr := []int{40, 45, 42, 25, 20, 63, 23, 20, 50, 29, 100, 9}
fmt.Println(arr)
myAlgo.QuickSort(arr, 0, len(arr) - 1)
}
package myAlgo
import "fmt"
func QuickSort(arr []int, left int, right int) {
//设置基准数,选择第一个作为基准数
baseKey := left
baseValue := arr[baseKey]
fmt.Println("当前序列", arr[left:right+1],"基准值为",baseValue)
fmt.Println("开始排序")
i := left
j := right
for i < j {
//先从右向左找,直到找到一个小于基准数的值
for (arr[j] >= baseValue) && (i < j) {
j--
}
if i < j {
//将j的值放到i的空位上
arr[i] = arr[j]
}
//从左向右找,直到找到一个大于基准数的值
for (i < j) && (arr[i] < baseValue) {
i++
}
if i < j {
//将此时的i放到之前j产生的空位上
arr[j] = arr[i]
}
fmt.Println(arr[left:right+1])
}
arr[i] = baseValue
fmt.Println("子序列结果", arr[left:right+1])
fmt.Println("总序列", arr)
fmt.Println("--------------------")
if left < i-1 {
QuickSort(arr, left, i-1)
}
if i+1 < right {
QuickSort(arr, i+1, right)
}
}
运行结果
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。