Durante el concurso actual de Google Code Jam (2013) , hubo un problema que llevó a las personas de C ++ y Java a más de 200 líneas de código en comparación con las personas de Python que resolvieron el mismo problema solo con 40 líneas de código.
Python no es directamente comparable con C ++ y Java, pero la diferencia de verbosidad que pensé podría influir en la eficiencia del algoritmo.
¿Qué tan importante es conocer el algoritmo correcto en comparación con la elección del idioma? ¿Podría un programa Python excelentemente implementado implementarse en C ++ o Java de una mejor manera (usando el mismo algoritmo) y esto tiene alguna relación con la verbosidad natural de ciertos lenguajes de programación?
java
c++
algorithms
python
superspacemarines
fuente
fuente
Respuestas:
Obviamente, si considera esta pregunta en el contexto de algo como Google Code Jam, entonces el pensamiento algorítmico es claramente más importante cuando tiene que resolver problemas algorítmicos.
Sin embargo, en la vida cotidiana, también se deben considerar alrededor de un millón de otros factores, lo que hace que la pregunta sea mucho menos negra frente a blanca.
Solo un contraejemplo: si necesita 200 líneas más en Java, pero todos en su empresa conocen Java, esto no es gran cosa. Si pudieras escribirlo en 5 líneas de Python o en cualquier otro idioma, pero serías el único en la compañía en conocer ese idioma, es un gran problema. De hecho, es tan importante que ni siquiera se te permitirá hacerlo y, en cambio, tendrás que escribirlo en Java.
Desde la perspectiva de un artesano, siempre tratamos de acercarnos con la herramienta adecuada para el trabajo, pero la palabra correcta es tan difícil que uno puede equivocarse fácilmente.
Por el contrario, encontré que el pensamiento algorítmico en las empresas estaba casi ausente. Solo unas pocas personas selectas lo poseen, mientras que el Joe promedio a menudo ya tiene problemas para estimar las complejidades de tiempo de ejecución de los bucles, búsquedas, etc.
Sin embargo, en términos de competiciones algorítmicas, mi experiencia personal de competir en ellas durante varios años, me dice claramente que debes apegarte a un idioma. La velocidad es un factor importante y simplemente no puede permitirse perder el tiempo en sus herramientas, cuando debe dedicarlas a resolver los problemas dentro del límite de tiempo. También considere que escribir 200 líneas de código Java sin pensar es aún mucho más rápido que crear a mano 50 líneas de código python complicado que requiere mucho pensamiento, pero ambos resuelven más o menos el mismo problema.
Ah, y finalmente, asegúrese de comprender las principales diferencias entre el código algorítmico de competencia y el código de producción de la compañía. He visto codificadores algorítmicos fantásticos, que escribieron códigos horribles que nunca aceptaría en un producto.
fuente
Yo diría que, incluso fuera de las competiciones, el pensamiento algorítmico es más importante que conocer cada truco para un lenguaje específico.
Por supuesto, desea conocer el idioma con el que trabaja lo mejor posible, pero los idiomas van y vienen, mientras que la capacidad de pensar de manera abstracta en términos de algoritmos es una habilidad altamente transferible.
Caso en cuestión: si recuerdo bien, hubo una publicación aquí en Programmers hace un tiempo en la que alguien se quejó de haber fallado a FizzBuzz en una entrevista y culpó a su falta de conocimiento sobre el operador de módulo de Java. Esta conclusión es errónea: la falta de conocimiento sobre cómo funciona el módulo lo hizo incapaz de pensar algorítmicamente sobre el problema y resolverlo, incluso en ausencia de un operador de módulo dedicado. Yendo más allá: Java tiene una clase Tree: ¿qué pasa si, en el futuro, tiene que trabajar con un lenguaje que no implemente esta clase? Nuevamente, la capacidad de pensar sobre el problema triunfa sobre los detalles específicos del idioma.
Admito que los ejemplos son simplistas, pero ayudan a transmitir el punto.
fuente
El lenguaje importa.
DARPA y la Marina de los EE. UU. Realizaron un experimento de tiroteo hace casi 20 años. El ganador del fugitivo caballo oscuro fue Haskell. Ada y C ++ estuvieron ambos representados; Java no lo era.
Casi al mismo tiempo, Pratt & Whitney realizó un estudio de minería de datos sobre proyectos de controladores de motores a reacción, observando datos de tarjetas de tiempo y rastreadores de errores. Descubrieron que Ada daba el doble de productividad al programador y 1/4 de la densidad de defectos de cualquier otro lenguaje que estaban usando.
Atari solía usar FORTH para desarrollar videojuegos, y el hecho de que usaran FORTH se consideraba extremadamente patentado.
Los comentarios de Paul Graham sobre el uso de LISP son bien conocidos. Los comentarios de Erann Gat sobre LISP en JPL son igualmente convincentes, aunque no tan conocidos.
El software de aviónica Boeing 777 es prácticamente todo Ada. Su experiencia fue muy buena, a pesar de que un subcontratista importante tuvo que comenzar de nuevo a mitad de camino.
El lenguaje importa.
fuente
Algunos puntos:
Las primeras posiciones tienden a ser C ++ / C / Java, independientemente de cuántas líneas de código exista la diferencia entre ese y algún otro lenguaje. Esto puede ser más sobre que los codificadores principales tienden a elegir estos idiomas sobre otros, probablemente debido a su velocidad bruta.
Desafortunadamente, no puede ver fácilmente el lenguaje de programación en Google Code Jam, pero descargué algunos de los principales y, por lo que recuerdo, estos son principalmente C / C ++. TopCoder (un popular sitio de alojamiento de concursos de programación en línea) en su mayoría tiene resultados similares.
Debido a que son bastante bajo nivel, estoy bastante seguro de que no va a batir fácilmente C / C ++ en términos de tiempo de ejecución cruda (y Java no arrastrarse demasiado lejos). Según mi experiencia, los idiomas escritos dinámicamente tienden a ser significativamente más lentos que los idiomas escritos estáticamente. Es posible que la solución óptima ni siquiera sea lo suficientemente rápida en algunos idiomas, pero esto no debería ser una regla general.
El algoritmo correcto es vital. Si supiste cómo resolver todos los problemas (en gran detalle) desde el principio, y eres un codificador bueno y rápido, lo más probable es que ganes, independientemente del idioma en el que codifiques (asumiendo la solución óptima en ese idioma) es lo suficientemente rápido)
El número directo de líneas no es tan importante. Una vez que obtenga suficiente experiencia en programación, sabrá que puede pasar 10 minutos programando 10 líneas o 200 líneas, todo depende de cuán complejas sean las líneas. Además, si ha codificado un código similar cientos de veces, podrá hacerlo con bastante rapidez. Sin mencionar también todas las macros que los principales codificadores de C / C ++ suelen utilizar para optimizar su tiempo de codificación.
Frank hace un buen punto: (fuera de las competencias de programación) no se puede codificar en Python para su empresa si toda su base de código está en C o lo que sea, debe ajustarse a su lenguaje.
Es razonablemente fácil cambiar de idioma, no es fácil construir años de conocimiento de pensamiento algorítmico. Estoy dispuesto a apostar que casi cualquier programador excelente puede cambiar a otro lenguaje (vagamente similar) en, digamos, una semana. Tal vez él / ella no sea lo suficientemente bueno como para ganar competencias de programación en ese idioma (déle otras 2 semanas), pero tendrá lo básico.
fuente
¿Se puede implementar mejor la misma lógica en C ++? Por supuesto que puede, si por mejor quiere decir más rápido y más eficiente en memoria. El problema es que la cantidad de esfuerzo requerida para hacerlo es significativamente mayor. Además, en teoría, aún podría ir a un nivel inferior e implementarlo en C puro o incluso ASM, lo que tomaría aún más tiempo, pero podría tener un código aún más optimizado.
Por supuesto, en el caso de competiciones como Code Jam o TopCoder, no es un problema, ya que son solo 40 líneas frente a 200 líneas. Por otro lado, en este tipo de competencia, lo que más importa es la complejidad de tiempo / espacio del algoritmo. Mientras que en la aplicación de la vida real, YMMV, en este tipo de competencias, el algoritmo O (n) escrito en los idiomas más lentos siempre vencerá a O (n²) escrito en los idiomas más rápidos. Especialmente que habrá pruebas múltiples que son el peor de los casos.
Pero aparte de las competiciones, si estamos hablando de grandes proyectos de la vida real, entonces ya no son 40 líneas frente a 200 líneas. En grandes proyectos, la enorme base de código comienza a ser un problema. En ese momento llegas a:
C ++ vs Python?
Python puro es lento. Es por eso que el intérprete estándar de Python (CPython) está escrito en C. Prácticamente todo con funciones integradas escritas como C. altamente optimizado. Python también se puede usar fácilmente junto con las bibliotecas C (a través de ctypes o como módulos nativos de cpython ) y con las bibliotecas C ++ a través de Boost :: Python . De esta manera, puede escribir su lógica de alto nivel en Python, un lenguaje que es flexible, permite la creación rápida de prototipos y la adaptación (lo que significa que puede pasar más tiempo ajustando y mejorando su algoritmo). OTOH, puede escribir sus funciones de biblioteca de nivel inferior en el módulo C o C ++. Un gran ejemplo de este enfoque es SciPy, que es la biblioteca Python, pero bajo el capó utiliza bibliotecas numéricas altamente optimizadas como ATLAS, LAPACK, Intels MKL o ACML de AMD.
fuente
En mi opinión, lo que las personas consideran coloquialmente un "lenguaje de programación" son en realidad tres cosas diferentes:
Por ejemplo, cuando alguien menciona C # en una discusión, puede pensar que está hablando de la sintaxis del lenguaje (1), pero es 95% seguro de que la discusión involucrará .Net framework (3). Si no está diseñando un nuevo lenguaje, es difícil y generalmente inútil aislar (1) e ignorar (2) y (3). Esto se debe a que IDE y la biblioteca estándar son "factores de comodidad", cosas que afectan directamente la experiencia de usar una herramienta determinada.
Los últimos años también participé en Google Code Jam. La primera vez opté por C ++ porque tiene un buen soporte para leer la entrada. Por ejemplo, leer tres enteros de una entrada estándar en C ++ se ve así:
Mientras que en C # el mismo se vería así:
Eso es mucho más sobrecarga mental para una funcionalidad simple. Las cosas se vuelven aún más complicadas en C # con entrada multilínea. Tal vez simplemente no he descubierto una mejor manera en ese entonces. De todos modos, no pude pasar la primera ronda porque tenía un error que no podía corregir antes del final de la ronda. Irónicamente, el método de lectura de entrada ofuscó el error. El problema era simple, la entrada contenía un número que era demasiado grande para un entero de 32 bits. En C #
int.Parse(string)
arrojaría una excepción, pero en C ++ la secuencia de entrada del archivo establecería un cierto indicador de error y fallaría silenciosamente, haciendo que el desarrollador desprevenido desconozca un problema.Ambos ejemplos demuestran cómo se usó la biblioteca en lugar de la sintaxis del lenguaje. El primero demuestra la verbosidad y el otro demuestra la fiabilidad. Muchas bibliotecas se portan a varios idiomas y algunos idiomas pueden usar bibliotecas que no están específicamente diseñadas para ellos (consulte la respuesta de @ vartec sobre Python con bibliotecas C).
Para concluir, conocer el algoritmo correcto ayuda. En las competencias de codificación es crucial, especialmente cuando los recursos, como el tiempo de ejecución y la memoria, están limitados a propósito. En el desarrollo de aplicaciones es bienvenido pero generalmente no es crucial. La mantenibilidad es más importante allí. Se puede lograr mediante la aplicación de patrones de diseño correctos, con una buena arquitectura, código legible y documentación relevante y todos esos métodos dependen en gran medida de las bibliotecas internas y de terceros. Por lo tanto, me parece más importante saber qué tipo de ruedas ya se han inventado y cómo se ajustan y cómo hacer las mías.
fuente
Main
y algunas cosas dentro delMain
método (instancia de mi clase de entrada y la secuencia de salida y el bucle de mayúsculas y minúsculas).Si desea competir en competencias de programación cronometrada, debe aprender el lenguaje más expresivo permitido en la competencia. Perl probablemente sería el mejor, seguido de Ruby o Python. Aún necesitará una buena instalación con algoritmos, pero al menos no se atascará escribiendo algo como
en lugar de
No te preocupes por aprender varias bibliotecas. Todos son muy similares y la documentación está en línea. Ser fluido en lenguajes más expresivos te hará un mejor programador (pero posiblemente frustrado) en lenguajes menos expresivos. Lo contrario no es verdad.
nótese bien
La diferencia entre 200 líneas de código y 40 líneas de código es enorme, y es aún mayor cuando es la diferencia entre un programa de 200,000 líneas y un programa de 40,000 líneas. Entonces es la diferencia entre un equipo de cinco más un gerente y un equipo de uno o dos.
fuente
Cualquier algoritmo puede implementarse en cualquier lenguaje de programación. Después de todo, no es la sintaxis lo que importa. Pero usar un lenguaje de alto nivel como Python tiene sus propias ventajas. Menos trabajo y menos cantidad de codificación. Entonces, para implementar un algoritmo en Python, necesitará menos líneas de las que se requieren en un lenguaje de bajo nivel como C.
Python tiene la mayoría de las estructuras de datos integradas en su biblioteca. Pero en C, debemos comenzar desde cero y usar una estructura para construirlo todo. Ciertamente, existen diferencias entre el lenguaje de alto nivel y el de bajo nivel, pero el lenguaje no debería impedir que implemente ningún algoritmo.
fuente
Si bien extrapolar el ejemplo "40 LoC vs 200 LoC", diciendo "bueno, solo una quinta parte de la LoC total es obviamente más rápida de escribir, por lo que debe ser mejor" puede parecer tentador, realmente creo que hay poca verdad que encontrar allí.
La optimización para la menor cantidad de LoC casi nunca es una buena idea en mi opinión. Sí, cada LoC escrito es un potencial para errores, y nunca tiene que depurar lo que nunca escribió etcetc. El punto es, optimizar la legibilidad y el desacoplamiento. No importa si resuelve un problema utilizando una expresión regular grande de 20 líneas, en lugar de escribir un módulo de 1k LoC. La expresión regular será una pared opaca, extremadamente propensa a los insectos, difícil de entender, una pesadilla para alterar sin cambiar su comportamiento de manera no detectable, etc.
Deshacerse de repeticiones y verbosidad que no agregan ningún valor está muy bien, pero por otro lado, usar algo como Java o C #, tener conocimiento sobre patrones de diseño y herramientas como resharper le permiten TANTA flexibilidad en la refactorización del código , limpiarlo con el tiempo, descomponer cosas, etc., eso sería MUCHO más difícil si lo hubiera escrito como un script de Python o una aplicación de rubí mucho más pequeños.
Una comparación muy reveladora: Prefiero tener 100k LoC de código C # desacoplado cubierto por pruebas, lleno de cosas "excesivas" como patrones de estrategia, fábricas, etc., en lugar de una aplicación python de 20k que simplemente "hace las cosas". 5 veces más código o no, la arquitectura gana todos los días.
Estoy totalmente de acuerdo en que algunos tipos de trabajo son más fáciles y más convenientes en algunos idiomas, pero creo más en la elección de su idioma en función de las herramientas que necesita y cuáles son los requisitos (y podrían ser en el futuro cercano).
fuente