算法实战---OC希尔排序(二)

知了一笑 2018-01-30 16:31:29 ⋅ 624 阅读

我没有为这种算法做任何事,我的名字不应该出现在算法的名字中。---- 希尔(shell排序作者)


希尔排序按其设计者希尔(Donald Shell)的名字命名,该算法由1959年公布。一些老版本教科书和参考手册把该算法命名为Shell-Metzner,即包含Marlene Metzner Norton的名字,但是根据Metzner本人的说法,“我没有为这种算法做任何事,我的名字不应该出现在算法的名字中。”

----那时候的名人多谦虚.


第一.定义

希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是非稳定排序算法。

希尔排序是基于插入排序的以下两点性质而提出改进方法**的:

1. 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率
2. 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位.
第二: 插入排序

既然提到了插入排序, 就在此先了解一下插入排序; 它的工作原理通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

话说一图胜千言, 来一张个人认为最容易理解的图:

来自维基百科--插入排序

对上图解释一下:

1. 从第一个元素开始,该元素可以认为已经被排序;
2. 取出下一个元素, 与前边的元素对比, 直到找到大于等于前边的那个数字停止, 对比过得数字往后移动;
3. 将新元素插入到该位置, 

直接上OC代码, 之后会随着希尔排序一块放在github上:

/** *  插入排序 */- (void)algorithm_InsertSortWith:(NSMutableArray *)array{    
    //将第一个数字视为 基准, 所以 i 从 1 开始
    for (int i = 1; i < array.count; i++) {        //待定位的数字
        int temp = [array[i] intValue];        //每次都从上次定位好的数字的前一位开始对比, 一直往前找, 直到找到合适位置<大于等于前边那个数字>,
        for (int j = i - 1; j >= 0 && temp < [array[j] intValue]; j --) {            //凡是不合格的数字都靠后移动
            array[j + 1] = array[j];            //最终将合格的数字确定位置
            array[j] = [NSNumber numberWithInt:temp];
        }
    }
    NSLog(@"排序过后的数组为: %@", array);
}
第三. 分析

还是说希尔排序产生的缘由吧,

1. 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率;
2. 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位.

主要是和时间复杂度O(n²)过不去, 就是看你不顺眼.

聊天都离不开GIF, 这里怎么能少!  隔着GIF图就感觉到前辈们的牛逼气息!

希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。即: 可以将数据分区域放在一个二维数组中,每个区一列, 然后对每一列排序.

待排序数组---[9, 1, 5, 8, 3, 7, 4, 6, 2], 先将步长设置为3稍后看步长

例子一

第一次分组<步长==3>原始数据为[9, 1, 5, 8, 3, 7, 4, 6, 2]

9, 1, 5 
8, 3, 7
4, 6, 2

第一次排序后为[4, 1, 2, 8, 3, 5, 9, 6, 7];

4, 1, 2 
8, 3, 5
9, 6, 7

第二次分组<步长==2>原始数据为[4, 1, 2, 8, 3, 5, 9, 6, 7];

4, 1
2, 8
3, 5
9, 6
7

第二次排序后为[2, 1, 3, 5, 4, 6, 7, 8, 9];

2, 1
3, 5
4, 6
7, 8
9

第三次分组步长==1, 排序后为 [1, 2, 3, 4, 5, 6, 7, 8, 9]

例子二

以图片的形式展示以上的操作步骤:

重点---步长计算

通过以上的插入排序希尔排序的例子, 想必对希尔排序有了初步的认识, 但对于步长这个东西完全模糊....放心;

因为步长的选择是希尔排序的重要部分, 所以摘出来单独说明; 作者最初的建议是折半再折半知道最后的步长为1<也就是插入排序>, 但是当用较小步长排序后,以前用的较大步长仍然是有序的。, 如果一个数列以步长5进行了排序然后再以步长3进行排序,那么该数列不仅是以步长3有序,而且是以步长5有序。如果不是这样,那么算法在迭代过程中会打乱以前的顺序,那就不会以如此短的时间完成排序了。 摘录自wiki百科

已知的最好步长序列是由Sedgewick提出的 **1,5,19,41,109,... **

它是由交错两个序列的元素获得:<公式: 9(4 ķ - 2 ķ)+ 1 和 2 K + 2(2 K + 2 - 3)+ 1 >

1191095052161,... ...,|| 94 ķ - 2 ķ)+ 1,K = 0123,... 
5412099293905,... ..|| 2 K + 22 K + 2 - 3)+ 1,K = 0123,...

这项研究也表明“比较在希尔排序中是最主要的操作,而不是交换。”用这样步长序列的希尔排序比插入排序要快,甚至在小数组中比快速排序和堆排序还快,但是在涉及大量数据时希尔排序还是比快速排序慢。可以参考 Sorting Algorithms - Shellsort

OC希尔排序代码

