Menu
Coddy logo textTech

Counting Sort

Última actualización

Counting sort es un ordenamiento sin comparaciones para enteros en un rango conocido y limitado. Cuenta cuántas veces aparece cada valor y luego usa esos conteos para escribir cada valor directamente en su posición ordenada, sin necesidad de comparaciones. Pulsa reproducir arriba para ver cómo se cuentan los valores y luego se colocan en orden.

Counting sort se ejecuta en tiempo O(n + k), donde k es el rango de los valores de entrada. Cuando k no es mucho mayor que n, es extremadamente rápido y puede superar a los ordenamientos por comparación de O(n log n), pero si el rango de valores es enorme, el arreglo de conteo de O(k) lo hace poco práctico.

Complejidad temporal y espacial

CasoComplejidadNotas
TiempoO(n + k)n elementos, k = rango de valores
EspacioO(n + k)Arreglo de conteo + arreglo de salida
EstableAl colocar de derecha a izquierda usando sumas de prefijos
¿Comparación?NoOrdena por conteo, no por comparación
Mejor paraRango entero pequeñok cercano a n

Paso a paso

PasoQué ocurre
1Encontrar el valor máximo para dimensionar el arreglo de conteo.
2Contar cuántas veces aparece cada valor.
3(Opcional) Convertir los conteos en sumas de prefijos para lograr estabilidad.
4Escribir cada valor en la salida tantas veces como aparece.
5El arreglo de salida ya está completamente ordenado.

Ejemplo resuelto

Ordenando [1, 4, 1, 2, 4] (los valores van de 0 a 4, por lo que el arreglo de conteo tiene 5 posiciones):

PasadaEstadoAcción
Recorrer entradacount = [0, 2, 1, 0, 2]Contar ocurrencias: el 1 aparece dos veces, el 2 una vez, el 4 dos veces.
Sumas de prefijoscount = [0, 2, 3, 3, 5]Cada posición contiene ahora cuántos valores son <= a su índice, dando las posiciones finales.
Colocar 4output = [_, _, _, _, 4]Leer de derecha a izquierda: count[4] = 5, así que el 4 va al índice 4; decrementar a 4.
Colocar 2output = [_, _, 2, _, 4]count[2] = 3, así que el 2 va al índice 2; decrementar a 2.
Colocar 1output = [_, 1, 2, _, 4]count[1] = 2, así que el 1 va al índice 1; decrementar a 1.
Colocar 4output = [_, 1, 2, 4, 4]count[4] = 4, así que este 4 va al índice 3; decrementar a 3.
Colocar 1output = [1, 1, 2, 4, 4]count[1] = 1, así que este 1 va al índice 0. El arreglo está ordenado.

Cuándo usar counting sort

Úsalo cuandoEvítalo cuando
Ordenas enteros (o claves convertibles a enteros) en un rango pequeño y conocido.El rango de valores k es mucho mayor que el número de elementos n.
Necesitas tiempo lineal O(n + k) y puedes permitirte los arreglos adicionales.La memoria es escasa: el arreglo de conteo cuesta O(k) sin importar n.
Necesitas un ordenamiento estable como subrutina (por ejemplo, dentro de radix sort).Las claves son flotantes, cadenas u objetos arbitrarios sin mapeo a enteros.
El valor máximo está acotado y es barato de calcular de antemano.El rango es desconocido o no está acotado, por lo que no puedes dimensionar el arreglo de conteo.

Código de Counting Sort

Una implementación limpia y ejecutable de Counting Sort en Python, JavaScript, Java, C++, C. Elige un lenguaje, copia el código o ábrelo ya cargado en el Playground de Coddy.

Código de Counting Sort en Python

Python
1def counting_sort(a):2    # Works for non-negative integers with a small max value3    counts = [0] * (max(a) + 1)4    for value in a:5        counts[value] += 16    # Prefix sums turn counts into final positions7    for i in range(1, len(counts)):8        counts[i] += counts[i - 1]9    out = [0] * len(a)10    for value in reversed(a):  # reversed keeps equal values stable11        counts[value] -= 112        out[counts[value]] = value13    return out14
15
16nums = [4, 2, 2, 8, 3, 3, 1]17print("Before:", nums)18print("After: ", counting_sort(nums))
Ejecuta este código en el Playground de Python

Preguntas frecuentes sobre Counting Sort

¿Cuál es la complejidad temporal de counting sort?
Counting sort es O(n + k), donde n es el número de elementos y k es el rango de valores posibles. Cuando k = O(n) esto es tiempo lineal. Usa O(n + k) de espacio adicional.
¿Es counting sort estable?
Puede serlo. La versión estable construye sumas de prefijos de los conteos y coloca los elementos de derecha a izquierda, lo que preserva el orden relativo de las claves iguales. La versión simple de "reescribir por valor" que se muestra aquí produce un orden correcto pero se usa principalmente para enteros simples.
¿Cuándo debería usar counting sort?
Úsalo al ordenar enteros (o claves convertibles a enteros) dentro de un rango pequeño y conocido. Si el rango de valores k es mucho mayor que el número de elementos, el arreglo de conteo desperdicia memoria y es mejor un ordenamiento por comparación.
¿Cuál es la diferencia entre counting sort y radix sort?
Counting sort ordena por el valor completo en una sola pasada y necesita un arreglo de conteo tan grande como el rango de valores. Radix sort ordena dígito por dígito y normalmente llama a un counting sort estable en cada dígito, lo que mantiene pequeño el rango por pasada (por ejemplo, 10 para dígitos decimales). Radix sort maneja rangos de valores grandes que harían impracticable un único counting sort.
¿Por qué counting sort no siempre es más rápido que quicksort?
Counting sort es O(n + k), por lo que solo gana cuando el rango de valores k es comparable a n. Si k es enorme -por ejemplo, ordenar 100 valores en el rango de 0 a 1,000,000,000- el arreglo de conteo de O(k) domina y desperdicia memoria, mientras que un ordenamiento por comparación de O(n log n) como quicksort se mantiene rápido y eficiente en espacio.
¿Puede counting sort manejar números negativos?
Sí, con un pequeño desplazamiento. En lugar de indexar el arreglo de conteo directamente por el valor, indéxalo por value - min, de modo que el valor más pequeño se asigne al índice 0. El tamaño del arreglo de conteo pasa a ser max - min + 1. Olvidar este desplazamiento es un error común que falla con entradas negativas.
Coddy programming languages illustration

Domina los algoritmos con Coddy

COMENZAR