您最喜欢的算法和它教给您的课程

时间:2008-08-25 15:55:42

标签: algorithm language-agnostic

什么算法教你最多关于编程或特定语言功能?

我们所有人都知道,我们已经知道,我们已经学会了一个重要的教训,基于最终理解程序员在进化阶梯上的几个步骤编写的算法。谁的想法和代码对你有神奇的触觉?

33 个答案:

答案 0 :(得分:32)

一般算法:

  • Quicksort(以及它的平均复杂度分析)表明随机化输入可能是一件好事!;
  • 平衡树(例如AVL trees),一种平衡搜索/插入成本的巧妙方法;
  • 图上的
  • DijkstraFord-Fulkerson算法(我喜欢第二个有很多应用程序的事实);
  • LZ *系列压缩算法(例如LZW),数据压缩对我来说听起来很神奇,直到我发现它(很久以前:));
  • FFT,无处不在(在许多其他算法中重复使用);
  • simplex算法,无处不在。

数字相关:

  • Euclid算法计算两个整数的gcd:第一个算法之一,简单而优雅,功能强大,有很多概括;
  • 整数的快速乘法(例如Cooley-Tukey);
  • 牛顿迭代反转/找到一个根,一个非常强大的元算法。

数论相关:

  • AGM - 相关算法(examples):导致非常简单和优雅的算法来计算pi(以及更多!),尽管理论非常深刻(Gauss引入了椭圆函数和模块形式)从中,你可以说它产生了代数几何......);
  • number field sieve(对于整数分解):非常复杂,但理论结果相当不错(这也适用于AKS算法,证明PRIMES在P)。

我也非常喜欢研究量子计算(例如ShorDeutsch-Josza算法):这教你开箱即用。

如您所见,我对数学导向算法有点偏向:)

答案 1 :(得分:17)

“迭代是人,回归神圣” - 1989年在大学引用。

P.S。 Woodgnome发布时等待邀请加入

答案 2 :(得分:10)

Floyd-Warshall all-pairs shortest paths algorithm

procedure FloydWarshall ()
   for k := 1 to n
     for i := 1 to n
        for j := 1 to n
          path[i][j] = min ( path[i][j], path[i][k]+path[k][j] );

这就是为什么它很酷:当你第一次了解图论理论课程中的最短路问题时,你可能从Dijkstra算法开始,该算法解决了单个 - 源最短路径。一开始它很复杂,但是你克服它,你完全理解它。

然后老师说“现在我们想要解决同样的问题,但所有来源”。你自己想,“天啊,这将是一个更难的问题!它将比Dijkstra的算法复杂至少N倍!”。

然后老师给你Floyd-Warshall。而你的思想爆炸了。然后你开始讨论算法的简单程度。它只是一个三重嵌套的循环。它只为数据结构使用一个简单的数组。


对我来说,最令人瞩目的部分是以下实现:说你有问题A的解决方案。然后你有一个更大的“超级问题”B,其中包含问题A.问题B的解决方案实际上可能比问题A的解决方案。

答案 3 :(得分:9)

Quicksort。它向我展示了递归可以是强大而有用的。

答案 4 :(得分:9)

霍夫曼编码将是我的,我最初通过最小化将文本编码的位数从8减少到较少来制作我自己的哑版本,但是根据频率没有考虑可变位数。然后我在杂志的一篇文章中找到了霍夫曼编码,它开辟了许多新的可能性。

答案 5 :(得分:9)

这个听起来可能微不足道,但这对我来说是一个启示。 我参加了我的第一个编程课程(VB6),教授刚给我们讲了随机数,他给出了以下说明:“创建一个虚拟彩票机。想象一下,玻璃球上有100个标有0到99的乒乓球。随机选择并显示它们的编号,直到它们全部被选中,没有重复。“

其他人都这样编写了他们的程序:选择一个球,将其编号放入“已选择的列表”中,然后选择另一个球。检查它是否已被选中,如果是这样选择另一个球,如果没有将它的号码放在“已选择的列表”等等....

