维基百科:http://zh.wikipedia.org/wiki/插入排序
算法思想:
若数组A[n]的前n-1个数已经有序,我们只需把第n个元素插入到适当的位置即可。易分析得算法的时间复杂度为Ο(n^2)
具体描述:
- 从第一个元素开始,该元素可以认为已经被排序
- 取出下一个元素,在已经排序的元素序列中从后向前扫描
- 如果该元素(已排序)大于新元素,将该元素移到下一位置
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
- 将新元素插入到该位置后
- 重复步骤2~5
如果比较操作的代价比交换操作大的话,可以采用二分查找法来减少比较操作的数目。该算法可以认为是插入排序的一个变种,称为二分查找排序。
一、简单插入排序(simple insertion sort)
#include <cstdlib>
#include <iostream>
using namespace std;
//iterative implementation
template<class T>
void simpleInsertionSort(T *a, int n)
{
T temp;
int j;
for(int i=1; i<n; i++)
{
temp = a[i];
j = i-1;
while(j >= 0 && a[j] > temp)
{
a[j+1] = a[j];
j--;
}
a[j+1] = temp; //put a[i] to right place
}
}
//recursive implementation
template<class T>
void insertionSort(T *a ,int n)
{
if(n>1)
{
insertionSort(a,n-1); //sort the first n-1 elements recursively
insert(a,n); //insert a[n-1] in a[0..n-2]
}
}
/* n the size of the array
* assume the first n-1 elements is already sorted
*/
template<class T>
void insert(T *a, int n)
{
T temp = a[n-1];
int i = n-2;
while(i >= 0 && a[i] > temp)
{
a[i+1] = a[i];
i--;
}
a[i+1] = temp;
}
int main(int argc, char *argv[])
{
int n;
int *a = NULL;
while(cin>>n && n > 0)
{
a = new int[n];
for(int i=0; i<n; i++)
{
cin>>a[i];
}
//simpleInsertionSort(a,n);
insertionSort(a,n);
for(int i=0; i<n; i++)
{
cout<<a[i]<<" ";
}
cout<<endl<<endl;
delete [] a;
}
system("PAUSE");
return EXIT_SUCCESS;
}
二、二分查找排序(binary search sort)
template<class T>
void binarySearchSort(T *a, int n)
{
T temp;
int low ,mid,high;
for(int i=1; i<n; i++)
{
temp = a[i]; //暂存记录
low = 0;
high = i-1;
while(low <= high) //寻找插入点
{
mid = (low + high)/2;
if(temp < a[mid])
high = mid - 1; //插入点在低半区间
else
low = mid + 1; //插入点在高半区间
}
//high+1为插入点
for(int k=i-1; k>=high+1; k--)//记录后移
{
a[k+1] = a[k];
}
a[high+1] = temp;//插入到适当位置
}
}
注意:
1、虽然折半查找减少了比较次数,但是没有减少移动次数,因而折半插入排序的算法时间复杂度仍为Ο(n^2)
2、折半插入,插入点的确定:
(1)考虑特殊情况,当区间[0,i]恰好是有序的,此时插入点应该为i,即high+1,因为high==i-1
(2)对于折半插入,我们就是要在[0,i-1]之间寻找一个有效的插入点k,使得a[k-1]<=a[i]<a[k],即保证插入是稳定的。
(3)由于搜索区间是以2倍的速度不断递减,必然会有某一时刻出现:low == mid == high的情况,此时分两种情况:
a、若temp <a[mid],插入点在左边区间:high = mid-1;接着由于循环条件low<=high不满足而结束循环,此时temp 刚好比a[low]小,也就是说应该插入在low处。且满足low == mid == high+1
b、若temp>=a[mid],插入点在右边区间:low = mid +1;同样循环结束,此时temp刚好应该插入high点之后,且满足mid == high ==low-1
(4)综合两种情况,插入点都应该为high+1
参考书籍:
[1]《数据结构(C语言版)》严蔚敏
[2]《算法导论》第2版,潘金贵译