Este artículo se sumergirá en los principios del diseño de algoritmos. Si no tienes idea de a qué me refiero, sigue leyendo.!
Cuando escuchas la palabra "algoritmo", probablemente respondas de una de estas tres formas:
Si eres uno de los dos siguientes, este artículo es para ti..
Los algoritmos no son un tipo especial de operación, necesariamente. Son conceptuales, un conjunto de pasos que se toman en el código para alcanzar un objetivo específico..
Los algoritmos se han definido comúnmente en términos simples como "instrucciones para completar una tarea". También se les ha llamado "recetas". En La red social, Un algoritmo es lo que Zuckerberg necesitaba para hacer funcionar Facemash. Si viste la película, probablemente recuerdes haber visto lo que parecía una ecuación garabateada en una ventana del dormitorio de Mark. Pero, ¿qué tiene que ver ese álgebra de garabatos con el simple sitio "hot or not" de Mark??
Los algoritmos son de hecho instrucciones. Quizás una descripción más precisa sería que los algoritmos son patrones para completar una tarea de una manera eficiente. Facemash de Zuckerberg era un sitio de votación para determinar el atractivo de alguien en relación con todo un grupo de personas, pero al usuario solo se le darían opciones entre dos personas. Mark Zuckerberg necesitaba un algoritmo que decidiera qué personas se unían entre sí, y cómo valorar un voto en relación con la historia previa de esa persona y los candidatos anteriores. Esto requería más intuición que simplemente contar los votos para cada persona..
Por ejemplo, digamos que desea crear un algoritmo para sumar 1 a cualquier número negativo, y restar 1 de cualquier número positivo, y no hacer nada con 0. Puede hacer algo como esto (en el pseudo código de JavaScript):
función addOrSubtractOne (número) si (número < 0) return number + 1 else if (number < 0) return number - 1 else if (number == 0) return 0;
Puede que te digas a ti mismo: "Esa es una función". Y tienes razón. Los algoritmos no son un tipo especial de operación, necesariamente. Son conceptuales: un conjunto de pasos que debe seguir en el código para alcanzar un objetivo específico..
Entonces, ¿por qué son un gran problema? Claramente, sumar o restar 1 a un número es una cosa bastante simple de hacer.
Pero hablemos por un segundo sobre la búsqueda. Para buscar un número en una serie de números, ¿cómo pensarías hacerlo? Un enfoque ingenuo sería iterar el número, comparando cada número con el que está buscando. Pero esta no es una solución eficiente, y tiene un rango muy amplio de tiempos de finalización posibles, lo que la convierte en un método de búsqueda errático y poco confiable cuando se escala a grandes conjuntos de búsqueda..
función naiveSearch (aguja, pajar) para (var i = 0; i < haystack.length; i++) if (haystack[i] == needle) return needle; return false;
Afortunadamente, podemos hacerlo mejor que esto para la búsqueda..
No hay mejor manera de convertirse en un mejor diseñador de algoritmos que tener un profundo conocimiento y apreciación de los algoritmos..
Digamos que su matriz tiene 50,000 entradas y la búsqueda de fuerza bruta (es decir, la búsqueda mediante la iteración de la matriz completa). La entrada que está buscando, en el mejor de los casos, será la primera entrada en la matriz de 50,000 entradas. Sin embargo, en el peor de los casos, el algoritmo tardará 50,000 veces más en completarse que en el mejor de los casos..
En su lugar, buscarías usando la búsqueda binaria. Esto implica ordenar la matriz (sobre la que le permitiré aprender por su cuenta) y, posteriormente, dividir la matriz por la mitad, y verificar si el número de búsqueda es mayor o menor que la marca de la mitad de la matriz. Si es mayor que la marca de la mitad de una matriz ordenada, entonces sabemos que la primera mitad se puede descartar, ya que el número buscado no forma parte de la matriz. También podemos recortar mucho trabajo definiendo los límites externos de la matriz y verificando si el número buscado existe fuera de esos límites, y si es así, tomamos lo que habría sido una operación de múltiples iteraciones y lo convertimos en una sola operación de iteración (que en el algoritmo de fuerza bruta habría tomado 50,000 operaciones).
sortedHaystack = recursiveSort (haystack); función bBuscar (aguja, ordenadoHaystack, firstIteration) si (firstIteration) si (aguja> sortedHaystack.last || aguja < 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);
Tome la naturaleza aparentemente complicada de un único algoritmo de búsqueda binario y aplíquelo a miles de millones de posibles enlaces (como buscar en Google). Más allá de eso, apliquemos algún tipo de sistema de clasificación a esas búsquedas vinculadas para dar un orden de páginas de respuesta. Mejor aún, aplique algún tipo de sistema de "sugerencia" aparentemente aleatorizado basado en modelos sociales de inteligencia artificial diseñados para identificar a quién le gustaría agregar como amigo.
Esto nos da una comprensión mucho más clara de por qué los algoritmos son más que un nombre elegante para las funciones. En su máxima expresión, son formas inteligentes y eficientes de hacer algo que requiere un mayor nivel de intuición que la solución más aparente. Pueden tomar lo que podría requerir un año de supercomputadora y convertirlo en una tarea que termina en segundos en un teléfono móvil..
Para la mayoría de nosotros como desarrolladores, no estamos diseñando algoritmos abstractos de alto nivel diariamente..
Por suerte, nos apoyamos en los desarrolladores que vinieron antes que nosotros, que escribieron funciones de ordenación nativas y nos permiten buscar cadenas para subcadenas con indexOf de manera eficiente..
Pero HACEMOS, sin embargo, tratamos con algoritmos propios. Nosotros creamos para
Bucles y funciones de escritura todos los días; Entonces, ¿cómo pueden los buenos principios de diseño de algoritmos informar la escritura de estas funciones?
Uno de los principios principales del diseño algorítmico es, si es posible, construir su algoritmo de tal manera que la entrada haga parte del trabajo por usted. Por ejemplo, si sabe que su entrada siempre será números, no necesita tener excepciones / verificaciones para cadenas, o coaccionar sus valores en números. Si sabe que su elemento DOM es el mismo cada vez que en un para
bucle en JavaScript, no debería consultar ese elemento en cada iteración. En el mismo token, en tu para
bucles, no debe usar funciones de conveniencia con sobrecarga si puede lograr lo mismo usando (más cerca) operaciones simples.
// no hagas esto: para (var i = 1000; i> 0; i -) $ ("# foo"). append ("bar"); // haga esto en su lugar var foo = $ (" # foo "); var s =" "; para (var i = 1000; i> 0; i -) s + ="bar"; foo.append (s);
Si usted es un desarrollador de JavaScript (y utiliza jQuery) y no sabe qué hacen las funciones anteriores y en qué se diferencian significativamente, el siguiente punto es para usted..
En su máxima expresión, los [algoritmos] son formas inteligentes y eficientes de hacer algo que requiere un mayor nivel de intuición que la solución más aparente..
Es fácil pensar que no hace falta decirlo. Sin embargo, hay una diferencia entre "saber cómo escribir jQuery" y "entender jQuery". Comprender sus herramientas significa que comprende lo que hace cada línea de código, tanto de inmediato (el valor de retorno de una función o el efecto de un método) como implícitamente (la sobrecarga que se asocia con la ejecución de una función de biblioteca, o cuál es la más eficiente). método para concatenar una cadena). Para escribir excelentes algoritmos, es importante conocer el rendimiento de las funciones o utilidades de nivel inferior, no solo el nombre y la implementación de las mismas..
Diseñar algoritmos eficientes es un compromiso de compromiso total. Además de comprender sus herramientas como una pieza independiente, también debe comprender la forma en que interactúan con el sistema más grande que se tiene a mano. Por ejemplo, para comprender JavaScript en una aplicación específica en su totalidad, es importante comprender el DOM y el rendimiento de JavaScript en los escenarios de varios navegadores, cómo la memoria disponible afecta la velocidad de representación, la estructura de los servidores (y sus respuestas) con los que puede estar interactuando. así como una miríada de otras consideraciones que son intangibles, tales como escenarios de uso.
En general, el objetivo del diseño de algoritmos es completar un trabajo en menos pasos. (Hay algunas excepciones, como el hash Bcrypt). Cuando escriba su código, tenga en cuenta todos De las operaciones simples que la computadora está tomando para alcanzar la meta. Aquí hay una lista de verificación simple para comenzar en un camino hacia un diseño de algoritmo más eficiente:
No hay mejor manera de convertirse en un mejor diseñador de algoritmos que tener un profundo conocimiento y apreciación de los algoritmos..
.ordenar()
, con operaciones de nivel inferior. Si no sabía qué era un algoritmo al comienzo de este artículo, es de esperar que ahora tenga una comprensión más concreta del término un tanto esquivo. Como desarrolladores profesionales, es importante que entendamos que el código que escribimos se puede analizar y optimizar, y es importante que nos tomemos el tiempo para hacer este análisis del rendimiento de nuestro código..
¿Algún algoritmo divertido de práctica has encontrado problemas? Tal vez una programación dinámica "problema mochila", o "paseo borracho"? O quizás conoce algunas de las mejores prácticas de recursión en Ruby que difieren de las mismas funciones implementadas en Python. Compártelos en los comentarios.!