数据结构与算法八: 2)排序算法--希尔排序

384 阅读3分钟

这是我参与8月更文挑战的第7天

关注我,以下内容持续更新

数据结构与算法(一):时间复杂度和空间复杂度

数据结构与算法(二):桟

数据结构与算法(三):队列

数据结构与算法(四):单链表

数据结构与算法(五):双向链表

数据结构与算法(六):哈希表

数据结构与算法(七):树

数据结构与算法(八):排序算法

数据结构与算法(九):经典算法面试题

前面讲了直接插入排序,当较小的数在序列的偏后面的位置时,后移的次数明显增多,对效率有影响。针对这一点,希尔排序做出了优化,希尔排序通过设置一个增量gap,使得序列基本有序.提高了效率。这届主要讲希尔排序.

基本思想

将整个待排序序列分割成若干个子序列,在子序列内分别进行直接插入排序,待整个序列基本有序时,对所有元素进行直接插入排序(也就是最后一次循环gap=1的时候)。分割子序列的方法:将相隔某个增量的元素组成一个子序列,取增量的方法,令gap初始值为元素个数,每轮循环令gap除以2,算法如下:for (int gap = (int)arr.count/2; gap>0; gap/=2) {以 gap 为增量,进行组内直接插入排序};子序列内直接插入排序的思路:在插入元素 arr[i]时,自arr[i-gap]起往前跳跃式(跳跃幅度为gap)搜索待插入位置,在搜索过程中,元素后移也是跳跃 gap 个位置;在整个序列中,前 gap 个元素分别是 gap 个子序列的第一个元素,所以从 gap+1 的位置开始进行插入.

希尔排序.png

希尔排序和字节插入排序一样,有交换法和移位法,交换法效率太低,代码用移位法实现。

代码实现

-(void)shellSort:(NSMutableArray*)arr{

    int gap = (int)arr.count/2;

    while (gap>0) {

        for (int i = gap; i<arr.count; i++) {

            //暂存arr[i]的值,也就是要插入的值,使其不至于因为元素的后移而丢失元素的内容

            int tmp = [arr[i] intValue];

            int j = i;//j代表要插入的位置,tmp要和 j-gap 比较,如果tmp大,则插入到j-gap后面的位置,就是j

            /**

            while循环的条件:

            j-gap>=0:如果下一个要比较的元素>=0;

            tmp < arr[j-gap]:如果待插入的值小于下一个要比较的元素;往后移动

            如果同时满足这两个条件,元素后移gap个位置;

            退出 while 循环时,就找到正确的位置,直接插入 j 的位置

            */

            while (j-gap>=0 && tmp < [arr[j-gap] intValue]) {

                arr[j] = arr[j-gap];//前边的元素往后移动一位

                j = j-gap;//下次比较同一子序列的前一个位置

            }

            arr[j] = @(tmp);//把要比较的元素插入在正确的位置

        }

        gap = gap/2;

    }

}
//while 循环方式实现
-(void)shellSort:(NSMutableArray*)arr{
    //gap从n开始,每次循环除以2
    for (int gap = (int)arr.count/2; gap>0; gap/=2) {//①

        for (int i = gap; i<arr.count; i++) {
            //暂存arr[i]的值,也就是要插入的值,使其不至于因为元素的后移而丢失元素的内容
            int tmp = [arr[i] intValue];//②
            //j代表要插入的位置,tmp要和 j-gap 比较,如果tmp大,则插入到j-gap后面的位置,就是j
            int j = i;

            /**
             while循环的条件:
             j-gap>=0:如果下一个要比较的元素>=0;
             tmp < arr[j-gap]:如果待插入的值小于下一个要比较的元素;往后移动
             如果同时满足这两个条件,元素后移gap个位置;
             退出 while 循环时,就找到正确的位置,直接插入 j 的位置
             */

            while (j-gap>=0 && tmp < [arr[j-gap] intValue]) {/③
                arr[j] = arr[j-gap];//前边的元素往后移动gap个位置
                j = j-gap;//下次比较同一子序列的前一个位置
            }
            arr[j] = @(tmp);//把要比较的元素插入在正确的位置
        }
    }
}

代码解读

① gap从n开始,每次循环除以2,这个外层循环走了几次,就执行了几轮子序列的直接插入排序

② tmp暂存arr[i]的值,也就是要插入的值,使其不至于因为元素的后移而丢失元素的内容

③ while循环的条件:

       j-gap>=0:如果下一个要比较的元素>=0;

       tmp < arr[j-gap]:如果待插入的值小于下一个要比较的元素;往后移动

      如果同时满足这两个条件,元素后移gap个位置;

      退出 while 循环时,就找到正确的位置,直接插入 j 的位置      

希尔排序与直接插入排序的对比

希尔排序vs直接插入排序.jpg 通过希尔排序与直接插入排序代码的比较,发现只需要把直接插入排序设置为 1 的地方,改为 gap,外层再嵌套个for循环,这个外层循环走了几次,就执行了几轮子序列的直接插入排序

其他排序算法

排序算法:1)直接插入排序

排序算法:2)希尔排序

排序算法:3)冒泡排序

排序算法:4)快速排序

排序算法:5)选择排序

排序算法:6)归并排序

排序算法:7)基数排序

排序算法:8)堆排序

关注

如果觉得我写的不错 请点个赞
关注我 持续更新