当然,到最后他们正在进行数百次比较,以找到尚未被挑选的几个球。这就像选择它们后将球扔回罐子里一样。我的启示是在采摘后丢球。

我知道这听起来令人头晕目眩,但这就是“编程开关”在我脑海中浮现的那一刻。这是编程从尝试学习一门奇怪的外语到试图找出一个令人愉快的谜题的时刻。一旦我在编程和乐趣之间建立了心理联系,那真的没有阻止我。

答案 6 :(得分:6)

Bresenham's line drawing algorithm让我对实时图形渲染感兴趣。这可以用于渲染填充的多边形,如三角形,用于3D模型渲染等。

答案 7 :(得分:5)

Recursive Descent Parsing - 我记得这么简单的代码可以做些看起来如此复杂的事情。

答案 8 :(得分:4)

Haskell的Quicksort:

qsort []     = []
qsort (x:xs) = qsort (filter (< x) xs) ++ [x] ++ qsort (filter (>= x) xs)

虽然我当时不能编写Haskell,但我确实理解了这段代码以及它的递归和快速排序算法。它只是点击它,那是...

答案 9 :(得分:3)

Fibonacci的迭代算法,因为对我来说,它确定了最优雅的代码(在这种情况下,递归版本)并不一定是最有效的。

详细说明 - “fib(10)= fib(9)+ fib(8)”方法意味着将fib(9)评估为fib(8)+ fib(7)。因此,对fib(8)(以及因此fib7,fib6)的评估将被评估两次。

迭代方法(forrop中的curr = prev1 + prev2)不会以这种方式生成,也不会占用太多内存,因为它只有3个瞬态变量,而不是递归堆栈中的n个帧。

在编程时,我倾向于寻求简单,优雅的代码,但是这个算法帮助我意识到这不是编写优秀软件的最终结果,最终结束用户不关心代码的外观。

答案 10 :(得分:3)

Minimax告诉我国际象棋程序并不聪明,他们可以考虑比你更多的进步。

答案 11 :(得分:3)

出于某种原因,我喜欢Schwartzian transform

@sorted = map  { $_->[0] }
          sort { $a->[1] cmp $b->[1] }
          map  { [$_, foo($_)] }
                @unsorted;

其中foo($ )表示计算密集型表达式,它接受$ (列表中的每个项目)并生成相应的值,以便进行比较。

答案 12 :(得分:2)

我不知道这是否算作算法,或者只是经典黑客。在任何一种情况下,它都有助于让我开始在盒子外思考。

在不使用中间变量的情况下交换2个整数(在C ++中)

void InPlaceSwap (int& a, int &b) {
     a ^= b;
     b ^= a;
     a ^= b;
}

答案 13 :(得分:2)

Quicksort:在我上大学之前,我从未质疑蛮力冒泡排序是否是最有效的排序方式。它看似直观明显。但是,接触Quicksort这样的非显而易见的解决方案让我看到了明显的解决方案,看看是否有更好的解决方案。

答案 14 :(得分:2)

对我而言,它是弱堆算法,因为它表明(1)明智选择的数据结构(以及处理它的算法)能够影响性能,以及(2)即使在旧的情况下也能发现有趣的东西,众所周知的事情。 (弱堆是所有堆排序的最佳变体,八年后是proven。)

答案 15 :(得分:1)

RSA向我介绍了模运算的世界,可用于solve a surprising number of {{3 }} interesting

答案 16 :(得分:1)

没有教会我多少,但Johnson–Trotter Algorithm永远不会让我大吃一惊。

答案 17 :(得分:1)

我没有收藏 - 有很多美丽的选择 - 但我总是觉得有趣的是Bailey–Borwein–Plouffe (BBP) formula,这使你能够计算pi的任意数字而不知道前面的数字。

答案 18 :(得分:1)

Binary decision diagrams虽然形式上不是算法而是数据结构,但它可以为各种(布尔)逻辑问题提供优雅和最小的解决方案。它们的发明和开发是为了最大限度地减少芯片设计中的门数,并且可以被视为硅革命的基础之一。由此产生的算法非常简单。

