插入排序的过程和平时打牌的时候给手里的牌排序差不多:
参考动画:visualgo.net
#include <algorithm>
#include <utility>
/**
* 对范围[first, last)的元素进行插入排序
* @param first 双向迭代器开头
* @param last 双向迭代器结尾
* @param comp 比较函数
*/
template<typename BidirectionalIterator, typename Compare>
void insertionSort(BidirectionalIterator first, BidirectionalIterator last, Compare comp) {
if (first != last) {
// [first, sortedEnd)表示目前已经排好序的范围
for (auto sortedEnd = first; ++sortedEnd != last;) {
if (comp(*sortedEnd, *first)) {
// 当前元素val应该排在第一位
auto val = std::move(*sortedEnd);
auto next = sortedEnd;
std::move_backward(first, sortedEnd, ++next);
*first = std::move(val);
} else {
// prev表示当前元素val所在正确位置的前一个位置
auto prev = sortedEnd;
--prev;
auto next = sortedEnd;
auto val = std::move(*sortedEnd);
while (comp(val, *prev)) {
*next = std::move(*prev);
next = prev;
--prev;
}
*next = std::move(val);
}
}
}
}
对于排序算法而言,它并不会关心自己处理的数据具体代表什么,而只关心数据之间的大小关系。所以对于任意一组数据,都可以将里面的元素抽象成其在整组数据里面的大小排名(rank)。简单起见,这里假设所有元素大小均不相同,于是任一组数据便可对应于集合\(\pi=\{1,2,3,\cdots,n\}\)的一种排列。
然后引入逆序对(invertion pair)的概念:
定义:在数列\(A[1\ldots n]\)中若存在下标\(1\leq i<j\leq n\)使得 A[i]>A[j] ,则称\((A[i],A[j])\)为一个逆序对。数列中逆序对的总数为逆序数
显然数组的逆序数能很好地描述该数组的无序程度。而且不难看出的是一组数据的逆序数刚好就是插入排序需要执行的比较移动操纵的次数。因为在进行元素的插入时,每一次比较出元素该再往前一步时,随着较大的元素后移一步恰好就修复了一个逆序对。
期望值\(E(X)\)求解过程:
令随机变量
则
很明显\((A[i],A[j])\)是逆序对的概率是\(\frac{1}{2}\),所以期望也是\(\frac{1}{2}\)
原文:https://www.cnblogs.com/HachikoT/p/13832155.html