1.插入排序
func insertSort(arr []int) {
// 将数组分为已经排序好的区间[0, bound), 和未排序好的区间[bound,length]
for i := 0; i < len(arr); i++ {
end := i-1
cur := arr[i]
// 如果遇到了比cur大的元素就需要往后搬
for end >= 0 && arr[end] > cur {
arr[end+1] = arr[end]
end--
}
arr[end+1] = cur
}
}
时间复杂度O(n^2)
空间复杂度O(1)
2. 希尔排序
希尔排序就是将插入排序多分了几个组, 对每个组都使用插入排序
常常使用的gap = len(arr)/2, 之后再依次除以2
func insertSortWithGap(arr []int, gap int) {
for i := 0; i < len(arr); i++ {
end := i-gap
cur := arr[i]
for end >= 0 && arr[end] > cur {
arr[end+gap] = arr[end]
end -= gap
}
arr[end+gap] = cur
}
}
func shellSort(arr []int) {
// 如果会插入排序那么希尔排序也就会, 希尔排序就是将插入排序分堆利用gap来分组块
// 常用的gap就是长度依次除2
gap := len(arr)/2
for gap > 0 {
insertSortWithGap(arr, gap)
gap /= 2
}
}
3. 选择排序
将当前下标先看做最小值, 然后依次从[i, len(arr)-1]的位置找到一个最小值的下标
func selectSort(arr []int) {
if arr == nil || len(arr) < 2 {
return
}
// 每次定义一个position, 用来找到后面的数组中的最小值
for i := 0; i < len(arr)-1; i++ {
// 以本次的i为下标先当做最小的元素
position := i
for j := position+1; j < len(arr); j++ {
if arr[j] < arr[position] {
position = j
}
}
arr[i], arr[position] = arr[position], arr[i]
}
}
O(n^2)
O(1) 常数级变量
还有一种可以改进的选择排序思想, 就是在找最小值的下标时, 同时找到最大值的下标与最后的元素交换, 这样就可以减少循环的次数
4 .堆排序
堆排和快排是两个最重要的排序也是面试中考的最多的, 一定要动手实现几次,
想要练习堆排, 建议可以去做力扣215题
func heapSort(arr []int) {
size := len(arr)
createHeap(arr, size)
for i := len(arr)-1 ; i >= 0; i-- {
arr[0], arr[i] = arr[i], arr[0]
size--
shiftDown(arr, 0, size)
}
}
func createHeap(arr []int, size int) {
// 堆排序的核心思想就是, 先建立一个大跟堆, 再依次将数组第一个元素和最后一个元素交换, 直至堆的大小0
// 从第一个非叶子结点开始建堆
root := (len(arr)-1-1) >> 1 // size == len(arr) size-1是最后一个元素的下标, 那么他的父亲结点就是 parent = (size-1-1)/2
for ; root >= 0; root-- {
// 依次按照每一个节点向下调整
shiftDown(arr, root, size)
}
}
func shiftDown(arr []int, parent int, size int) {
// 首先找到左孩子
child := parent*2 + 1
for child < size {
// 一直向下调整
// 判断左子树和右子数哪个大
if child+1 < size && arr[child] < arr[child+1] {
child += 1
}
// 判断父亲的值和孩子的值哪个大, 大了的话 就需要交换
if arr[parent] < arr[child] {
arr[parent], arr[child] = arr[child], arr[parent]
}else {
// 不需要交换直接break
break
}
parent = child
child = 2*parent +1
}
}
时间复杂度O(n*logn)
空间O(1)(忽略递归使用的栈空间)