他们教给我的是什么:

  • 任何问题的紧凑表示很重要;小是美丽的
  • 递归应用的一小组约束/缩减可用于实现此
  • 对于对称问题,转换为规范形式应该是第一步考虑
  • 并非所有文献都被阅读过。 Knuth在发明/介绍几年后发现了BDD。 (花了将近一年的时间来调查它们)

答案 19 :(得分:1)

出于某种原因,Bubble Sort一直都很突出。不是因为它优雅或好,只是因为它有/我有一个愚蠢的名字。

答案 20 :(得分:1)

这是一个缓慢的:)

通过理解Duffs DeviceXOR swaps

,我通常了解了很多关于C和计算机的知识

编辑:

@ Jason Z,那是我的XOR交换:)很酷不是吧。

答案 21 :(得分:0)

@Krishna Kumar

按位解决方案比递归解决方案更有趣。

答案 22 :(得分:0)

一种算法,通过将每个数字与当前的素数列表进行比较来生成素数列表,如果未找到则添加它,并在结尾处返回素数列表。以几种方式引人注目,其中最重要的是将部分完成的输出用作主要搜索标准。

答案 23 :(得分:0)

在一个单词中存储两个指针,用于双向链表,这教会了我可以用C做非常糟糕的事情(保守的GC会有很多麻烦)。

答案 24 :(得分:0)

我最骄傲的解决方案是写一些与DisplayTag包非常相似的东西。它教会了我很多关于代码设计,可维护性和重用的知识。我在DisplayTag之前写的很好,它已经陷入了NDA协议,所以我无法开源,但我仍然可以在求职面试中热情地谈论那个。

答案 25 :(得分:0)

不是我最喜欢的,但用于测试素数的Miller Rabin Algorithm告诉我,几乎所有时间都是正确的,几乎所有时间都足够好。 (即不要仅仅因为它有错误的概率而不信任概率算法。)

答案 26 :(得分:0)

地图/减少。两个简单的概念相互配合,使数据处理任务的加载更容易并行化。

哦......而且它只是大规模并行索引的基础:

http://labs.google.com/papers/mapreduce.html

答案 27 :(得分:0)

  

Fibonacci的迭代算法,因为对我来说,它确定了最优雅的代码(在这种情况下,递归版本)并不一定是最有效的。

     

迭代方法(forrop中的curr = prev1 + prev2)不会以这种方式生成,也不会占用太多内存,因为它只有3个瞬态变量,而不是递归堆栈中的n个帧。

你知道斐波那契有一个封闭形式的解决方案,允许在固定的步骤中直接计算结果,对吧?即,(phi n - (1-phi) n )/ sqrt(5)。它总是让我觉得有点显着,它应该产生一个整数,但确实如此。

当然,phi是黄金比例; (1 + sqrt(5))/ 2。

答案 28 :(得分:0)

Towers of Hanoi algorithm是最漂亮的算法之一。它展示了如何使用递归以比迭代方法更优雅的方式解决问题。

或者,Fibonacci级数的递归算法和计算数字的幂表明递归算法的反向情况是为了递归而不是提供好的值。

答案 29 :(得分:0)

二进制搜索必须是最简单优雅的算法。因为数据需要进行排序,为此合并排序算法也是最简单和优雅的。

答案 30 :(得分:0)

对我而言,Kelly&amp; amp;中的简单交换当我第一次看到它时,Pohl的一本关于C 的书来演示按引用的方式将我翻出来。我看着那个,指针突然插入到位。逐字。 。

void swap(int *p, int *q)
{
   int temp;

   temp = *p;
   *p = *q;
   *q = temp;
}

答案 31 :(得分:0)

  1. 使用矩阵算法计算O(log N)中的Fibonacci
  2. 使用傅里叶变换进行大数乘法
  3. 经验教训是,可以在非常意外的领域找到解决方案,并且算法和数学的不同领域之间存在非常令人惊讶的联系。

答案 32 :(得分:0)

尚未引用的一些算法,原则或技巧: