2010-11-27 7 views
6

Supposons que nous ayons besoin de trier 50 000 000 numéros. supposons que les nombres sont stockés dans un fichier. Quel est l'algorithme le plus efficace pour résoudre ce problème? Algorithme parallèle pour le tri ...tri 50 000 000 numéros

Comment le faire? Peut-être que lien utile)

Je ne peux pas utiliser d'algorithme standard

Je vous demande donc sur les méthodes et les algorithmes :)

Ok .. Je l'ai lu en parallèle mergesort ... Mais on ne sait pas pour moi .

solution , la première version

code is located here

+0

:) que voulez-vous dire? –

+0

@Paul Il est juste de la matrice - regarde son surnom :) –

+3

Pourquoi ne pouvez-vous pas utiliser des algorithmes standard? Est-ce un problème de devoirs? –

Répondre

8

Du haut de ma tête, merge sort semble être la meilleure option en matière de parallélisation et la distribution, car il utilise diviser -conquer approche. Pour plus d'informations, google pour "fusion parallèle tri" et "distribué fusionner tri".

Pour un seul ordinateur, plusieurs cœurs exemple, voir Correctly multithreaded quicksort or mergesort algo in Java?. Si vous pouvez utiliser Java 7 fork/join, voir: "Java 7: more concurrency" et "Parallelism with Fork/Join in Java 7".

Pour distribuer sur plusieurs machines, voir Hadoop, il a une implémentation de tri de fusion distribuée: voir MergeSort et MergeSorter. Également d'intérêt: Hadoop Sorts a Petabyte in 16.25 Hours and a Terabyte in 62 Seconds

+0

pour sûr si vous avez des téraoctets de données à trier j'irais pour cela. – Uberto

+0

:) ne peut pas trouver l'algorithme exact pour le système multi-cores. Peut-être que vous pouvez donner un lien ou du papier? –

+0

J'ai édité ma réponse –

4

Pour le tri que de nombreux éléments, votre meilleur coup est Merge Sort. Ce sont généralement les algorithmes utilisés par les bases de données. Même s'il n'est pas aussi rapide que Quick Sort, il utilise un stockage intermédiaire, vous n'avez donc pas besoin d'énormes quantités de mémoire pour effectuer le tri.

En outre, comme indiqué par sje397 et Scott dans les commentaires, Merge Sort est hautement parallélisable.

+1

Et mergesort est facilement parallélisées – sje397

+0

sorte de fusion est aussi éminemment parallelisable – Scott

+1

... et sje397 et moi sommes exactement sur la même longueur d'onde :-) – Scott

3

Cela dépend beaucoup du domaine du problème. Par exemple, si tous les nombres sont des entiers positifs, la meilleure solution consiste à créer un tableau de 0-MAX_INT, puis de simplement compter le nombre de fois où chaque nombre se produit lorsque vous lisez le fichier, puis d'imprimer chaque int avec un zéro compte cependant plusieurs fois il s'est produit. C'est un "tri" O (n). Il y a un nom officiel pour ce genre, mais j'oublie ce que c'est. Par ailleurs, cette question m'a été posée lors d'une interview Google. À partir des contraintes du problème, j'ai trouvé cette solution, et elle semblait être la réponse recherchée. (Je me suis tourné vers le bas le travail parce que je ne voulais pas bouger.)

+1

C'est ce qu'on appelle le comptage. http://en.wikipedia.org/wiki/Counting_sort –

+0

Non, le tableau peut contenir des nombres négatifs. –

2

Ils ne sont pas si nombreux. Si elles ont 10 octets de long par exemple, ce serait un tableau de 500 Mo, il peut presque rester sur mon téléphone! ;) Donc, je dirais aller Quicksort si ce n'est que ça.

19

50 millions ne sont pas particulièrement importants. Je voudrais juste les lire dans la mémoire. Triez-les et écrivez-les. Cela devrait prendre quelques secondes. À quelle vitesse en avez-vous besoin? Comment compilé avez-vous besoin d'être?

