文章目录
1. 插入排序
1.1 基本思想
有N个数据data[N],从头到尾扫描数据data[i],将数据data[i]插入到前面已经排好序的data[0] — data[i-1]的合适位置处,即完成data[0] — data[i]的数据排序,直到数据末尾,结束排序。
1.2 分类
根据确定插入位置时选择的方法不同,可以分为直接插入排序,二分(折半)插入排序,希尔排序。
1.2.1 直接插入排序
基本思想
在确定插入位置时,利用顺序法确定插入位置。
代码实现
template<typename RanIt, typename Pr>
void InsertSort(const RanIt first, const RanIt last, Pr pred) {
typedef typename std::iterator_traits<RanIt>::value_type ValueType;
typedef typename std::iterator_traits<RanIt>::difference_type DiffType;
DiffType maxDiff = last - first;
for (DiffType i = 1; i < maxDiff; ++i) {
ValueType current = *(first + i);
DiffType j = i - 1;
for (; j >= 0 && pred(current, *(first + j)); --j) {
*(first + j + 1) = *(first + j);
}
*(first + 1 + j) = current;
}
}
template<typename RanIt>
void InsertSort(const RanIt first, const RanIt last) {
InsertSort(first, last, std::less<>());
}
性能分析
- 当所要比较的数据已经是排好序时,为该算法最好情况。时间复杂度 O(n)。
- 当所要比较的数据是逆序排好序时,为算法最差情况。时间复杂度 O(n2)。
- 原始数据越接近有序,排序速度越快
- 时间复杂度:min = O(n); max = O(n2); ave = O(n2)
- 空间复杂度:O(1),需要一个哨兵位置,原地排序。
- 是一种稳定的排序方法。
1.2.2 二分(折半)插入排序
基本思想
- 在确定插入位置时,利用二分法确定插入位置。
代码实现
template<typename RanIt, typename Pr>
void binarySearchSort(RanIt first, RanIt last, Pr pred){
typedef typename std::iterator_traits<RanIt>::value_type ValueType;
typedef typename std::iterator_traits<RanIt>::difference_type DiffType;
DiffType maxDiff = last - first;
for (DiffType i = 1; i < maxDiff; ++i){
ValueType current = *(first + i);
DiffType left = 0, right = i - 1, mid;
//binary search
while (left <= right){
mid = (left + right) / 2;
if(pred(*(first + mid), current)){
left = mid + 1;
}
else{
right = mid - 1;
}
}
for(DiffType j = i - 1; j >= left; --j){
*(first + 1 + j) = *(first + j);
}
*(first + left) = current;
}
}
template<typename RanIt>
void binarySearchSort(RanIt first, RanIt last){
binarySearchSort(first, last, std::less<>());