排序算法-插入排序
插入排序(升序排序为例)
- 思路:
-
- 将序列分为两个部分,头部已经排好的和后面待排序的
-
- 从头部开始遍历每一个元素,然后插入头部已排好序的恰当位置
-
class InsertionSort {
var array = [5, 7, 2, 8, 9, 4, 7, 3, 2]
// 使用二分搜索优化插入排序
/**
因为头部序列有序,可以用二分搜索快速定位到r待插入元素的最终位置
*/
func sort() {
for begin in 1 ..< array.count {
// 备份要插入的函数
let value = array[begin]
// 用二分搜索找到插入位置
let dest = search(index: begin)
// 将要插入的位置到插入元素原始位置之间的d元素向后挪动1位
for i in stride(from: begin, to: dest, by: -1) {
array[i] = array[i - 1]
}
// 将元素插入准确位置
array[dest] = value
}
}
private func search(index: Int) -> Int {
var begin = 0
var end = index
while begin < end {
let mid = (begin + end) >> 1
if array[index] < array[mid] {
end = mid
} else {
begin = mid + 1
}
}
return begin
}
// 优化版插入排序
/**
思路:将 交换 --> 挪动
1. 先将待插入的元素备份
2. 头部有序数据中比待插入元素大的,都朝尾部方向挪动1位
3. 将待插入的元素放到最终的位置
*/
func sort2() {
for begin in 1 ..< array.count {
var current = begin
let value = array[current]
while current > 0, value < array[current - 1] {
array[current] = array[current - 1]
current -= 1
}
array[current] = value
}
}
// 基础版插入排序
func sort1() {
// 没必要从第0个元素开始,可以从第一个元素开始
for begin in 1 ..< array.count {
var current = begin
while current > 0, array[current] < array[current - 1] {
let tmp = array[current]
array[current] = array[current - 1]
array[current - 1] = tmp
current -= 1
}
}
}
}
最坏、平均时间复杂度: O(n^2), 最好时间复杂度:O(n)
空间复杂度: O(1)
稳定性: 稳定排序
- 上述代码中函数 sort1 是基本插入排序的算法
插入排序的最坏和平均时间复杂度达到O(n^2)是与逆序对的数量有关,逆序对数量g越多,时间的复杂度越高
何为逆序对? 如数组: [3, 5, 8, 4, 1],y逆序对有 (3, 1) (5, 4) (5, 1) (8, 1) (4, 1),共5个逆序对
函数 sort2 做了简单优化
函数 sort 根据二分查找快速定位要插入的位置,相较 sort2 在比较次数上做了优化