常见的排序方法简介以及Go实现
常见排序方法汇总
相关概念
- 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。
- 非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。
- 稳定排序:如果 a 原本在 b 的前面,且 a == b,排序之后 a 仍然在 b 的前面,则为稳定排序。
- 非稳定排序:如果 a 原本在 b 的前面,且 a == b,排序之后 a 可能不在 b 的前面,则为非稳定排序。
- 原地排序:原地排序就是指在排序过程中不申请多余的存储空间,只利用原来存储待排数据的存储空间进行比较和交换的数据排序。
- 非原地排序:需要利用额外的数组来辅助排序。
- 时间复杂度:一个算法执行所消耗的时间。
- 空间复杂度:运行完一个算法所需的内存大小
排序方法思路及其实现
插入排序(稳定)
思路:对于arr[i]
,在前面有序数组中找到对应的位置插入,然后把插入位置后面的数字平移一位。
func InsertSort(nums []int) {
for i := 1; i < len(nums); i++ {
cur := nums[i]
j := i - 1
for ; j >= 0 && nums[j] > cur; j-- {
nums[j + 1] = nums[j]
}
nums[j + 1] = cur
}
}
冒泡排序(稳定)
思路:不断比较相邻的数字,大的数字就往后靠,如果前面的比较大就交换位置,然后指向下一个比较位置,直至到最后排好序的序列前截止
func BubbleSort(nums []int) {
for i := len(nums) - 1; i > 0; i-- {
flag := true
for j := 0; j < i; j++ {
if nums[j] > nums[j + 1] {
nums[j], nums[j + 1] = nums[j + 1], nums[j]
flag = false
}
}
if flag {
return
}
}
}
归并排序(稳定)
思路 :归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。
func MergeSort(nums []int, left, right int) {
if left < right {
mid := (right - left) / 2 + left
MergeSort(nums, left, mid)
MergeSort(nums, mid + 1, right)
merge(nums, left, mid, right)
}