Me asignaron un ejercicio en mi universidad. Me lo llevé a casa e intenté programar un algoritmo para resolverlo, supongo que era algo relacionado con gráficos, encontrar componentes conectados.
Luego hice lo más trivial que se me ocurrió y luego se lo mostré a mi profesor. Después de una breve observación, percibió que la complejidad del tiempo de ejecución de mi solución era inviable y mostró algo más eficiente. Y existe una tradición de programadores que no tienen idea de qué es la complejidad computacional (yo era uno de esos), entonces, ¿es un problema si un programador no tiene idea de qué es la complejidad computacional?
algorithms
algorithm-analysis
education
applied-theory
Billy Rubina
fuente
fuente
Respuestas:
Sí, diría que saber algo sobre la complejidad computacional es imprescindible para cualquier programador serio. Mientras no esté lidiando con grandes conjuntos de datos, estará bien sin conocer la complejidad, pero si desea escribir un programa que aborde problemas graves, lo necesita.
En su caso específico, su ejemplo de encontrar componentes conectados podría haber funcionado para gráficos de hasta nodos. Sin embargo, si probaste un gráfico con nodos, entonces el algoritmo de tu profesor probablemente lo hubiera logrado en 1 segundo, mientras que tu algoritmo habría (dependiendo de cuán grave fuera la complejidad) tomado 1 hora, 1 día, o tal vez incluso 1 eternidad.100.000100 100.000
Un error algo común que los estudiantes cometen en nuestro curso de algoritmos es iterar sobre una matriz como esta:
Puede que este no sea el código más hermoso, pero en un programa complicado, algo como esto podría aparecer sin que el programador lo sepa. Ahora, ¿cuál es el problema con este programa?
Supongamos que lo ejecutamos en un conjunto de datos de elementos. En comparación con el siguiente programa, el programa anterior se ejecutará más lento.50.000100.000 50.000
Espero que esté de acuerdo en que tener el conocimiento para hacer que su programa se ejecute veces más rápido es probablemente algo importante para un programador. Comprender la diferencia entre los dos programas requiere algunos conocimientos básicos sobre la teoría de la complejidad y algunos conocimientos sobre los detalles del lenguaje en el que está programando.50.000
En mi lenguaje de pseudocódigo, "eliminar un elemento de una matriz" desplaza todos los elementos a la derecha del elemento que se está eliminando una posición desde la izquierda. Esto hace que eliminar el último elemento sea una operación ya que para hacerlo solo necesitamos interactuar con 1 elemento. Eliminar el primer elemento es ya que para eliminar el primer elemento, también debemos desplazar todos los demás elementos una posición hacia la izquierda.O ( n ) n - 1O ( 1 ) O ( n ) n - 1
Un ejercicio muy básico de complejidad es demostrar que el primer programa realizará operaciones mientras que el segundo programa usa solo operaciones. Si conectas , verás que un programa es drásticamente más eficiente que el otro.nn=100.00012norte2 norte n = 100.000
Este es solo un ejemplo de juguete, pero ya requiere una comprensión básica de la complejidad para distinguir la diferencia entre los dos programas, y si realmente está tratando de depurar / optimizar un programa más complicado que tiene este error, se necesita una comprensión aún mayor para encontrar fuera de donde está el error. Porque un error como eliminar un elemento de una matriz de esta manera puede ocultarse muy bien por abstracciones en el código.
Tener una buena comprensión de la complejidad también ayuda cuando se comparan dos enfoques para resolver un problema. Suponga que ha ideado dos enfoques diferentes para resolver el problema de los componentes conectados por su cuenta: para decidir entre ellos sería muy útil si pudiera (rápidamente) estimar su complejidad y elegir el mejor.
fuente
"So long as you are not dealing with huge data sets you will be fine not knowing complexity"
Esto suele ser cierto, pero no siempre es así. Por ejemplo, unO(n!)
algoritmo no será viable incluso para conjuntos de datos relativamente pequeños. Si usa unO(n!)
algoritmo en el que podría haber usadoO(n^2)
su programa, tardará 36.288 veces más en ejecutarse en un tamaño de datos de 10 . Con un tamaño de datos de 20, está viendo 2.4 quintillones de operaciones.Esta es una refutación de la respuesta de Tom van der Zanden , que afirma que es imprescindible.
La cosa es que, la mayoría de las veces, 50,000 veces más lento no es relevante (a menos que trabajes en Google, por supuesto).
Si la operación que realiza toma un microsegundo o si su N nunca supera un cierto umbral (una gran parte de la codificación realizada hoy en día) NUNCA importará. En esos casos, pensar en la complejidad computacional solo le hará perder tiempo (y probablemente dinero).
La complejidad computacional es una herramienta para entender por qué algo puede ser lento o escalar mal, y cómo mejorarlo, pero la mayoría de las veces es una exageración total.
He sido programador profesional durante más de cinco años y nunca he encontrado la necesidad de pensar en la complejidad computacional al hacer un bucle dentro de un bucle O (M * N) porque siempre la operación es realmente rápida o M y N son tan pequeño.
Hay cosas mucho más importantes, de uso general y más difíciles de entender para cualquiera que realice trabajos de programación (el enhebrado y el perfilado son buenos ejemplos en el área de rendimiento).
Por supuesto, hay algunas cosas que nunca podrá hacer sin comprender la complejidad computacional (por ejemplo: encontrar anagramas en un diccionario), pero la mayoría de las veces no lo necesita.
fuente
He estado desarrollando software durante unos treinta años, trabajando tanto como contratista como empleado, y he tenido bastante éxito en ello. Mi primer idioma fue BASIC, pero enseguida aprendí el lenguaje de máquina para obtener una velocidad decente de mi caja de baja potencia. He pasado mucho tiempo en perfiladores a lo largo de los años y he aprendido mucho sobre la producción de código optimizado rápido y eficiente en memoria.
Independientemente de decir, soy autodidacta. Nunca encontré la notación O hasta que comencé a entrevistar hace unos años. Nunca apareció en mi trabajo profesional, EXCEPTO durante las entrevistas. Así que tuve que aprender los conceptos básicos solo para manejar esa pregunta en las entrevistas.
Me siento como el músico de jazz que no sabe leer partituras. Todavía puedo jugar bien. Sé acerca de las tablas hash (diablos, inventé las tablas hash antes de saber que ya se habían inventado) y otras estructuras de datos importantes, e incluso podría conocer algunos trucos que no enseñan en la escuela. Pero creo que la verdad es que si quieres tener éxito en esta profesión, tendrás que ir al cine independiente o aprender las respuestas a las preguntas que te harán durante las entrevistas.
Por cierto, recientemente me entrevisté para un rol de desarrollador web front-end. Me hicieron una pregunta donde la respuesta requería tanto el conocimiento de la complejidad computacional como los logaritmos. Logré recordar suficientes matemáticas de hace veinte años para responderlas más o menos correctamente, pero fue un poco desagradable. Nunca he tenido que usar logaritmos en ningún desarrollo front-end.
¡Buena suerte para ti!
fuente
La pregunta es bastante subjetiva, así que creo que la respuesta es que depende .
No importa mucho si trabaja con pequeñas cantidades de datos. En estos casos, generalmente está bien usar lo que sea, por ejemplo, la biblioteca estándar de su idioma.
Sin embargo, cuando maneja grandes cantidades de datos, o por alguna otra razón insiste en que su programa es rápido, debe comprender la complejidad computacional. Si no lo hace, ¿cómo sabe cómo se debe resolver un problema o qué tan rápido es posible resolverlo? Pero comprender la teoría justa no es suficiente para ser un buen programador. Creo que para producir código extremadamente rápido, también debe comprender cómo funciona su máquina (cachés, diseño de memoria, el conjunto de instrucciones) y qué hace su compilador (los compiladores hacen su mejor esfuerzo, pero no son perfectos).
En resumen, creo que comprender la complejidad claramente te convierte en un mejor programador.
fuente
Ciertamente es un problema si alguien que está desarrollando algoritmos significativos no comprende la complejidad del algoritmo. Los usuarios de un algoritmo generalmente dependen de una buena calidad de implementación que tiene buenas características de rendimiento. Si bien la complejidad no es el único contribuyente a las características de rendimiento de un algoritmo, es significativo. Alguien que no comprende la complejidad del algoritmo tiene menos probabilidades de desarrollar algoritmos con características de rendimiento útiles.
No es un problema para los usuarios de un algoritmo, suponiendo que los algoritmos disponibles sean de buena calidad. Esto es cierto para los desarrolladores que usan lenguajes que tienen una biblioteca estándar significativa, bien especificada, solo necesitan saber cómo elegir un algoritmo que satisfaga sus necesidades. El problema viene cuando hay múltiples algoritmos de algún tipo (por ejemplo, clasificación) disponibles dentro de una biblioteca, porque la complejidad es a menudo uno de los criterios para elegir. Un desarrollador que no comprende la complejidad no puede entender la base para elegir un algoritmo efectivo para su tarea en cuestión.
Luego están los desarrolladores que se centran (por falta de una mejor descripción) en preocupaciones no algorítmicas. Por ejemplo, pueden centrarse en desarrollar interfaces de usuario intuitivas. Dichos desarrolladores a menudo no tendrán que preocuparse por la complejidad del algoritmo, aunque, nuevamente, pueden confiar en que las bibliotecas u otro código se desarrollen con una alta calidad.
fuente
Depende, pero no de la cantidad de datos con los que está trabajando, sino del tipo de trabajo que realiza, los programas que desarrolla.
Llamemos al programador que no conoce la complejidad conceptual del programador novato.
El programador novato puede hacer:
El programador novato no debe hacer:
Entonces, el programador novato está bien, cuando solo quieres usar tecnologías. Entonces, cuando se trata del desarrollo de nuevas soluciones, tecnologías personalizadas, etc. Entonces es mejor contratar un programador no novato.
Sin embargo, si la compañía no desarrolla nuevas tecnologías, solo usa las ya hechas. Sería una pérdida de talento contratar a programadores calificados y talentosos. Lo mismo se aplica, si no desea trabajar en nuevas tecnologías y está bien poner las ideas de los clientes en diseños y programas utilizando marcos ya creados, entonces es una pérdida de tiempo aprender algo que nunca necesitará, excepto si es tu hobby y te gustan los desafíos lógicos.
fuente
Dudo un poco en escribir una respuesta aquí, pero como me encontré molestando a varios otros '[algunos de mis comentarios fueron trasladados al chat], así es como lo veo ...
Hay muchos niveles / grados de conocimiento en muchas cosas en informática (y con este término me refiero aproximadamente a la unión de la informática con la tecnología de la información). La complejidad de la computación seguramente es un campo vasto (¿Sabes qué es OptP? ¿O qué dice el teorema de Abiteboul-Vianu?) Y también admite mucha profundidad: la mayoría de las personas con un título de CS no pueden producir las pruebas de expertos que se dedican a la investigación publicaciones en complejidad computacional.
Sinceramente, me atrevería a comparar la situación de saber cuándo aplicar conceptos de complejidad computacional (y saber cuándo puede ignorarlos de manera segura) con la práctica algo común (fuera del mundo de Java) de implementar algún código sensible al rendimiento en C y el insensible al rendimiento cosas en Python, etc. (Como comentario aparte, esto se llamó en una charla de Julia el "compromiso estándar" ). Saber cuándo no tiene que pensar en el rendimiento le ahorra tiempo de programación, que también es un bien bastante valioso.
Y un punto más es que conocer la complejidad computacional no lo hará automáticamente bueno para optimizar programas; necesita comprender más cosas relacionadas con la arquitectura, como la ubicación de caché, [a veces] canalización, y hoy en día también programación paralela / multi-core; este último tiene tanto su propia teoría de la complejidad como también consideraciones prácticas; una muestra de este último de un documento SOSP de 2013 "Cada esquema de bloqueo tiene sus quince minutos de fama. Ninguno de los nueve esquemas de bloqueo que consideramos supera constantemente a cualquier otro, en todas las arquitecturas o cargas de trabajo de destino. Estrictamente hablando, para buscar la óptima, un por lo tanto, el algoritmo de bloqueo debe seleccionarse en función de la plataforma de hardware y la carga de trabajo esperada ".
fuente
Si no sabes big-O, debes aprenderlo. No es difícil y es realmente útil. Comience con la búsqueda y clasificación.
Noto que muchas respuestas y comentarios recomiendan la creación de perfiles , y casi siempre significan usar una herramienta de creación de perfiles .
El problema es que las herramientas de creación de perfiles están en todo el mapa en términos de cuán efectivas son para encontrar lo que necesita para acelerar. Aquí he enumerado y explicado los conceptos erróneos que sufren los perfiladores.
El resultado es que los programas, si son más grandes que un ejercicio académico, pueden contener gigantes dormidos , que incluso el mejor perfilador automático no puede exponer. Esta publicación muestra algunos ejemplos de cómo los problemas de rendimiento pueden ocultarse de los perfiladores.
Pero no pueden esconderse de esta técnica.
fuente