2011-11-18 17 views
8

¿Cuáles son formas eficientes de ordenar matrices que tienen principalmente un pequeño conjunto de elementos duplicados? Es decir, una lista como:Algoritmos de clasificación rápida para matrices con elementos mayormente duplicados?

{10, 10, 55, 10, 999, 8851243, 10, 55, 55, 55, 10, 999, 8851243, 10}

Suponiendo que el orden de equal los elementos no importan, ¿cuáles son los mejores algoritmos de peor caso/caso medio?

+0

El peor de los casos para todos ellos será la misma que para los algoritmos de clasificación normal, ya que no se ha definido cómo "duplicar" la lista tiene que ser. Por supuesto, puede haber algunos que tengan un mejor promedio de casos. – quasiverse

+0

Estaría tentado de intentar insertar ordenar con una lista de omisiones – phs

+0

¿Qué tan pequeño es "pequeño"? Si solo se trata de una docena o dos elementos, algo sencillo como ordenar por selección será difícil de superar. –

Respuesta

14

En la práctica, primero puede iterar a través de la matriz una vez y usar una tabla hash el recuento de la cantidad de ocurrencias de los elementos individuales (esto es O (n) donde n = tamaño de la lista). A continuación, tome todos los elementos únicos y ordénelos (esto es O (k log k) donde k = número de elementos únicos), y luego vuelva a expandir esto a una lista de n elementos en O (n) pasos, recuperando los recuentos del tabla de picadillo. Si k < < n ahorra tiempo.

0

IMO Pidgeonhole sort es un buen ejemplo para tales datos.

Aclararé un poco: si sabes que la cantidad de elementos únicos en la matriz es razonable y sabes que hay muchos duplicados, pensaría en implementar algo así como contar el tipo pero hacer una lista de "cubos" dinámica. Después del primer pase eliminarás los duplicados, luego ordenarás el conjunto sin duplicados con algún buen algoritmo de ordenación y luego restaurarás el conjunto ordenado de una manera como lo hace el conteo de ordenaciones.

2

No es el mejor algoritmo, pero simple:
Puede poner todo en un trie y hacer que las hojas sean contadores. Eso debería tomar O (n * m) donde n es el número de elementos ym es el tamaño del elemento más grande (típicamente eso sería una constante, pero no necesariamente). A continuación, realice un pedido por adelantado para atravesar la atadura y obtenga counter elementos de la tecla actual cuando toque una hoja. Eso debería tomar solo O (n + p) donde p es el tamaño del trie, que debe ser pequeño en comparación con n.

2

Probaría Counting sort con alguna función de mapeo. Es decir. no utilizará la matriz de frecuencias de un tamaño igual al rango de elementos, en su lugar, iterará sobre la matriz, anotará los distintos elementos y los utilizará en una función de mapeo para la matriz de frecuencias.

De esta forma, el algoritmo tiene solo una iteración extra y una función de mapeo, que debería funcionar en un tiempo constante (usando alguna tabla king de hash). La complejidad de este enfoque sería O(n), que debería ser óptima.

+0

Me sorprende que esta última respuesta tenga cero recuento de utilidad. es la mejor respuesta aquí, ya que muestra la complejidad del tiempo = O (n) y la complejidad del espacio = O (k). –

1

Implementación en C++ basado en algo como lo sugiere @Antti Huima

  • frecuencias de recuento y se guardan en la tabla hash.
  • ordenar elementos en hashtable.
  • sobrescribe la matriz de entrada con elementos ordenados según las frecuencias.

    #include <unordered_map> 
    #include <map> 
    // Modifies input array to a sorted array 
    // Complexity: O(n+(k*log(k))) where 'k' = number of unique elements input array 
    template <typename Datatype> 
    void SortArrayWithDuplicates(std::vector<Datatype>& in_seq) { 
        std::unordered_map<Datatype, int> key_counts_map; 
        // Count freqs O(n) 
        for (const auto& itr: in_seq) 
         key_counts_map[itr] += 1; 
    
        // Sort elements by inserting into a map O(k*log(k)) 
        std::map<Datatype, int> key_counts_sorted_map; 
        for (auto const& itr: key_counts_map) 
         key_counts_sorted_map.insert(std::make_pair(itr.first, itr.second)); 
    
        auto AlwaysTrue = [](Datatype i)->bool{return true;}; 
        auto seq_itr = std::begin(in_seq); 
        // Update input sequence with new sorted values 
        for (auto const& itr: key_counts_sorted_map) { 
         std::replace_if(seq_itr, seq_itr+itr.second, AlwaysTrue, itr.first); 
         seq_itr += itr.second; 
        } 
    } 
    
Cuestiones relacionadas