- (void)algorithm_shellSortWith:(NSMutableArray *)array{    
    //总长度
    int n = (int)array.count;    //最外层for循环确定----步长的个数 <折半直至为步长等于 1 >
    for (int gap = n / 2; gap > 0; gap /= 2){
        NSLog(@"步长----%d", gap);        //确定以步长为间隔的一对数字的后一个.
        for (int i = gap; i < n; i++){
            NSLog(@"第 %d 位 与第 %d 位对比", i - gap, i);            //找到成对的前一个, 加上判断<从第一位开始><升序降序>, j -= gap, 小组内排序
            for (int j = i - gap; j >= 0 && array[j] > array[j + gap]; j -= gap){
![Uploading Sorting_shellsort_anim_123589.gif . . .]                //交换位置
                [array exchangeObjectAtIndex:j withObjectAtIndex:(j + gap)];
            }
        }
    }
       NSLog(@"----%@", array);
}

还得在整理一下.....


参考链接

1. 维基百科
2. Sorting Algorithms - Shellsort

更多精彩内容请关注“IT实战联盟”哦~~~




全部评论: 0

    我有话说:

    算法实战---OC快速排序(一)

    近来在巩固数据结构和算法的知识, 动动手操作操作. 能讲出来是真的懂了, 分享是件快乐的事第一.

    决战上海滩!美团or滴滴,谁是打车界"大佬"?/滴滴共享单车道路艰难:青桔单车投放当天再次被“ 收缴”/支付宝惨遭沃玛封杀..

    决战上海滩!美团or滴滴,谁是打车界"大佬"?;滴滴共享单车道路艰难:青桔单车投放当天再次被“ 收缴”;支付宝惨遭沃玛封杀!马爸爸,你怎么看?

    排序 --- 归并排序

    此篇文章引自 这里,个人感觉无出其右者,只好借鉴而来 归并排序 是递归分治和有序合并的简称, 首先利用分治法的思想将序列递归分裂成若干个子序列,使将子序列基本有序,最后使整体有序。 一、图示

    iOS实战篇:[译]iOS扩充--OCR光学字符识别(内附项目GitHub地址)

    OCR(Optical Character Recognition) 光学字符识别, 是从图像中电子扫描提取文本的过程, 可以在文档编辑等多种形式重用它,例如: 文本搜索/压缩等用途。

    Kafka系列

    目的是:提供负载均衡,实现系统的高伸缩性【Sca...

    Redis为什么变慢了?Redis性能问题排查详述

    Redis 作为优秀的内存数据库,其拥有非常高的性能,单个实例OPS 能够达到 10W 左右。但也正因此如此,当我们在使用 Redis 时,如果发现操作延迟变大的情况,就会与我们的预期不符。 你

    Java项目权威排名:Nacos未上版,Maven排名 28

    来源:toutiao.com/i6908912198412681732/ https://github.com/ossf/criticality_score 发布了开源项目排名, 下载地址

    Node.js 实战篇--微信支付系列(

    接上一篇首先我们看一下整体上微信小程序的开发流程图

    Git 2.29稳定版发布,实验性支持更安全的SHA-256

    Git 2.29 稳定版已发布。此前发布的多个版本都在为将 Git 使用的安全哈算法从 SHA-1 迁移至 SHA-256 做准备,2.29 版本终于实验性支持 SHA-256,可用于提升代码仓库

    SpringBoot+zk+dubbo架构实践):SpringBoot 集成 zookeeper

    不啰嗦,本篇完成两件事:1、搭建SpringBoot 框架;2、基于spring boot框架访问zookeeper。

    Java并发解决方案:分布式应用限流实践

    任何限流都不是漫无目的的,也不是一个开关就可以解决的问题,常用的限流算法有:令牌桶,漏桶。在之前的文章中,也讲到过,但是那是基于单机场景来写。 之前文章:接口限流算法:漏桶算法&令牌桶算法

    架构实战篇(十):Spring Boot 分布式Session共享Redis

    分布式Web网站一般都会碰到集群session共享问题,小编整理了一套解决方案,内附GitHub 源码地址哦~~~

    架构实战篇()-Spring Boot整合Swagger,让你的API可视化

    你还在跟前端对接上花费很多的时间而没有效果吗?你还在为写接口文档而烦恼吗?今天就教大家一个接口对接神器...

    Chrome OS 88 自定义屏保界面,可指纹登录第三方网站

    上周 Google 推出了 Chrome 88,在一周之后,Google 正式向 Chromebook 用户推送 Chrome OS 88,这也是 2021 年首个大版本更新。这个版本加入了多项新

    微信小程序营销之大转盘(

    第一个版本的大转盘都是用图片做的,奖品等信息都是不无法修改的,说白了就是没啥实际用途,作者我就直接用canvas撸了一个全手工绘制的大转盘分享给大家

    Redis系列四 GEO附近的人

    GEO算法 GeoHash是一种地址编码方法。将维的空间经纬度数据编码成一个字符串; 地球上的经度范围:[-180, 180],纬度范围:[-90,90]。如果以本初子午线、赤道为界,地球可以

    抖音实战案例使用手册

    实战案例的数据怎么用?看这里!看这里!

    Redis系列:位图实战,实现打卡签到

    前言 如果要统计一篇文章的阅读量,可以直接使用 Redis 的 incr 指令来完成。 如果要求阅读量必须按用户去重,那就可以使用 set 来记录阅读了这篇文章的所有用户 id,获取 set 集合的长度就是去重阅读量。但是如...