插入类排序

来源:互联网 发布:highcharts.js 下载 编辑:程序博客网 时间:2024/04/29 00:21

~~无论是查资料、翻书、自己总结,总之记了很多笔记,以后慢慢将它分享出来~~

插入类排序的基本思想
在一个已经排好序的有序序列区内,对待排序的无序序列区中记录逐个进行处理,每一步将一个待排序的记录与有序序列区的记录进行比较,然后有序地插入到该有序序列区中,直到待排序的无序序列区处理完毕。

分类
1).直接插入排序(基于顺序查找)
2).折半插入排序(基于折半查找)
3).希尔排序(基于逐趟缩小增量)

直接插入排序
思想:假设记录序列的状态为R[1...i...n],则有序序列区为R[1...i-1],无序序列区为R[i...n],R[i]为无序序列区正在处理的记录。直接插入排序就是利用顺序查找来确定r[i]在有序序列区有序序列区R[1...i-1]中的插入位置。即:将第i个记录的关键字Ki与前面记录R[1...i-1]的关键字从后向前顺次比较,将所有关键字大于Ki的记录依次向后移动一个位置,直到遇到一个关键字小于或等于Ki的记录,该记录的位置即为R[i]的插入位置。
注意:初始时,R[1]自成1个有序区,无序区为R[2...n]。从i=2起直至i=n为止,依次将R[i]插入当前的有序区R[1..i-1]中,生成含n个记录的有序区。
代码:见下。
平均时间复杂度:O(n^2)。
稳定性:稳定。

折半插入排序
思想:折半插入排序是利用折半查找来确定r[i]在有序序列区有序序列区R[1...i-1]中的插入位置。
代码:见下。
平均时间复杂度:O(n^2)。
稳定性:稳定。

希尔排序
思想:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率上比前两种方法有较大提高。
代码:见下。
平均时间复杂度:跟增量的选取有很大的关系。很多情况下“增量每次除以2递减”,时间复杂度为O(n^2)。当按{2k-1,2k-1-1,...,7,3,1}序列取增量时,时间复杂度为O(n^(3/2)),“增量每次除以3递减”也可以达到这种效果。
稳定性:不稳定。

代码:
//直接插入排序

void directInsertSort(int array[],int length)

{

    for (int i=2; i<=length; i++)

    {

        array[0]=array[i];//记录Ki

        int j=i-1;

        for (; array[j]>array[0]; j--)//条件中当j=0时,array[j]>array[0]自然不成立

        {

            array[j+1]=array[j];//如果该记录大于Ki则后移

        }

        array[j+1]=array[0];//上一步条件判断失败时j多走了一个,因此插入到j+1

    }

}


//折半插入排序

void binaryInsertSort(int array[],int length)

{

    for (int i=2; i<=length; i++)

    {

        array[0]=array[i];

        int low=1,hight=i-1,mid;

        while (low<=hight)//此处通过折半查找的方式确定要插入的位置,而不是顺序比较

        {

            mid=(low+hight)/2;

            if (array[0]<array[mid])//若当前记录小于中间位置的记录则heigh缩小

            {

                hight=mid-1;

            }

            else//否则low缩小

            {

                low=mid+1;

            }

        }

//while执行完,low则为要插入的位置,即low之后的记录的关键字都比low位置的大

        for (int j=i-1; j>=low; j--)//前一步已经找出要插入的位置,因此这里直接将比往后移动

        {

            array[j+1]=array[j];

        }

        array[low]=array[0];

    }

}

//希尔排序

void ShellInsert(int array[],int length,int d)

{

    for (int i=d+1; i<=length; i++)//从增量d划分的第一个子序列的第二个记录开始,顺序扫描整个待排序列,对每个扫描到的记录在其所在的子序列进行直接插入排序

    {

        array[0]=array[i];

        int j=i-d;//当前记录所在子序列的前一个记录

        for (; j>0&&array[0]<array[j]; j=j-d)//j=j-d有可能直接跳过j=0,因此需要加上j>0这个条件

        {

            array[j+d]=array[j];

        }

        array[j+d]=array[0];

    }

}

void ShellSort(int array[],int length)

{

    int d=length/2;//初始增量设为数组长度的一半

    while (d>=1)

    {

        ShellInsert(array, length, d);//每次调用,即为一趟排序

        d=d/3;//增量每次除以3递减

    }

}