2020年我GET了两个算法 | 掘金年度征文

867 阅读7分钟

第一个算法

某次,在解析后端童鞋的protocol buffer时用了protobuf.js库。然后在试图拿到在注释信息时,我发现解析出来的comment属性竟然是错位的!

你在逗我?

再次确认了一下不是我也不是源文件的格式问题后,一怒之下决定调试源码,看看到底是什么鬼?

于是就看到了个包含巨大循环的状态机,大概长这样:

function parse(code) {
  let line = 0;
  let token = '';
  const parsed = {};
  function nextToken() {
    skipWhiteSpace();
    ...
  } 
  ...
  while(token = nextToken()) {
    switch(token) {
      case 'message': 
        parseMessage();
        break;
        ...
    }
  }
  function parseMessage() {
    const message = parsed[nextToken()] = {};
    nextToken(); // 跳过 '{'
    while((token = nextToken()) !== '}') {
      if (token === 'option') { parseOption() }
      else { parseType() }
    }
  }
  ...
}

一眼看过去就是个bug生产机,没个注释的还看起来超吃力,只能多加断点继续调。

然后就发现,好家伙,果然是这个巨大循环设计缺陷的锅。这个坑成功地引起了我的好奇心:有没有更好的办法?研究一下说不定可以搞篇很酷炫的博文和分享。想想就很美好,有没有?

于是百度谷歌,翻无数篇大神博客,打开了新世界。编译领域的水越潜越深。看大佬总结的算法列表感受一下:

编译算法比较

学不动了,放过我吧

不!我的问题还没有解决,我的博客还没有影子,不能半途而废!然后我看到了这:

Earley parsers are awesome, because they will parse anything you give them. Depending on the algorithm specified, popular parsers such as lex/yacc, flex/bison, Jison, PEGjs, and Antlr will break depending on the grammar you give it. And by break, I mean infinite loops caused by left recursion, crashes, or stubborn refusals to compile because of a “shift-reduce error”.

– Better Earley than never (hardmath123.github.io/earley.html)

有点意思

让咱瞧瞧你有多神!

于是先维基百科把跟我陌生的词(Earley parser, context free之类)撸了一遍。还瞄了眼人家论文都怎么写的,然后摸摸鼻子表示太好腻害,咱大学时候写的都是什么垃圾玩意儿。

英文论文混杂着跟咱学的不同标准的符号看得我很吃力。仍旧一知半解的时候,突然想到会不会有人讲解过?于是我又在优酷,youtube上撸了一遍能找到的视频。大部分人就一笔带过介绍一下(我怀疑其实你们根本没懂),讲得比较清楚的还是印度小哥哥小姐姐,口音重了点,跟着节奏摇起头来多听两遍就懂了七七八八。

于是磨拳擦掌写博客。写到一半,又发现,好吧我明白了这算法里的动态规划怎么玩,但无论是视频还是所有看的资料里都没讲清楚最后也是最重要的部分。动态规划其实把所有可能性都列出来了,但到最后还得根据一定条件选择其中合适的对吧?但人家就一笔带过了像这样:

The state (P → S •, 0) represents a completed parse. This state also appears in S(3) and S(1), which are complete sentences.

– Wikipedia (en.wikipedia.org/wiki/Earley…)

一脸懵逼

最后幸好社区有相关的开源项目,通过阅读源码解决了我的最后一公里。

第二个算法

第一个算法的研究虽然费力了一些,但感觉收获颇丰,并且对此信心大增。接着我翻出了一个在待办事项里躺了很久的问题:听说有个一个牛逼的排序算法Tim sort,有多牛?

我照猫画虎,百度谷歌搜索搜索搜索……然而这次竟然啥!都!没!有!

怎么可能?不是很牛逼吗?我怀疑我被骗了!

我怀疑我被骗了

从开始到放弃的前一秒,挖到了原作者朴素的文章:bugs.python.org/file4451/ti… (卧槽竟然是txt!?)

看到归并排序,插入排序老朋友,好说好说。不,不过这个gallop mode是什么鬼?

维基百科这样说:

An individual merge of runs R1 and R2 keeps the count of consecutive elements selected from a run. When this number reaches the minimum galloping threshold (min_gallop), Timsort considers that it is likely that many consecutive elements may still be selected from that run and switches to the galloping mode. Let us assume that R1 is responsible for triggering it. In this mode, the algorithm performs an exponential search, also known as galloping search, for the next element x of the run R2 in the run R1. This is done in two stages: the first one finds the range (2k − 1, 2k+1 - 1) where x is. The second stage performs a binary search for the element x in the range found in the first stage. The galloping mode is an attempt to adapt the merge algorithm to the pattern of intervals between elements in runs.

不懂

好吧!撩起袖子撸C源码!咱几年前学过,我不怕你!然后看着到处乱飞的* &内存操作符风中凌乱。大叔你确定这代码你写完还能维护?

注释不多,我就对照着Tim大叔的文章推敲每一段写法的意图。然后这篇博客就诞生了:深度剖析Tim Sort - Pyhon及Chrome引擎v8使用的高效排序算法

虽然这次感觉自己读够透了代码才写的博客,但是写着写着又发现漏掉了不少细节,解释不清楚。最后又来回翻看了几遍才完成。

收获的不仅仅是算法

也许你会问这除了酷炫学来何用?(反正大前端是不太可能会用的🤷‍♀️)我觉得吧有2点:

一是打开思路、激发创意。算法其实是种用巧妙的思维方式轻松解决一个难题的方法,它不是一成不变的老古板,它的能力大小完全取决于怎么被使用。像Earley parser,其实本质上用了动态规划,但它通过设计合适动态规划项的数据结构,和填入规划表里的方式步骤成为了一个全新的算法,一个有趣的编译器。而Tim sort,就是多个经典算法的结合,根据现实世界的统计选择在合适的时候用较为高效的算法解决问题。

二是学习方式。在这个信息易得、碎片化的时代,固守成规以求在课堂上跟着老师学习或者工作中跟着领导和资深专家学习是远远不够的!这里经我验证,有一个让人有动力持续学习技术,并且学得更深的方法,总结下来有这些步骤:

  1. 任何听到不明白的,感兴趣的话题,记录下来。因为你太忙了,现在不一定有时间探索,以免回头就忘了。
  2. 闲暇时候,翻出这些记录,选择一个,搞起!
  3. 定至少一个标志完成的小目标,比如发布一篇博客,做一次分享,写一遍代码……完成这个目标的执着是在“想放弃”时候最大的动力!另外,输出的过程往往可以让你达到更深一层的理解,发现被自己忽略的细节。
  4. 任何不懂的部分,都不要放过,往下挖资料。包括一个词,背后这么做的原因,后续的发展,相关的项目和应用等等。 查询的资料源注意要有多样化,通常没有什么是能完美覆盖所有你需要的知识的。查一下百科可以快速了解概况,拿到一些直接有联系的资料链接。通过视频网站可以直观地看到步骤、效果。多翻几篇文章可以从不同角度更深入地了解这是什么,为什么,怎么做。通过相关课程和书籍可以了解整个体系……
  5. 完成定下的下目标后,为自己鼓掌,奖励一下自己。然后就会有下一次,下下一次,做得更多,更好。

共勉。2021再见!

掘金年度征文 | 2020 与我的技术之路 征文活动正在进行中......

加我加我