先声明:所有的排序我都会总结记录在博客里,最后会有一个大的cpp文件包含全部排序的代码,每个排序算法放在单独的一个namespace里面,清晰明了,并设计对数器给出测试。我会把它放到网盘供需要之人下载,见这里。 ps:所有的排序以升序为基准。测试编译器为Visual C++
插入排序思想:假设[0, i - 1]位置有序,将 i 位置元素插入到前面有序数组中适当的位置。一直到最后一趟,[0, n - 2]位置有序,将 n -1 位置元素插入进去即可。
插入排序:我们拆词,”插入“,如何理解”插入“这个词?理解了就简单了。
插入排序属于比较类的排序。
插入排序是稳定的。
最简单的demo:
template<typename T>
inline void swap(T* arr, size_t lhs, size_t rhs) { // size_t是unsigned int的typedef
T tmp(arr[lhs]);
arr[lhs] = arr[rhs];
arr[rhs] = tmp;
}
template<typename T>
void insertsort(T* arr, size_t size) {
if (size <= 0)
return;
for (size_t i = 1; i < size; ++i) {
for (size_t j = i; j >= 1; --j) {
if (arr[j] < arr[j - 1]) {
swap(arr, j, j - 1);
}
}
}
}
上面这个是最简单的实现,有很多可以改进的地方。
假设 [0, i - 1]有序,现在需要把 i 位置元素插入到前面有序数组的适当位置;
-
上面代码是一直与前一个比较交换、比较交换,能不能先一直比较,直到找到正确位置,再最后交换一次即可呢?copy可是很费时的一个操作。
-
[0, i - 1]有序呢,“有序”,能二分查找(binary search)?
上面都是可以实现的。
第1点的代码:
template<typename T>
void insertsort(T* arr, size_t size) {
if (size <= 0)
return;
for (size_t i = 1; i < size; ++i) {
T temp(arr[i]);
size_t j = 0;
for (j = i - 1; j >= 0; --j) {
if (temp < arr[j]) {
arr[j + 1] = arr[j];
}
else {
break;
}
}
arr[j + 1] = temp;
}
}
第2点的代码:没贴出来,读者可以自己实现。二分查找的变种。
二分虽说简单,但是要写出来还是没那么容易的,《编程珠玑》书中作者谈到,在美国一所大学授课的时候,作者要求学生在纸上写出二分查找的代码,只要20%的人能够真正让作者满意,“纸上谈兵”可不是一个好事。
结果:
有个问题:这里我就用了这么简单一个例子,肯定说明不了这个算法是正确的。
可以设计对数器去判断,冒泡排序肯定是不会写错的,用随机生成的数组(元素随机,每个数组元素 个数也随机)去同时跑冒泡和待比较的排序算法,跑100000次,如果一次都没有出错,基本上可以证明待验证算法的正确性了。
平均时间复杂度 O(N^2)。
最好时间复杂度:正序,只需比较 N - 1 次,O(N)。
最差时间复杂度:逆序,O(N^2)。
空间复杂度都是 O(1)。
纸上得来终觉浅,绝知此事要躬行。