Heim >Web-Frontend >js-Tutorial >Gewinnen Sie ein tieferes Verständnis der Grundlagen des Algorithmusdesigns
Dieser Artikel befasst sich mit den Prinzipien des Algorithmusdesigns. Wenn Sie nicht wissen, was ich meine, lesen Sie weiter!
Wenn Sie das Wort „Algorithmus“ hören, können Sie auf eine von drei Arten reagieren:
Wenn Sie zu den beiden Letzteren gehören, dann ist dieser Artikel genau das Richtige für Sie.
Algorithmen sind nicht unbedingt eine spezielle Art von Operation. Sie sind konzeptionell, eine Reihe von Schritten, die Sie in Ihrem Code ausführen, um ein bestimmtes Ziel zu erreichen.
Algorithmen werden oft einfach als „Anweisungen zur Erledigung einer Aufgabe“ definiert. Sie werden auch „Rezepte“ genannt. In The Social Network benötigte Zuckerberg einen Algorithmus, damit Facemash funktioniert. Wenn Sie den Film gesehen haben, erinnern Sie sich wahrscheinlich daran, etwas gesehen zu haben, das wie eine hingekritzelte Gleichung an Marks Wohnheimfenster aussah. Aber was hat diese gekritzelte Algebra mit Marks einfacher „Hot or Not“-Website zu tun?
Algorithmen sind in der Tat Anweisungen. Eine vielleicht genauere Beschreibung wäre, dass Algorithmen Muster für die effiziente Erledigung von Aufgaben sind. Zuckerbergs Facemash ist eine Umfrageseite, die dazu dient, die Attraktivität einer Person im Vergleich zu einer ganzen Gruppe zu ermitteln, aber Benutzer können nur zwischen zwei Personen wählen. Mark Zuckerberg benötigt einen Algorithmus, um zu entscheiden, welche Personen zueinander passen und wie der Wert einer Stimme auf der Grundlage der Vorgeschichte dieser Person und früherer Kandidaten bewertet wird. Dies erfordert mehr Intuition als nur das Zählen aller Stimmen.
Angenommen, Sie möchten einen Algorithmus erstellen, der 1 zu jeder negativen Zahl addiert, dann 1 von jeder positiven Zahl subtrahiert und mit 0 nichts macht. Sie können so etwas tun (mit JavaScript-ähnlichem Pseudocode):
function addOrSubtractOne(number){ if (number < 0) { return number + 1 } else if (number < 0) { return number - 1 } else if (number == 0) { return 0; } }
Sie sagen sich vielleicht: „Das ist eine Funktion.“ Ein Algorithmus ist nicht unbedingt eine spezielle Art von Operation. Sie sind konzeptionell – eine Reihe von Schritten, die Sie in Ihrem Code ausführen, um ein bestimmtes Ziel zu erreichen.
Warum sind sie also wichtig? Offensichtlich ist das Addieren oder Subtrahieren von 1 zu einer Zahl eine ziemlich einfache Sache.
Aber lasst uns über die Suche sprechen. Was würden Sie tun, um in einem Zahlenarray nach einer Zahl zu suchen? Eine einfache Möglichkeit besteht darin, die Zahl zu durchlaufen und jede Zahl mit der gesuchten Zahl zu vergleichen. Dies ist jedoch keine effiziente Lösung und die Spanne möglicher Abschlusszeiten ist groß, was sie bei der Skalierung auf große Suchmengen zu einer instabilen und unzuverlässigen Suchmethode macht.
function naiveSearch(needle, haystack){ for (var i = 0; i < haystack.length; i++){ if (haystack[i] == needle) { return needle; } } return false; }
Glücklicherweise können wir mit der Suche bessere Ergebnisse erzielen.
Es gibt keinen besseren Weg, ein besserer Algorithmendesigner zu werden, als Algorithmen tiefgreifend zu verstehen und zu schätzen.
Angenommen, Ihr Array hat 50.000 Einträge und Sie führen eine Brute-Force-Suche durch (d. h. eine Suche durch Iteration über das gesamte Array). Im besten Fall ist der gesuchte Eintrag der erste Eintrag in einer Liste von 50.000 Einträgen. Im schlimmsten Fall dauert die Fertigstellung des Algorithmus jedoch 50.000 Mal länger als im besten Fall.
Stattdessen können Sie mit der binären Suche suchen. Dazu gehört das Sortieren des Arrays (ich überlasse es Ihnen, es selbst herauszufinden), das anschließende Teilen des Arrays in zwei Hälften und das Überprüfen, ob die Suchzahl größer oder kleiner als die mittlere Markierung im Array ist. Wenn sie größer als die mittlere Markierung des sortierten Arrays ist, wissen wir, dass die erste Hälfte verworfen werden kann, da die gesuchte Zahl nicht Teil des Arrays ist. Wir können auch viel Arbeit reduzieren, indem wir die äußeren Grenzen des Arrays definieren und prüfen, ob die gesuchte Zahl außerhalb dieser Grenzen existiert. Wenn dies der Fall ist, nehmen wir mehrere Iterationen und wandeln sie in eine einzige Iteration um (in Brute-Force-Algorithmen sind 50.000 erforderlich). Operationen).
sortedHaystack = recursiveSort(haystack); function bSearch(needle, sortedHaystack, firstIteration){ if (firstIteration){ if (needle > sortedHaystack.last || needle < sortedHaystack.first){ return false; } } if (haystack.length == 2){ if (needle == haystack[0]) { return haystack[0]; } else { return haystack[1]; } } if (needle < haystack[haystack.length/2]){ bSearch(needle, haystack[0..haystack.length/2 -1], false); } else { bSearch(needle, haystack[haystack.length/2..haystack.length], false); } }
Nehmen Sie die scheinbar komplexe Natur eines einzelnen binären Suchalgorithmus und wenden Sie ihn auf Milliarden möglicher Links an (z. B. über die Google-Suche). Darüber hinaus wenden wir eine Art Ranking-System auf diese Linksuchen an, um eine Reihenfolge der antwortenden Seiten festzulegen. Besser noch, wenden Sie eine Art scheinbar zufälliges „Vorschlagssystem“ an, das auf einem sozialen KI-Modell basiert und darauf ausgelegt ist, Personen zu identifizieren, die Sie möglicherweise als Freunde hinzufügen möchten.
Dies gibt uns ein klareres Verständnis dafür, warum Algorithmen mehr als nur ausgefallene Namen für Funktionen sind. Im besten Fall sind sie intelligente und effiziente Möglichkeiten, etwas zu erreichen, das intuitiver ist als die offensichtlichste Lösung. Sie können Aufgaben, die auf einem Supercomputer Jahre dauern könnten, in Aufgaben umwandeln, die auf einem Mobiltelefon in Sekundenschnelle erledigt werden können.
Für die meisten von uns Entwicklern entwerfen wir nicht jeden Tag abstrakte Algorithmen auf hoher Ebene.
幸运的是,我们站在前辈开发人员的肩膀上,他们编写了本机排序函数,并允许我们以有效的方式使用 indexOf 搜索字符串中的子字符串。
块引用>但是我们确实处理我们自己的算法。我们每天创建
for
循环并编写函数;那么好的算法设计原则如何指导这些函数的编写呢?了解您的输入
算法设计的主要原则之一是,如果可能的话,以输入本身为您完成一些工作的方式构建算法。例如,如果您知道您的输入始终是数字,则不需要对字符串进行异常/检查,或将您的值强制转换为数字。如果您知道 JavaScript 中的
for
循环中的 DOM 元素每次都是相同的,那么您不应该在每次迭代中查询该元素。同样,在for
循环中,如果可以使用(更接近)简单操作完成相同的操作,则不应使用有开销的便利函数。// don't do this: for (var i = 1000; i > 0; i--){ $("#foo").append("<span>bar</span>"); } // do this instead var foo = $("#foo"); var s = ""; for(var i = 1000; i > 0; i--){ s += "<span>bar</span>"; } foo.append(s);如果您是一名 JavaScript 开发人员(并且使用 jQuery),并且您不知道上述函数在做什么以及它们有何显着不同,那么下一点适合您。
了解您的工具
在最好的情况下,[算法]是聪明、有效的方法来完成比最明显的解决方案更高水平的直觉。
很容易认为这是不言而喻的。然而,“知道如何编写 jQuery”和“理解 jQuery”之间是有区别的。了解您的工具意味着您了解每一行代码的作用,既立即(函数的返回值或方法的效果)又隐式(与运行库函数相关的开销,或者哪一个是最有效的)连接字符串的方法)。要编写出色的算法,了解较低级别函数或实用程序的性能非常重要,而不仅仅是它们的名称和实现。
了解环境
设计高效的算法是一项全身心投入的工作。除了将您的工具理解为一个独立的部分之外,您还必须了解它们与手头的更大系统交互的方式。例如,要完全理解特定应用程序中的 JavaScript,重要的是要了解跨浏览器场景中 JavaScript 的 DOM 和性能、可用内存如何影响渲染速度、您可能与之交互的服务器的结构(及其响应),以及无数其他无形的考虑因素,例如使用场景。
减少工作量
一般来说,算法设计的目标是用更少的步骤完成一项工作。 (也有一些例外,例如 Bcrypt 哈希。)编写代码时,请考虑计算机为达到目标而采取的所有简单操作。以下是一个简单的清单,可帮助您开始更高效的算法设计:
- 使用语言功能来减少操作(变量缓存、链接等)。
- 尽可能减少迭代循环嵌套。
- 尽可能在循环外部定义变量。
- 使用自动循环索引(如果可用)而不是手动索引。
- 使用巧妙的缩减技术(例如递归分治和查询优化)来最大限度地减少递归过程的规模。
学习先进技术
要成为一名更好的算法设计师,没有比深入理解和欣赏算法更好的方法了。
- 每周花一两个小时阅读《计算机编程的艺术》。
- 尝试 Facebook 编程挑战赛或 Google Codejam。
- 学习使用不同的算法技术解决同一问题。
- 通过使用较低级别的操作实现语言的内置函数(例如
.sort()
)来挑战自己。
结论
如果您在本文开始时还不知道什么是算法,那么希望您现在对这个有点难以捉摸的术语有了更具体的理解。作为专业开发人员,重要的是我们要了解我们编写的代码是可以分析和优化的,而且我们花时间对代码的性能进行分析也很重要。
你发现过什么有趣的算法练习题吗?也许是动态规划“背包问题”,或者“醉酒行走”?或者您可能知道 Ruby 中的一些递归最佳实践与 Python 中实现的相同函数不同。在评论中分享它们!
Das obige ist der detaillierte Inhalt vonGewinnen Sie ein tieferes Verständnis der Grundlagen des Algorithmusdesigns. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!