排序——插入排序

(一) 插入排序
1. 直接插入排序(insert sorting)
基本思想: 当插入第i (i≥1) 个元素时,前面的V[0], V[1], …, V[i-1]已经排好序。这时,用V[i]的排序码与V[i-1], V[i-2], …的排序码顺序进行比较,找到插入位置即将V[i]插入,原来位置上的元素向后顺移。
时间复杂度:O(n^2)
稳定性:稳定的
基本方法:每步将一个待排序的元素,将其排序码的大小,插入到前面已经排好序的一组元素的适当位置,知道元素全部插入为止。
这里写图片描述
这里写图片描述
代码示例:

/*
**直接插入排序
*/
void InsertSort(int a[], int len)
{
    int i, j, key;
    for(i = 1; i < len; ++i){
        key = a[i];
        for(j = i-1; j >=0; --j){
            if(a[j] > key)
                a[j+1] = a[j];
            else
                break;
        }
        a[j+1] = key;
    }
}

2.折半排序

基本思想 : 设在顺序表中有一 个元素序列 V[0], V[1], …, V[n-1]。其中, V[0], V[1], …, V[i-1] 是已经排好序的元素。在插入V[i] 时, 利用折半搜索法寻找V[i] 的插入位置。
算法分析:
折半搜索比顺序搜索快, 所以折半插入排序就
平均性能来说比直接插入排序要快。
它所需的排序码比较次数与待排序元素序列的初始排列无关,仅依赖于元素个数。在插入第 i 个元素时,需要经过 log2i +1 次排序码比较, 才能确定它应插入的位置。因此,将 n 个元素(为推导方便, 设为 n=2k ) 用折半插入排序所进行的排序码比较次数为:这里写图片描述
当 n 较大时,总排序码比较次数比直接插入排序的最坏情况要好得多,但比其最好情况要差。
在元素的初始排列已经按排序码排好序或接近有序时,直接插入排序比折半插入排序执行的排序码比较次数要少。折半插入排序的元素移动次数与直接插入排序相同,依赖于元素的初始排列,所以时间复杂度:O(n^2)
稳定性:稳定的

这里写图片描述

代码描述:

    int BinaryInsertSort()  
    {  
        int i,j,low,high,mid;  
        for (i = 2; i < iCount; i++)  
        {  
            iRawBuff[0] = iRawBuff[i];  
            low = 1;  
            high = i -1;  
            while (low<=high)  
            {  
                mid = (low+high)/2;  
                if(iRawBuff[0] > iRawBuff[mid])  
                    low = mid +1;  
                else  
                    high = mid -1;        
            }  
            //找到high,high+1就是i要插入的位置  
            for(j = i-1; j>= high + 1; j--)  
            {  
                iRawBuff[j+1] = iRawBuff[j];  
            }  
            iRawBuff[j+1] = iRawBuff[0];  
            printf("第%d趟:\n",i-1);  
            for(int k = 0; k < iCount; k++)  
            {  
                std::cout<<iRawBuff[k]<<"\t";  
            }  
            std::cout<<std::endl;  
        }     
        return 0;  
    }  

3.希尔排序
希尔排序方法又称为缩小增量排序。该方法的基本思想是 :
①设待排序元素序列有 n 个元素, 首先取一个整数 gap < n 作为间隔,将全部元素分为 gap 个子序列,所有距离为 gap 的元素放在同一个子序列中,在每一个子序列中分别施行直接插入排序。

②然后缩小间隔 gap, 例如取 gap = gap/2,重复上述的子序列划分和排序工作。直到最后取 gap == 1,将所有元素放在同一个序列中排序为止。
开始时 gap 的值较大,子序列中的元素较少,排序速度较快; 随着排序进展,gap 值逐渐变小, 子序列中元素个数逐渐变多,由于前面工作的基础,大多数元素已基本有序,所以排序速度仍然很快。

算法分析
稳定性:不稳定
Gap的取法有多种。最初 shell 提出取 gap = n/2,gap = gap/2,直到gap = 1。knuth 提出取 gap = gap/3 +1。还有人提出都取奇数为好,也有人提出各 gap 互质为好。
对特定的待排序元素序列,可以准确地估算排序码的比较次数和元素移动次数。
想要弄清排序码比较次数和元素移动次数与增量选择之间的依赖关系,并给出完整的数学分析,还没有人能够做到。
Knuth利用大量实验统计资料得出 : 当 n 很大时,排序码平均比较次数和元素平均移动次数大约在 n1.25 到 1.6n1.25 的范围内。这是在利用直接插入排序作为子序列排序方法的情况下得到的。
例:关键字序列
这里写图片描述
gap=3时,三个下标为1的相比较,排出大小,三个下标为2的相比较排出大小,两个下标为2的相比较排出大小。
结果如图所示。
gap=2和gap=1如同gap=3.
代码示例:

void shellsort2(int a[], int n)  
{  
    int j, gap;  

    for (gap = n / 2; gap > 0; gap /= 2)  
        for (j = gap; j < n; j++)//从数组第gap个元素开始  
            if (a[j] < a[j - gap])//每个元素与自己组内的数据进行直接插入排序  
            {  
                int temp = a[j];  
                int k = j - gap;  
                while (k >= 0 && a[k] > temp)  
                {  
                    a[k + gap] = a[k];  
                    k -= gap;  
                }  
                a[k + gap] = temp;  
            }  
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值