插入排序算是排序算法中最简单的一种了,实现起来也是比较简单的。算法的复杂度为O(N2),虽然复杂度比较高,但这并不意味着其它复杂度低的排序算法(并、
快排等)在任意的输入序列下其性能都比插入排序来得好。其原因主要有以下两点:
-
复杂度都是对足够大的N来说的,对于较小的N插入排序的比较次数可能更少。
-
受算法的实现程度而定,实现得好的插入排序有可能比实现得差的快排等更高效。算法实现得不好有可能是算法编写者在实现算法时没有处理好一些细节而导致时间空间的浪费,又或者是对所使用的语言理解不够深入,没有利用好语言的特性。
因此插入排序作为一个实现起来比较容易的算法来讲,它对实现者的编程素养没有太高的要求,因为代码量比较少。而且对于较小的N来说其优势也很明显。事实
上,在实际的快排实现中,当N小于某个值时就可直接利用插入排序来对待排数组进行排序,而不是继续的利用快排递归下去。这个值通常可取为10。
所谓插入排序就是假定待排数组A前面的0到j-1个元素已经排好序了,而将第j个元素插入到前面元素的某个位置k,使得A[k-1] <= A[k] < A[k+1](这里忽略了边界情况,且以非降序排列)。下面是一个插入排序的c++实现:
#include
template < typename Comparable >
void insertion_sort( std::vector< Comparable > & array, int begin, int end ) {
for( int i = begin + 1; i <= end; ++i ) {
for( int j = i; j > 0; --j ) {
if( array[ j - 1 ] > array[ j ] ) {
std::swap( array[ j ], array[ j - 1 ] );
}
else
break;
}
}
}
上面的代码可以进一步优化,因为std::swap包含三个赋值语句,没必要在内部循环里执行那么多赋值操作,因此优化后的代码如下:
#include
template < typename Comparable >
void insertion_sort( std::vector< Comparable > & array, int begin, int end ) {
for( int i = begin + 1; i <= end; ++i ) {
Comparable temp = array[ i ];
for( int j = i; j > 0; --j ) {
if( array[ j - 1 ] > temp ) {
array[ j ] = array[ j - 1 ];
}
else
break;
}
array[ j ] = temp;
}
}
我们可以先把待插入的元素保存起来,这样在循环内部就只需要一条赋值语句,最后再将该值插入到恰当的位置。