常见的五类排序算法图解和实现(插入类:直接插入排序,折半插入排序,希尔排序)

基本的五类排序算法(插入,选择,交换,归并,基数排序)。排序:将数据元素的一个任意序列,重新排列成一个按关键字有序的序列。

排序的稳定性:待排序列中有大于等于2个相同的项,且排序前后,相同项的相对位置是否发生了变化(如果变化了就是不稳定的排序,不变化就是稳定的)

内部排序:若整个排序过程不需要访问外存便能完成,则称此类排序问题为内部排序;(待排序列全部放入内存)

插入累排序:(直接插入,折半插入,希尔排序)

直接插入排序:

先将序列中第 1 个记录看成是一个有序子序列, 然后从第 2 个记录开始,逐个进行插入,直至整个序列有序。

通常是先把第一个记录看成是一个有序的序列,然后从第二个记录开始依次进行比较

r2处的38比第一个记录 r1处的49小,那么38插入到49的前面,把插入位置之后的记录顺次的后移一位,同时把带插入记录临时保存在 r0处(复制监视哨)。

然后把38插入到 r1处

下面是整个过程,一共7趟排序过程

特点:在最后一趟排序前,此序列没有一个记录到其最终位置。(所有的插入类排序的特点)

 1 //递增排序
 2 void insertSort(int list[])
 3 {
 4     int j = 0;
 5     int i = 0;
 6     int temp = 0;
 7     //对待排序列直接插入排序
 8     //一般把第一个记录先看成是有序子序列,然后从第二个记录开始,逐个的和前面去比较,插入
 9     for (i = 1; i <= 8; i++) {
10         //和前面的有序子序列的记录,逐个的比较,直接插入
11         if (list[i] < list[i - 1]) {
12             //复制为监视哨
13             temp = list[i];
14             //移位
15             list[i] = list[i - 1];
16             //继续顺次的和前面的记录进行比较,如果还有不小于它的,那么继续后移,直接插入排序
17             for (j = i - 1; temp <= list[j]; j--) {
18                 //记录后移
19                 list[j + 1] = list[j];
20                 //插入
21                 list[j] = temp;
22             }
23         }
24     }
25 }
26
27 int main(void)
28 {
29     int source[8] = {49, 38, 65, 97, 76, 13, 27, 49};
30
31     insertSort(source);
32
33     for (int i = 0; i < 8; i++) {
34         printf(" %d ", source[i]);
35     }
36
37     return 0;
38 }

13  27  38  49  49  65  76  97 Program ended with exit code: 0

算法评价

最好的情况:待排序记录按关键字从小到大排列(正序)

比较次数:,移动次数:0 

最坏的情况:待排序记录按关键字从大到小排列(逆序) 

比较次数:,移动次数: 

一般情况:待排序记录是随机的,取平均值。 比较次数和移动次数均约为: n^2/4

时间复杂度:T(n)=O(n²) (最坏情况下),最好的情况是O(n),平均时间复杂度是O(n²)

空间复杂度:S(n)=O(1) ,且直接插入排序是稳定排序

 

折半插入排序

用折半查找方法确定插入位置的排序。思想类似直接插入排序,只不过,要设置 mid=不大于(low+high)/2的最大整数,当插入到 mid 左边(做半区),则改变 high(mid-1),如果插入到 mid 右边,则改变 low(mid+1)。

初试序列,同样是把第一个记录看成是有序的子序列,然后从第二个记录开始,依次进行比较

假设只有最后的20这个记录了

mid=(0+6)/2=3,指向39处,20比mid 的值小,插入到 mid 左边,改变 high=mid-1

重新计算 mid=1,指向13处,继续和20比较,20比 mid的值大,插入到 mid 右边,改变 low=mid+1

计算 mid=2,指向30,20比 mid 的值30小,插入到 mid 左边,改变 high=mid-1

直到low>high时,由折半查找得到的插入位置为low或high+1。

//递增排序
void insertHalfSort(int list[])
{
    int j = 0;
    int i = 0;
    int low = 0;
    int high = 0;
    int mid = 0;
    int temp = 0;//临时监视哨
    //一般把第一个记录先看成是有序子序列,然后从第二个记录开始,前面去比较,折半插入
    for (i = 1; i <= 8; i++) {
        //复制为监视哨
        temp = list[i];
        low = 0;
        high = i - 1;
        //当 low>high,则找到了插入位置,为 low或者 high+1
        while (low <= high) {
            //循环计算 mid 的值
            mid = (int)((low + high) / 2);
            //待插入记录和 mid进行比较
            if (temp < list[mid]) {
                //改变 high
                high = mid - 1;
            }else{
                //改变 low
                low = mid + 1;
            }
        }
        //循环结束,说明找到了插入位置,进行移位
        for (j = i - 1; j >= low; j--) {
            list[j + 1] = list[j];
        }
        //插入
        list[low] = temp;
    }
}

折半插入,适用于记录较多的场景,但是记录的移动次数和直接插入排序一样,故时间复杂度一样。

最好是 o(n),最差是 O(n²),平均是 O(n²)。空间复杂度是 o(1)。

特点:折半插入排序的比较次数和初始的序列无关,因为折半的次数一定,折一次比较一次。和直接插入比较,仅减少了比较次数,移动次数不变。折半插入排序是稳定排序

 

希尔排序(缩小增量排序)

基本思想:对待排序列先作“宏观”调整,再作“微观”调整。先取一个正整数 d1 < n,把所有相隔 d1 的记录放在一组内,组内进行直接插入排序;然后取 d2 < d1,重复上述分组和排序操作,直至 di = 1,即所有记录放进一个组中排序为止。其中 di 称为增量。且增量 d逐渐变小。

增量d 的取法:最后一个值一定为1,且其余的值没有除1之外的公因子。

如图,增量为5,把相隔5的记录放到一组内,组内进行直接插入排序

分别把增量为5的记录找出,放在一组内,每组内直接插入排序

分别对子序列进行插入排序

缩小增量d=3

分别把增量 为3的记录找出

找完之后,缩小增量d=1,进行插入排序

直接插入排序适用于基本有序的情况,而希尔排序会使整个序列更加的有序。

特点:希尔排序是不稳定的排序方法

 

增量序列取法;

如何选择增量序列以产生最好的排序效果,至今仍没有从数学上得到解决。

     1)、没有除 1 以外的公因子;

     2)、最后一个增量值必须为 1。

记住:分组不是简单的“逐段分割”,而是将相隔某个增量的记录组成一个子序列。

 

希尔排序可提高排序速度

     1)、记录跳跃式前移,在进行最后一趟排序时,已基本有序。 

     2)、分组后 n 值减小,n^2 更小,而 T(n)=O(n^2),所以 T(n) 从总体上看是减小了。时间复杂度为 O(n log2(n)),控件复杂度为 o(1)

 

辛苦的劳动,转载请注明出处,谢谢……

http://www.cnblogs.com/kubixuesheng/p/4353575.html

时间: 2024-09-20 10:12:29

常见的五类排序算法图解和实现(插入类:直接插入排序,折半插入排序,希尔排序)的相关文章

排序算法之一插入排序(直接插入和希尔排序)

本文的图均引用自http://blog.csdn.net/pzhtpf/article/details/7559896,代码为结合众家思想以及自己的方式而来. 下面是一些排序的关系图: 直接插入排序 (1)基本思想:在要排序的一组数中,假设前面(n-1)[n>=2]个数是排好序的,现在要把第n个数插到前面的有序数中,使得这n个数也是排好序的.如此反复循环,知道全部排好顺序.(2)实例: (3)代码实现: 123456789101112131415161718192021222324 /** *

常见的五类排序算法图解和实现(多关键字排序:基数排序以及各个排序算法的总结)

基数排序思想 完全不同于以前的排序算法,可以说,基数排序也叫做多关键字排序,基数排序是一种借助"多关键字排序"的思想来实现"单关键字排序"的内部排序算法. 两种方式: 1.最高位优先,先按照最高位排成若干子序列,再对子序列按照次高位排序 2.最低位优先:不必分子序列,每次排序全体元素都参与,不比较,而是通过分配+收集的方式. 多关键字排序 例:将下表所示的学生成绩单按数学成绩的等级由高到低排序,数学成绩相同的学生再按英语成绩的高低等级排序.        第一个关键

常见的五类排序算法图解和实现(选择类:简单选择排序,锦标赛排序,树形选择排序,堆排序)

选择类的排序算法 简单选择排序算法 采用最简单的选择方式,从头到尾扫描待排序列,找一个最小的记录(递增排序),和第一个记录交换位置,再从剩下的记录中继续反复这个过程,直到全部有序. 具体过程: 首先通过 n –1 次关键字比较,从 n 个记录中找出关键字最小的记录,将它与第一个记录交换. 再通过 n –2 次比较,从剩余的 n –1 个记录中找出关键字次小的记录,将它与第二个记录交换. 重复上述操作,共进行 n –1 趟排序后,排序结束. 如图   过程图解 令 k=i:j = i + 1: 目

常见的五类排序算法图解和实现(归并类:二路归并排序)

归并类的排序算法 归并:将两个或两个以上的有序表组合成一个新的有序表. 内部排序中,通常采用的是 2-路归并排序.即:将两个位置相邻的记录有序子序列归并为一个记录有序的序列.归并排序是建立在归并操作上的一种有效的排序算法.该算法是采用分治法(Divide and Conquer)的一个非常典型的应用. 图解如下 看成是 n 个有序的子序列(长度为 1),然后两两归并. 得到 n/2 个长度为2 或 1 的有序子序列.继续亮亮归并 最后一趟 代码如下: 1 //二路一次归并过程的算法 2 //lo

常见的五类排序算法图解和实现(交换类:冒泡排序,递归的快速排序)

冒泡排序算法: 总的来说就是两两交换,反复直到有序,第一个记录和第二个记录,若逆序则交换,然后比较第二个和第三个记录,以此类推,直到第 n 个记录和第 n-1个记录比较完毕为止,第一趟排序,结果关键字最大的记录被安排在最后一个位置.对前 n-1个记录继续冒泡排序,使得关键字次大的记录安排在第 n-1个位置.如此重复,直到没有需要交换的记录为止(仅仅是第一个和第二个交换过为止).整个一趟趟的选出最值的过程,仿佛是那水里的气泡,咕嘟咕嘟的往上翻的过程. 递增冒泡排序过程图解: 一般先比较第一个元素和

各大排序算法性能比较及演示实例

所谓排序,即将原来无序的一个序列重新排列成有序的序列. 排序方法中涉及到稳定性,所谓稳定性,是指待排序的序列中有两个或两个以上相同的项,在排序前和排序后看这些相同项的相对位置有没有发生变化,如果没有发生变化,即该排序方法是稳定的,如果发生变化,则说明该排序方法是不稳定的. 如果记录中关键字不能重复,则排序结果是唯一的,那么选择的排序方法稳定与否就无关紧要了:如果关键字可以重复,则在选择排序方法时,就要根据具体的需求来考虑选择稳定还是不稳定的排序方法.那么,哪些排序算法是不稳定的呢? "快些选堆&

Java 实现的各种经典的排序算法小Demo

由于有上机作业,所以就对数据结构中常用的各种排序算法都写了个Demo,有如下几个: 直接插入排序 折半插入排序 希尔排序 冒泡排序 快速排序 选择排序 桶排序 Demo下载地址 下面谈一谈我对这几个排序算法的理解: 插入类算法 对于直接插入排序:(按从小到大的顺序) 核心原理: 若数组中只有一个元素,那么这就已经是有序的了:若数组中元素个数为两个,我们只需要对他们进行比较一次,要么交换顺序,要么不交换顺序就可以实现数组的内容的有序化:但是当数组内的元素的个数为N个呢?又该如何?这就催化了这个直接

Java实现几种常见排序算法代码_java

稳定度(稳定性)一个排序算法是稳定的,就是当有两个相等记录的关键字R和S,且在原本的列表中R出现在S之前,在排序过的列表中R也将会是在S之前. 排序算法分类 常见的有插入(插入排序/希尔排序).交换(冒泡排序/快速排序).选择(选择排序).合并(归并排序)等. 一.插入排序 插入排序(Insertion Sort),它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入.插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),

JavaScript版几种常见排序算法分享

说明 ·  每个浏览器测试得出的数据会不一样.比如我用chrome 测试 一般快速排序都会最快,IE 则根据数组长度有可能希尔最快. ·  不要用太大数据去测试冒泡排序(浏览器崩溃了我不管) 个人理解 ·  冒泡排序:最简单,也最慢,貌似长度小于7最优 ·  插入排序: 比冒泡快,比快速排序和希尔排序慢,较小数据有优势 ·  快速排序:这是一个非常快的排序方式,V8的sort方法就使用快速排序和插入排序的结合 ·  希尔排序:在非chrome下数组长度小于1000,希尔排序比快速更快 ·  系统