美文网首页@IT·互联网编程镓教程序员
《编程原来是这么回事》算法篇(下)

《编程原来是这么回事》算法篇(下)

作者: 深加思考 | 来源:发表于2018-09-21 09:33 被阅读60次

    6. 怎么避免在执行算法时犯错?

    终于,我们要执行元算法中的最后一步,也就是执行算法了。无论算法有多好,准备有多充分,要是执行不好的话全都白搭。

    那么,在执行算法过程中,我们往往会犯哪些错误,又该如何应对呢?

    1、流程错误

    这是我们最容易犯的一类错误,大概可以分为下面这三种情况:

    1. 漏掉了某些必要的步骤 ,比如下雨天出门忘了带伞……

    2. 多做了无用甚至有害的步骤,比如炒菜的时候放了两次盐……

    3. 步骤都没错但顺序颠倒了,比如先穿好鞋再穿袜子……

    导致流程错误的原因只有一个,那就是:忘记现在该执行哪一步了。正如我们之前所说,人的记忆是靠不住的。也许你现在能轻松地背出整个算法,但是如果你被其他突发事情打断了,或者不小心走了一下神,就很可能出现流程错误了。

    image

    我们都知道,只要不断进行 刻意练习,算法最终一定能烂熟于胸,就如魔方的公式手法一样,形成肌肉记忆和条件反射。但是对于有可能只会执行一两次的算法,我们往往没有必要付出那么高昂的代价。其实,我们只要在执行过程中多加一个环节,就能轻松解决这个问题:

    首先,把算法复制到一个可靠的媒介上,然后把它放在合适的位置,确保自己在执行过程中随时都能看到。这样一来,我们就不需要去记忆算法的所有步骤了。比如我们可以把菜谱打印出来贴在厨房的墙上,或者把显示菜谱的手机或IPAD放在一个稳妥的地方。

    其次,我们要在 每做完一个步骤之后,把它和未做完的步骤区分开。 比如在完成的步骤上打一个对号,或者干脆把它划掉。如果使用手机或IPAD,可以向上滑动让已完成的步骤移出屏幕。如果不方便腾出手来做标记的话,也可以给每个步骤编上号码,然后记住当前正在执行步骤的编号。

    这样一来,就算我们被突发事件打断了执行过程,也可以通过做好的标记来得知自己已经完成了哪些步骤,下一个步骤是什么。然后检查当前步骤是否被执行过并确认执行进度,在之前完成的进度基础上继续执行。

    2、细节偏差

    另外一个常见的问题就是 把握不好分寸,要么做不到位要么就做过了。很多算法里缺乏对细节的描述(比如:放适量盐、倒入酱油……),这往往是因为作者认为某些细节是常识或者共识,或者认为这个细节无关紧要,于是就没有写到算法里。

    image

    如果这个算法的执行结果对我们来说非常重要,不能出任何闪失,且条件允许的话,最好能联系到算法作者本人来确定丢失的细节。但如果是从网上找来的算法,往往根本不知道作者是谁。有时即便是算法里标注了细节(比如:放5克盐),我们往往也不具备条件去度量。那到底该怎么办呢?

    其次,如果有专业人士在场,那就请他来给你提供反馈,在把调料放到锅里之前让他把一下关,帮忙判断一下量是否合适。这样就是在利用别人长期积累下来的经验,帮助我们快速形成一个初步的判断标准。当然了,最好能让他先做一次示范,你再进行模仿。

    如果你是一个人孤军奋战,那就只能先凭感觉尝试,再根据反馈来进行调整了。如果第一次做盐放太多咸了,第二次就少放一些;第二次做盐放太少淡了,第三次就多放一些……几次下来,我们就知道放多少盐合适了。只不过,这样的试错成本也太高了,有没有更好的办法呢?

    第一种思路是:对本次操作的数量进行分解;其原理是通过提升精度来减少误差。比如说给一锅炖好的汤里放盐,我们可以先捏一点点盐放进去,搅拌均匀后舀一勺尝尝味道,然后再放一点点,如此反复直到味道满意为止。这样就可以避免一次手抖放盐太多,结果毁了整锅汤的情况。

    第二种思路是:对本次操作的影响面进行隔离;其原理是通过隔离来规避单次风险。比如说我们腌了十二只鸡翅,但不要一次性都放到油锅里煎,而是先煎上一只试试。万一不小心煎焦了,损失也可以承担得起。第一次过后,我们就大概知道该怎么煎、煎多久才能熟了,然后可以再煎一只……直到煎出来的效果差不多满意了,再把剩下的鸡翅一次性都煎了。这样就可以避免一次性全下锅,结果全部煎焦的可能性。

    说了这么多,你现在是不是开始害怕自己犯错搞砸了,心里已经开始打退堂鼓了呢?俗话不是说「多做多错,少做少错,不做不错」嘛,那干脆还是不要做好了,这样就不会错了呢……

    要知道,我们是人不是机器,完全不犯错误是不可能的。再说了,我们手中的算法也并不是通往目标唯一的途径,不过是无数条道路中的一条而已。当你有意或无意犯下一个错误时,其实就是开启了一条新的分支。要知道,很多人类历史上影响重大的发明(比如:青霉素),都是起源于一次无心犯下的错误。

    事实上,在有保护的环境下大量试错,再总结反思,是最高效的学习方式。正如你一直不敢下水,那么就算读再多的书、看再多的教学视频,也是学不会游泳的。学游泳最快的方法就是:多下水、多扑腾,难道不是吗?

    所谓高手,不过就是把所有能犯的错误几乎都犯过一遍的人而已。

    「试一试」 准备好一个自己从来没有执行过的算法,然后用上面所述的方法来执行。你在执行过程中都犯了哪些错误?出错的原因是什么?导致的结果是什么?你的收获是什么?

    7. 我们该怎么应对意外和失败?

    俗话说:“计划总是赶不上变化”。不管你做了多么充分的准备,也不能完全避免各种 意外 的发生,比如下面这两种最常见的情况:

    1. 有样东西之前没有考虑到,所以根本 没准备
    1. 之前准备好的某样东西 不见了 / 不够了 / 不能用了

    一旦意外发生,你不得不花额外的时间和精力去做新的准备,才能继续执行下一步。如果你在做准备时没有预留富余,就很容易陷入进退两难的境地。比如可乐鸡翅算法中的第一步是“用牙签在鸡翅上扎些洞”,如果在执行算法时我们突然发现家里没有牙签了,也没有多余的时间再去超市买,那该怎么办呢?

    这时,你应该思考下面这些问题:

    • 这一步的作用和意义是什么?它对结果有什么影响?

    • 有没有替代的方法可以达到类似的效果?代价如何?

    • 省略这一步,会引发什么后果?我能承受吗?

    image

    理解了一个步骤的作用和意义后,我们就可以考虑 用其他方法来实现。如果跳过这个步骤带来的损失很小,在我们可以承受的范围,那么 也可以选择忽略 它。如果你明白在鸡翅上扎洞是为了在腌制时让调料更入味的话,就可以用菜刀在鸡翅两侧划几个小口来起到同样的效果。事实上,就是跳过这一步不做,影响也不大。

    你可能会想问:那如果出现问题的是非常关键的步骤,既不能忽略、也找不到其他方法来实现怎么办呢?比如你只买了一瓶可乐,临到用的时候才发现被不明真相的家人给喝了……那可乐鸡翅还怎么做呢?

    image

    这时你就需要站在更高的层次来思考:

    • 我为什么要执行这个算法?

    • 我想达成的目标是什么?

    • 我能不能换一个算法来实现这个目标?

    • 我设立这个目标的动机是什么?

    • 我能不能从同样的动机出发,重设一个目标?

    我们总是出于某种动机而设立目标,又为了达成目标而寻找并执行算法。执行当前算法只是抵达目标的途径,而不是目标本身。我们 千万不要本末倒置,把“执行当前的算法”当成了自己的目标。 你可能只是想给家人一个惊喜罢了,那么为什么非要做可乐鸡翅呢,能不能做雪碧鸡翅、红烧鸡翅、蒜香鸡翅……?如果因为各种原因最后鸡翅没做成或者没做好,你冲家人发脾气合适吗?难道你忘了自己做鸡翅的动机是什么吗?

    事实上,第一次尝试就成功的概率很低,失败才是常态。因为没有经验,你可能每个步骤都没做到位,还不断出现各种意外……结果就是根本达不到算法预期的效果,甚至连最基本的合格线(比如:让人能咽下去)都达不到,这都是十分正常的。

    费了这么多气力,却没有达成预定目标,你估计会很气馁吧?也许你还会怀疑自己是不是不适合做这件事,甚至后悔自己做出这个决定……然而,** 如果你就此放弃了继续尝试,那你就彻底失败了。**这次失败的经历将不会给你产生任何积极意义,甚至会成为你内心挥之不去的阴影,给你持续带来痛苦和烦恼……你一定不希望最后变成这样,对吧?

    想象一下小婴儿学步的场景,有谁不是经历多次跌倒和失败,最终才摇摇晃晃站起来的呢?又有谁竟然会选择中途放弃,最终没能学会走路呢?我们应该从失败中吸取经验和教训,让自己得到成长和进步,下次继续勇敢地尝试。当我们把失败看做学习和成长的机会时,它便会变成生命中宝贵的经验和财富。

    image

    有了经验积累之后,你下次执行算法时的成功率和执行效果都会明显提升。因为你知道哪些环节可能出问题;出了问题该怎么解决,哪些方法试过靠谱、哪些方法试过不靠谱;哪些材料需要多准备一些;哪种调料要少放点;哪种调料要多放点……你下一次做的肯定会比这次更成功,不过前提是你得有下一次。

    你的第一个挑战目标应该已经完成了吧?那么,你的下一个目标是什么?

    「试一试」
    设立一个新目标,运用到目前为止你所学到的策略和方法去实现它。你有遇到意外吗?你是怎么处理的?你对结果满意吗?你一共尝试了几次?最近一次比起第一次来,那些方面有进步?

    (全文完)

    相关文章

      网友评论

        本文标题:《编程原来是这么回事》算法篇(下)

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