输入:N个数,<a1,a2,a3,a4....an>
输出:输出序列为一个有序排列<b1,b2,b3....bn> (b1 <= b2<=b3....<=bn 或者 b1>=b2>=b3...>=bn>
要求:在过程中,这N个数存储在长度为N的数组A[n]中,并且只允许有常数个数字储存在数组之外,也就是说对这N个数实现就地排序。下边的算法以升序为例介绍。
算法:假设我们现在有一个排好序的数组,现在需要将一个元素插入到这个排好序的数组中,那么我们需要找到这个要插入的位置,然后依次的将数据进行移动。插入排序正是用到了这种思想。一个元素必定是有序的,那么我们选取关键元素(即要插入有序数组的当前元素)为第二个元素,即key=A[1];此时我们要比较key与A[0]的大小,来确定key需要插入到A[0]的位置还是A[1]的位置,如果key比A[0]大的话,那么要实现升序就应当将其放置在A[1]的位置;反之,就应当位于A[0]的位置。下一次插入就要选取key为第三个元素......依照此规则,直到插入完毕这中间的所有元素为止。
代码:
/*插入排序
输入:n个数<a1,a2,a3...an>
输出:一个新排列<a1',a2',...an'>
要求:数据存放在一个数组中,在排列的过程中,至多有常数个数据存储在数组外,
当排好之后,所有数字都存放在数组中。
时间:2014年4月20日
*/
#include<iostream>
using namespace std;
void insertSort(int A[],int n)
{
int j;
int i;
int key;
for(j=1;j<n;j++)
{
if(A[j]< A [j-1])
{
key = A[j];
i = j-1;
while(i >=0 && A[i]>key)
{
A[i+1]=A[i];
i--;
}
A[i+1]=key;
}
}
}
int main()
{
cout <<"您将为几个整数进行排序?"<<endl;
int n;
cin >> n;
int * A = new int[n];
cout<<"输入数组"<<endl;
for(int i = 0 ;i < n ;i++)
{
cin >> A[i];
}
//int A[6] = {2,3,34,2,18,1};
insertSort(A,n);
int i;
for(i = 0;i<n;i++)
{
cout << A[i]<<" ";
}
delete A[];
return 0;
}
A[6]=(38,47,65,11,22,33)
第一趟:key = 38
47和38比较不用移动
第二趟:key = 38
65和47比较不用移动
第三趟:key = 11
11 38 47 65
第四趟:key = 22
11 22 38 47 65
第五趟:key = 33
11 22 33 38 47 65
直接插入排序算法简洁,容易实现,那么它的效率如何呢?
首先从看见上来看,只需要多增加一个保存记录的空间,可以另外设置一个变量来保存或者直接在数组中增加一个哨兵元素A[0]使其直接等于目标排序元素即可。
从时间来看,排序的关键就是关键字的大小和移动记录。最好的情况就是数组已经按照顺序排列好,那么即可实现0次移动以及n-1次比较。最坏的情况就是倒序,第i躺要比较i-1次要移动i-1个单元。
综合最好和最坏的情况,直接插入排序算法的时间复杂度为O(N^2)。
在进行插入排序时,除了逐个查找位置之外还可以采用折半查找找位置,这样可以减少比较的次数但是并不能减少移动的次数,不能减少时间复杂度。若想要减少移动次序,则要考虑K-路插入排序即与归并排序方法类似,建立多个辅助数组,然后分别排序之后,进行有序数组的归并。