参考的:blog.csdn.net/qq_34411783…
还有DeepSeek
1. 简单三兄弟:插入、冒泡、选择
平均时间复杂度:
空间复杂度:
只有选择不稳
1.1 插入排序
右侧数组已经有序,新元素插入到有序数组中对应位置。
动图去看文章置顶博客。
稳定吗?稳定!每次插入,遇到相等的,直接放在后面,就可以实现稳定。
代码:
func InsertSort(nums []int) {
n := len(nums)
for i := 1; i < n; i++ {
cur := nums[i]
j := i - 1
for j >= 0 && nums[j] > cur {
nums[j+1] = nums[j]
j--
}
// 结束循环后,nums[j]一定是小于等于cur的,所以j+1
nums[j+1] = cur
}
}
1.2 冒泡
稳定吗?稳定,等于的时候不交换,就稳定。
func BubbleSort(a []int) {
n := len(a)
for i := 0; i < n - 1; i++ {
swaped := false
for j := 0; j + 1 < n - i; j++ {
if a[j] > a[j+1] {
a[j], a[j+1] = a[j+1], a[j]
swaped = true
}
}
if !swaped {
break
}
}
}
1.3 选择
选择排序不稳定!记住这个【5 8 5 2 9】
func SelectSort(a []int) {
n := len(a)
for i := 0; i < n - 1; i++ {
minIdx := i
for j := i + 1; j < n; j++ {
if a[j] < a[minIdx] {
minIdx = j
}
}
a[i], a[minIdx] = a[minIdx], a[i]
}
}
2. 速度三兄弟:快排、堆排、归并
2.1 快排
func sortArray(nums []int) []int {
quickSort(nums, 0, len(nums)-1)
return nums
}
func quickSort(a []int, l, r int) {
if l >= r {
return
}
i, j, p := l, r, a[l]
for i < j {
for i < j && a[j] >= p {
j--
}
for i < j && a[i] <= p {
i++
}
a[i], a[j] = a[j], a[i]
}
a[i], a[l] = a[l], a[i]
quickSort(a, l, i-1)
quickSort(a, i+1, r)
}
2.2 堆排
思路
下沉操作
- 必须: 左子树是大根堆, 右子树也是大根堆. 对root节点调用sink一次, 可以让以root为根节点的树也变成大根堆.
- 具体做法: 根节点和左右孩子中较大的交换. 递归这个过程. 直到根节点是最大的.
构建大根堆
- 叶子结点是大根堆.
- 从最后一个非叶子结点开始, 从下往上构建.
利用大根堆排序
- 每次把「堆顶」的节点与数组最后一个节点交换, 然后重新构造大根堆. 重复这一过程直到数组有序.
代码
func sortArray(nums []int) []int {
heapSort(nums)
return nums
}
func heapSort(arr []int) {
end := len(arr)-1
// 从最后一个非叶子节点开始, 构建大根堆
for i := end/2; i >= 0; i-- {
sink(arr, i, end)
}
// 把最大的放到数组最后, 然后重新构建大根堆
for i := end; i >= 0; i-- {
arr[0], arr[i] = arr[i], arr[0]
end--
sink(arr, 0, end)
}
}
// 大根堆的下沉操作
func sink(arr []int, root, end int) {
for {
leftChild := root*2+1
if leftChild > end {
break
}
rightChild := leftChild+1
larger := leftChild
// 找到左右孩子中较大的
if rightChild <= end && arr[rightChild] > arr[leftChild] {
larger = rightChild
}
// root最大, 就结束. 因为构建是从下往上的
if arr[root] > arr[larger] {
break
}
// root与较大的交换
arr[root], arr[larger] = arr[larger], arr[root]
// 继续下沉
root = larger
}
}
2.3 归并
归并是我的老朋友了。
func sortArray(nums []int) []int {
return proc(nums, 0, len(nums)-1)
}
// proc 我采用的是左闭右闭,实践证明,可行
func proc(nums []int, l, r int) []int {
if l == r {
return nums[l:l+1]
}
mid := (l + r) / 2
left := proc(nums, l, mid)
right := proc(nums, mid+1, r)
return merge(left, right)
}
// merge 上来先写一个
func merge(a, b []int) []int {
lenA, lenB := len(a), len(b)
c := make([]int, lenA + lenB)
i, j, k := 0, 0, 0
for i < lenA && j < lenB {
if a[i] < b[j] {
c[k] = a[i]
i++
} else {
c[k] = b[j]
j++
}
k++
}
for i < lenA {
c[k] = a[i]
i++
k++
}
for j < lenB {
c[k] = b[j]
j++
k++
}
return c
}