2016-07-12 11 views
0

Welche Elemente können Sie am effizientesten mit einer Liste von Elementen gruppieren? Wenn der Eingang {a,c,a,b,c,b,b} ist, könnte ein gültiger Ausgang beispielsweise {a,a,b,b,b,c,c} oder {b,b,b,c,c,a,a} lauten. Wenn der Typ des Schlüssels eine Reihenfolge beobachtet, könnte ein Sortieralgorithmus verwendet werden, der uns eine Komplexität von O(nlogn) geben würde.Effiziente Gruppierung von Elementen einer Liste

Der Schlüssel kann jedoch nur für die Gleichheit, nicht aber für die Reihenfolge vergleichbar sein. Zum Beispiel typeof(dog) != typeof(cat), aber es macht keinen Sinn zu fragen, ob typeof(dog) < typeof(cat).

Natürlich könnte die Reihenfolge erzwungen werden (z. B. obj.GetType().ToString() und lexikalische Reihenfolge), aber da eine strikte Reihenfolge nicht notwendig ist (nur Gruppierung), habe ich mich gefragt, ob es einen effizienteren Weg als Sortieren gibt.

+0

Wieviel Schlüssel haben Sie? O (n) oder viel kleiner? –

+0

Sie wollen "in Place" Gruppierung oder es ist in Ordnung, die Elemente zu kopieren und eine andere sortierte Liste zu machen? –

+0

@OhadEytan Anzahl der Schlüssel variiert, aber normalerweise ist es entweder nahe 1 oder nahe bei n. Ich würde einen "In-Place" -Algorithmus bevorzugen, da diese Operation an vielen Eingaben vorgenommen wird. – MikeM

Antwort

1

I würde eine unsortierte verknüpften Liste und eine Hash-Karte für das Einfügen Punkte, etwa wie folgt (in Pseudocode) verwendet werden:

function group_sort(unsorted_list) 
    node_map = new hash_map 
    sorted_list = new linked_list 
    foreach node in unsorted_list 
    last_node = node_map.get(type_of(node)) 
    if last_node found 
     sorted_list.insert_after(last_node,node) 
    else 
     sorted_list.append(node) 
     node_map.add(type_of(node),node) 
    delete node_map 
    return sorted_list 

Hashzuordnung lookup und Einsatz ist meistens O (1) und die Hash-Karte Einfügungs ist vielleicht sogar selten, abhängig von Ihren Daten. Verknüpfte Listeneinfügung ist immer O (1). Was macht die Funktion fast O (n), und sicherlich O (nlogn).

+0

Schöne Idee. Die Listeneinfügung ist jedoch nur dann O (1), wenn sie als doppelt verknüpfte Liste implementiert ist. Wenn der zugrundeliegende Speicher ein Array ist, wie es häufig bei den gängigen Go-to-Implementierungen der Fall ist (z. B. Liste für C#, ArrayList für Java), dann ist insert O (n). – MikeM

+0

@MikeM: Einfügen eines Elements * in der Mitte von * eine Array-basierte Liste ist O (n), aber an das Ende, wie Fabel hier anfügt, ist O (1) (amortisiert). Außerdem ist die Einfügung an der Vorderseite einer einfach verknüpften Liste O (1). –

+0

Mein Beispiel fügt beide in der Mitte und am Ende, die beide O (1) ist. Und um es klar zu sagen, ich spreche von einer verknüpften Liste, nicht von einem Array. Die Verwendung eines Arrays zum Sortieren ist sehr ineffizient und würde diese Funktion zu O (n2) machen. – Fabel