美文网首页
拥抱算法 (Embracing Algorithms) 上

拥抱算法 (Embracing Algorithms) 上

作者: FicowShen | 来源:发表于2019-02-19 22:21 被阅读15次

    什么是算法?

    Algorithm

    算法:

    在计算或其他解决问题的操作中要遵循的一个或一组规则,特别是通过计算机:一种基本的划分算法。




    现在,请假设你正在构建这样一个App:

    示例App

    你可以选中画布中的某几个图形(view),然后对这些图形所在的图层进行多种操作。
    比如:将图层向前、向后移动、删除图层等等。


    从数组中删除元素



    会导致数组越界错误的删除算法

    你是否会这样删除数组中的元素呢? (好吧,很早以前我确实这样写过...... -_-+)
    事实上,上面的写法会导致数组越界错误(Fatal error: Index out of range)

    为什么?
    因为在0..<shapes.count处,for循环的range值就已经确定了。
    所以当shapes的元素个数减少时,就会出现索引值超过数组元素容量个数的问题,最终导致越界错误。



    不会导致数组越界错误,但是有bug的删除算法

    改成while之后,可以避免崩溃问题。因为我们知道while在每次循环开始时,都会去判断循环开始的条件是否成立。
    但是,这样做会产生bug,而且这个bug不容易立刻被发现!



    删除两个连续的元素

    因为每次循环i都会加1,所以删除连续的元素中的第一个元素时,i也会加1。
    然而,这一次加1就会导致待删除的连续元素中的第二个元素被跳过。



    没有bug,但是低效的删除算法

    更改if部分的逻辑后,可以解决上述问题。

    当然,你也可以这样写:


    image.png

    好像可以完美地完成删除多个元素的任务了。
    但是,这个算法的效率(主要考虑时间复杂度)如何呢?

    remove(at:)方法的文档



    remove(at:)方法的时间复杂度

    时间复杂度常用大O符号来表示,描述一个函数数量级的渐近上界。

    首先,外层for在遍历数组时的时间复杂度是O(n)
    然后,根据文档可以知道remove(at:)方法的时间复杂度也是O(n)
    那么,这个方法整体的时间复杂度就是O(n^2)了!!! Amazing!!!



    O(n^2)

    如果你的数组有1000、10000个元素,那么。。。结果完全可以想象!
    你的程序将会变得很低效!

    那么,你现在该怎么办?



    removeAll(where:)方法 removeAll(where:)方法的文档 removeAll(where:)方法的时间复杂度

    这也许就是你想要的,removeAll(where:)方法的时间复杂度仅为O(n) !!!



    我们来对比一下不同时间复杂度O(n)O(n^2)之间的差别:

    image.png




    你现在一定很好奇removeAll(where:)方法内部的算法为什么能够如此高效?

    removeAll(where:)方法的实现

    需要注意的是,这个方法在MutableCollection的扩展中,而且方法被标记为mutating
    所以,待操作的集合一定是可变的!



    接下来,看一下halfStablePartition(isSuffixElement:)的实现,这里才是高效率的关键部分:

    halfStablePartition(isSuffixElement:)的实现

    formIndex(after:)方法用于改变索引的值,将索引位置向后移动。
    显然,halfStablePartition(isSuffixElement:)方法的复杂度仅为O(n)




    至此,你也知道了标准库的强大。
    所以,可以多花点时间去了解一下Swift Standard Library



    继续阅读: 拥抱算法 (Embracing Algorithms) 下



    参考文章:
    Embracing Algorithms

    相关文章

      网友评论

          本文标题:拥抱算法 (Embracing Algorithms) 上

          本文链接:https://www.haomeiwen.com/subject/ifyfyqtx.html