一、算法思想
在已形成的有序表中折半查找,并在适当位置插入,把原来位置上的元素向后顺移。
二、算法过程
其中,红色部分是已形成的有序表,黑色部分是待排序元素
三、实现
void insertSort(int R[],int n) //待排关键字存储在R[]中,个数为n
{
int i,j;
int temp;
int mid;
int low;
int high;
for(i=1;i<n;i++) // 由于第一个元素不需要比较,故从第二个元素开始执行插入
{
mid;
low=0;
high=i-1; // 0到i-1是已经排序好的部分
temp=R[i]; // 用于存储待排序的关键字
while(low<=high)
{
mid=(low+high)/2;
if(temp<R[mid])
high=mid-1; // 插入点在低半区
else
low=mid+1; // 插入点在高半区
}
for(j=i-1;j>=high+1;j--) //high+1相当于mid,i-1是已排序序列的最高点,记录后移
{
R[j+1]=R[j];
}
R[high+1]=temp; // 插入
}
}
四、算法性能分析
(1)时间复杂度分析
无论什么情况,外部循环始终逐一执行,外部循环次数为n。
内部循环分为两个部分:一个是折半比较元素的循环,一个是元素移动的循环。
折半插入排序的关键字比较次数和初始序列无关,其折半次数是固定的(都是在low>high时结束),折半次数为 log n。因此,我们要讨论元素移动的时间复杂度。
-
考虑最坏的情况,即整个序列都是逆序的,则内层循环的元素移动需要逐一执行,因此内部循环次数为 log n + n,故总循环次数为 n( log n + n ),其算法复杂度是 O(n^2)
-
考虑最好的情况,即整个序列都是顺序的,则内层循环的元素移动不需要执行,因此内部循环次数为 log n + 0,故总循环次数为 n( log n ),其算法复杂度是 O(nlog n)
-
对于平均的情况,其算法复杂度是 O(n^2)
(2)空间复杂度分析
算法所需要的辅助存储空间不随待排序列的规模的变化而变化,是个常量,因此空间复杂度为 O(1)
(3)稳定性
若两个记录A和B的关键字值相等,A先插入,B后插入,此时排序后A、B的先后次序保持不变,因此称此排序算法是稳定的。