前段时间在blog上写了一个humble number的代码,没有想到有热心读者坚持希望知道这个算法的实现原理,本着share的原则,今天我的作品中就来探讨一下关于这个算法是如何实现的。
我们前面分析过,最笨的一种humble number的计算方法无非是穷举数据,那么它的复杂度是很难想象的。(要知道第5842个数据已经到达20亿了)。我们下面介绍的方法是通过对种子元素(因数)快速的产生humble number。
我们假设一个因数集合为A,其元素为给出的种子元素{2,3,5,7};首先我们从种子元素中取得最小的2,其与自己相乘得到 4,插入这个集合为{2,3,4,5,7},下面我们计算2×3,得到为 6 ,6也插入这个集合{2,3,4,5,6,7},接下来的 2×4为8,同理插入{2,3,4,5,6,7,8};而2×5则比3×3要大,因此现在换成3来开始乘,3×3 = 9,插入集合;3×4=12大于了2×5,因此又换成2×5开始计算。
以上我们已经介绍了这个算法的大概原理,可能有人会说,会不会造成数据的遗漏,不会的,因为我们是对每个因数做了乘积。对于某个humble number,它必然可以通过前面某些比它小的humber number通过两者之积得到。
回到我们说的这个过程,我们看到,这个过程需要一个数组来保存humble number,而且要是排序的,这个在我们代码中用pData来保存,至于为什么是new出来呢,主要是担心堆栈的问题。
另外,我们要能保证我们求积的大小是按照从小到大来,这样能保证我们求出来的数据也能按照从小到大插入pData,由此来保证求出来数据的完备性,在这里我们用到了一个双向的排序队列(保证队头的乘机要小于队尾)。这个队列保存的信息是两个索引(也就是我们集合中让哪两个数据来相乘)。代码中的InQue和OutQue就是我们用来对这个队列进行操纵的代码,主要是链表结构,想必各位懂得一点数据结构的人都应当毫不陌生。还有一个问题就是什么时候需要更新第一个索引,例如在上面的例子中就是什么时候该计算3×3,这个是在完成2×2之后就开始的,也就是说完成了2×2之后,我们要做的比较是 2×3, 3×3,双向排序队列的首元素乘积(在队列不空的情况下)。我们的程序是一直在做这种比较,来更新最新的数据索引,如果pData中直接取得的索引大于了双向排序队列的数据,就会把数据插入到队列中,这个时候队列自动调整,使之重新成为双向排序队列,而队头元素将被交换出来。
不多说了,要是你还是不明白的话,可以运行的时候看下我写的那段输出队列的代码,其实就很容易理解了。