各种排序算法汇总(插入排序:直接插入排序、折半插入排序、希尔排序)

来源:互联网 发布:淘宝权女朋友静雯 编辑:程序博客网 时间:2024/04/30 02:57

以下是我对常见的几种排序算法的总结并给出的代码,基于C++语言实现,存储格式是顺序表。本人才疏学浅,如果有错漏还请各位指正。

一、存储格式:顺序表

int *data;//存储数据(data[1...size]存储待排序序列,data[0]为临时单元)int size;//可存放容量

二、插入排序

1.直接插入排序

(1)思路:当插入data[i](i>=2)时前面的data[1],data[2],...,data[i-1]已经排好序.这时用data[i]的排序码与data[i-1],data[i-2],...的排序码顺序进行比较,找到插入位置即将data[i]插入,原来位置上的对象向后顺移.

插入排序演示
(2)空间复杂度:只需要一个记录的附加空间,即data[0](即额外空间为O(1))
(3)时间复杂度:O(n^2)
(4)稳定性:稳定

(5)源代码:

//直接插入排序void SeqList::directInsertSort(){int i, j;for (i = 2; i <= size; i++){data[0] = data[i];//暂存j = i - 1;while (data[j] > data[0])//查找插入位置{data[j + 1] = data[j];--j;}data[j + 1] = data[0];//插入}}

(6)分析:简单直观,工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。直接插入排序不适用与数据量大的排序,但是数据量较小,例如量级小于千时,插入排序还是一个不错的选择。



2.折半插入排序(又叫二分查找插入排序):

(1)思路:思路与直接插入排序相同,只是在查找插入位置时用二分查找提高效率,是对直接插入排序的改进。

(2)空间复杂度:只需要一个记录的附加空间,即data[0]

(3)时间复杂度:折半插入排序的比较次数数量级为O(n*log(n)),移动记录的次数和直接插入排序一样数量级为O(n^2),所以折半插入排序的时间复杂度为O(n^2)

(4)稳定性:稳定

(5)源代码:

//折半插入排序void SeqList::halfInsertSort(){int i, j, low, high, mid;for (i = 2; i <= size; i++){data[0] = data[i];//暂存low = 1;high = i - 1;while (low <= high)//二分查找寻找插入位置{mid = (low + high) / 2;if (data[0] < data[mid])high = mid - 1;elselow = mid + 1;}for (j = i - 1; j >= low; j--)//依次后移data[j + 1] = data[j];data[low] = data[0];//插入}}

(6)分析:优劣点与直接插入排序相同。


3.希尔排序(缩小增量排序):

(1)思路:把所有记录按一定的增量分组,对每组用直接插入排序算法排序,随着增量的减少,各分组中包含的记录将越来越多,当增量减少至1时,所有记录序列变成一个组。由此可见,希尔排序巧妙地利用原有子序列的有序性。步长的选择是希尔排序的关键,一般增量取d1=n/2,di+1=di/2(Shell的取法),已知的最好步长序列是由Sedgewick提出的(1, 5, 19, 41, 109,...)。注意最后一个增量必须为1

一个更好理解的希尔排序实现:将数组列在一个表中并对列排序(用插入排序)。重复这过程,不过每次用更长的列来进行。最后整个表就只有一列了。将数组转换至表是为了更好地理解这算法,算法本身仅仅对原数组进行排序(通过增加索引的步长,例如是用i += step_size而不是i++)。

例如,假设有这样一组数[ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ],如果我们以步长为5开始进行排序,我们可以通过将这列表放在有5列的表中来更好地描述算法,这样他们就应该看起来是这样:

13 14 94 33 8225 59 94 65 2345 27 73 25 3910

然后我们对每列进行排序:

10 14 73 25 2313 27 94 33 3925 59 94 65 8245

将上述四行数字,依序接在一起时我们得到:[ 10 14 73 25 23 13 27 94 33 39 25 59 94 65 82 45 ].这时10已经移至正确位置了,然后再以3为步长进行排序:

10 14 7325 23 1327 94 3339 25 5994 65 8245

排序之后变为:

10 14 1325 23 3327 25 5939 65 7345 94 8294
最后以1步长进行排序,此时就是简单的插入排序了(实例取自维基百科点击打开链接)

(2)空间复杂度:只需要一个记录的附加空间,即data[0]

(3)时间复杂度:Shell算法的性能与所选取的分组长度序列有很大关系。只对特定的待排序记录序列,可以准确地估算关键词的比较次数和对象移动次数。想要弄清关键词比较次数和记录移动次数与增量选择之间的关系,并给出完整的数学分析,至今仍然是数学难题。

(4)稳定性:不稳定

(5)源代码:

//希尔排序void SeqList::shellSort(){    int i, j, gap;    gap = size / 2;            //初始步长    while (gap >= 1)            //减小步长直至为1(变为一般的直接插入排序)    {        for (i = gap + 1; i <= size;i++)        {            data[0] = data[i];        //暂存以及岗哨            j = i - gap;            while (data[j] > data[0])    //依次后移            {                data[j + gap] = data[j];                j -= gap;            }            data[j + gap] = data[0];    //插入        }        gap /= 2;                    //减小步长    }}
0 0