Sur mon ancien labtop, cela a pris 28 secondes. Si j'avais plus de processeurs, cela pourrait être un peu plus rapide mais la plupart du temps on passe à lire et écrire le fichier (15 secondes) ce qui ne serait pas plus rapide.

L'un des facteurs critiques est la taille de votre cache. La comparaison elle-même est très bon marché à condition que les données soient dans le cache. Comme le cache L3 est partagé, un thread est tout ce dont vous avez besoin pour l'utiliser pleinement.

public static void main(String...args) throws IOException { 
    generateFile(); 

    long start = System.currentTimeMillis(); 
    int[] nums = readFile("numbers.bin"); 
    Arrays.sort(nums); 
    writeFile("numbers2.bin", nums); 
    long time = System.currentTimeMillis() - start; 
    System.out.println("Took "+time+" secs to sort "+nums.length+" numbers."); 
} 

private static void generateFile() throws IOException { 
    Random rand = new Random(); 
    int[] ints = new int[50*1000*1000]; 
    for(int i= 0;i<ints.length;i++) 
     ints[i] = rand.nextInt(); 
    writeFile("numbers.bin", ints); 
} 

private static int[] readFile(String filename) throws IOException { 
    DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream(filename), 64*1024)); 
    int len = dis.readInt(); 
    int[] ints = new int[len]; 
    for(int i=0;i<len;i++) 
     ints[i] = dis.readInt(); 
    return ints; 
} 

private static void writeFile(String name, int[] numbers) throws IOException { 
    DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(name), 64*1024)); 
    dos.writeInt(numbers.length); 
    for (int number : numbers) 
     dos.writeInt(number); 
    dos.close(); 
} 
+0

"Comme le cache L3 est partagé, un thread est tout ce dont vous avez besoin pour l'utiliser pleinement." Néanmoins, mon code C++ prend 6s (horloge et CPU) pour trier 50M entiers dans un seul thread, et 3.7s clock/6.5s CPU pour partitionner d'abord les entiers au-dessus et en dessous de INT_MAX, puis trier la partie inférieure dans un thread et le supérieur partie dans l'autre. Je ne sais pas si Java serait différent, mais suggère que le cache L3 n'est pas tout ce qu'il y a à faire. C'est avec des valeurs uniformément réparties. –

+0

Timing juste le genre, il a fallu 13 secondes sur mon ordinateur portable avec un thread et 7 secondes avec deux. Alors que cela économise 6 secondes (22% du total), il a considérablement augmenté la complexité du code (non affiché;) Note avec 6 cœurs, je pourrais économiser 5 secondes de plus, mais cela prendrait 18 secondes alors que le chargement et l'enregistrement 15 secondes –

+0

Beaucoup dépend de combien il est critique d'économiser quelques secondes. Il m'a fallu plusieurs minutes pour écrire le code, plus longtemps si je l'ai testé. ;) Dans la plupart des cas, il ne vaudrait pas la peine de l'effort à mon humble avis. –

2

ne pas avoir peur du grand nombre. en fait, 50 000 000 numéros ne sont pas si gros. donc si les nombres étaient des nombres entiers, alors chaque nombre a une taille de 4 octets, donc la mémoire globale à allouer pour ce tableau est 50 000 000 * 4/1024/1024 = 190,7 méga octets, ce qui est relativement petit. Une fois le calcul terminé, vous pouvez procéder à l'exécution de QuickSort qui s'exécute dans O (nLogn). Notez que la méthode de tri intégrée dans les tableaux .net utilise QuickSort, mais je ne sais pas si c'est le cas dans Java.

tri 250 000 000 entiers sur ma machine a pris environ 2 minutes pour aller pour elle :)

+0

50 000 000 * 4 (couse sizeof (item) == 4) == 200 000 000 –

+0

200 000 000/1024/1024 ~ 200 mb ... –

+1

Um. Vous devriez avoir multiplié par 4, non divisé. Les valeurs 50M à 4 octets prennent chacune environ 200 Mo (190 Mo après impôt binaire). –

0

numéros 50e6 est très faible de nos jours, ne font pas les choses plus complexes qu'ils doivent être ...

bash$ sort <file> sorted.file

Questions connexes