2009-10-30 16 views
5

Estoy tratando de encontrar un algoritmo para encontrar los 2 números más altos en una lista de números.Encontrar los 2 números más altos: informática

El número más alto se puede encontrar en n-1 etapas, tal vez haciendo el primer paso de una burbuja de ordenación o algo por el estilo. Para mí, parece que encontrar el siguiente número más alto también podría encontrarse en un total de 1.5n comparaciones en promedio.

Mi profesor nos preparó la tarea para escribir un alogrithm que encuentre los 2 números más altos en n + log (n) comparaciones. ¿Esto es posible? Alguna idea, sugerencia?

Editar: Cuando digo n + log (n) No me refiero a O (n + n log), sino más bien exactamente n + log n

+0

Vea la pregunta número. 1602998 –

+2

aquí hay un enlace útil: http://stackoverflow.com/questions/1602998 – nickf

+0

¿Los números tienen que ser diferentes? P.ej. En la lista (1, 3, 2, 3), ¿los dos números más altos (3, 3) o (2, 3)? –

Respuesta

6

Sí, es posible hacerlo en no más de (n + log n). Realmente no puedo decirte cómo sin dar la respuesta, pero déjame intentarlo. :-)

Tome los n números, compárelos en pares a la vez. Tome el ceil (n/2) "ganadores", y repita, "como un árbol binario". Preguntas: ¿Cuántas comparaciones se necesitan para encontrar la más grande? ¿A cuántas personas gana esta victoria "ganadora"? ¿A quién podría haber perdido el segundo más grande? Entonces, ¿cuántas comparaciones toma ahora para encontrar el segundo número más grande?

La respuesta resulta ser un total de n-1 + techo (log n) - 1 comparaciones, donde el registro está en la base 2. También puede demostrar usando un argumento contradictorio que no es posible hazlo mejor que esto en el peor de los casos.

+0

Gracias. Tan simple, pero inteligente. Ahora voy a intentar programarlo de forma recursiva y eficiente en Java ... – Meir

0

¿Qué tal esto:

for each listOfNumbers as number 
    if number > secondHighest 
     if number > highest 
      secondHighest = highest 
      highest = number 
     else 
      secondHighest = number 
+1

esto requiere comparaciones 'O (2n)', que es mayor que 'O (n + log (n))'. –

+0

Lo anterior se refiere al peor tiempo de ejecución del caso, si los números se almacenan en orden ascendente. –

+4

O (2n) es lo mismo que O (n) para que el comentario no tenga sentido. –

2

Editar: Oops, se perdió una cosa simple debido a la estupidez. Esta solución no es correcta, aunque la mantengo aquí ya que todavía es prom (n + log (n)). Gracias a ShreevatsaR por señalar mi estupidez. Sí consideré la búsqueda en árbol, pero olvidé por completo la idea de retroceder para encontrar el segundo número más alto en log (n).

De todos modos, aquí sigue mi prueba de por qué el algoritmo inferior no es más que avg (n + log (n)). En la vida real todavía debería funcionar bastante bien al menos.

  • Primera comparación contra el segundo número más alto registrado.
  • Solo si esa comparación tiene éxito, compárela con el número más alto registrado.

Para demostrar que es en promedio n + log n, simplemente tenemos que demostrar que la primera comparación solo tiene éxito en log (n) veces en promedio. Y eso es bastante simple de ver o demostrar.

  1. Supongamos P como el de la posición real de la corriente segundo número más grande en una versión ordenada de la lista, y ejecutar el algoritmo
  2. Si P> 2 a continuación, cuando se encuentra un número mayor, la nueva p en promedio no será más que P/2.
  3. Si P = 2, entonces la primera comparación no puede tener éxito, ya que no hay un número que sea mayor que el segundo número más grande actual.
  4. P a lo sumo igual N
  5. De 2, 3 y 4 debe ser trivial ver que la primera comparación no puede tener más éxito que el log (N) veces en promedio.
+1

Sus primeras líneas no son correctas: no necesita 2 * n comparaciones en el peor de los casos, y de hecho se puede hacer en exactamente (n-1) + techo (log n) -1, comparaciones, como pregunta la pregunta. No estoy bajoneando esto porque el resto de la respuesta es correcta, pero en realidad, "No puedo pensar en una forma" no es una prueba. : P – ShreevatsaR

0

La respuesta publicada por ShreevatsaR parece ser O (n log n).

La primera pasada (n operaciones) produce n/2 respuestas. Al repetir, supongo que te refieres a que harás n/2 operaciones para producir n/4 respuestas. Pasará por el registro de bucles n veces. Esto es muy parecido a un tipo de combinación, excepto que la clase de fusión siempre procesa n nodos cada vez que pasa. También ejecuta el registro de bucle n veces. Y no veo cómo este algoritmo hará un seguimiento del segundo número más alto.

nickf tiene la respuesta correcta. El peor caso es cuando la lista está ordenada, hará 2n comparaciones, eso es O (n).

por cierto, O (n + log n) es O (n) la notación de orden se refiere al crecimiento asintótico en el peor de los casos.

+0

¿Eh? n/2 + n/4 + ... = n-1. (Otra forma de ver esto: todos menos el ganador pierde exactamente una vez). El algoritmo que di tiene exactamente n + log (n) -2 comparaciones (no solo asintóticamente). Tenga en cuenta que la medida en cuestión es el número de comparaciones, no el tiempo de ejecución. (Pero n + log (n) es O (n), por lo que el tiempo de ejecución es O (n) también.) Lamento que mi respuesta no sea más clara, pero no quiero dar por completo la respuesta a un pregunta de tarea. – ShreevatsaR

0

Puede usar clasificación de conteo, clasificación de radix, ordenación de cuchara u otro algoritmo de tiempo lineal para primero ordenar la lista en orden descendente. Luego solo obtenga los primeros 2 elementos de la lista ordenada. Esto tomará (n) + 2 = (n)

Tenga en cuenta que estos algoritmos pueden ordenar en tiempo lineal porque cada uno tiene sus propias suposiciones.

+0

(1) No se garantiza nada acerca de los números dados, por lo que no es posible ordenar en tiempo lineal. (2) Observe que la medida aquí es el número de comparaciones, no el número de operaciones (3) Observe que está pidiendo * exactamente * n + log (n), no O (n + log (n)) - lo que haría ser solo O (n). – ShreevatsaR

0

Pseudocódigo (no es esta esencia n?)

int highestNum = 0 
int secondHighest = highestNum 

for(i = 0; i < list.length; i++) 
{ 
if(list[i] >= highestNum) 
{ 
secondHighest = highestNum 
highestNum = list[i] 
} 
} 
+1

Prueba en esta lista: 0 3 2 1. El segundo máximo permanecerá 0.(Más generalmente, tome cualquier lista donde ocurra el número más alto antes del segundo número más alto, y su código fallará el segundo más alto). – ShreevatsaR

Cuestiones relacionadas