J'utilise Java sur une grosse quantité de données. P>
[J'essaie de simplifier le problème autant que possible] P>
En réalité, j'ai une petite classe (élément) contenant une clé INT et un double poids (avec getters & setters). P>
J'ai lu beaucoup de ces objets à partir d'un fichier et je dois obtenir les meilleurs objets (la plupart du poids) M. P>
En fait, j'utilise une priorityQueue avec un comparateur écrit pour comparer deux éléments, et cela fonctionne, mais c'est trop lent. P>
Savez-vous (je sais que vous faites) tout moyen plus rapide de le faire? P>
merci p>
4 Réponses :
Si M est de manière appropriée, trier tous les éléments peut perdre beaucoup de temps de calcul. Vous ne pouvez placer que les premiers objets M dans la file d'attente prioritaire (par exemple, un tas, un élément minimal sur le dessus), puis itérer sur le reste des éléments: chaque fois qu'un élément est supérieur au sommet du tas, retirez le dessus et poussez de nouveau élément dans le tas. p>
Alternativement, vous pouvez itérer sur toute la matrice une fois pour trouver une valeur de seuil statistique pour laquelle vous pouvez être très sûr que des objets plus que M avec une valeur plus grande (nécessiteront certaines hypothèses concernant les valeurs, par exemple si elles sont normalement distribué). Vous pouvez ensuite limiter le tri à tous les éléments avec une valeur plus grande. P>
Une file d'attente prioritaire basée sur le tas est une bonne structure de données pour ce problème. Tout comme une vérification de la santé mentale, vérifiez que vous utilisez correctement la file d'attente. p>
Si vous voulez les éléments de poids les plus élevés, utilisez un min em> -Queue, où le haut du tas est le plus petit article. Ajout de chaque article à une max-file d'attente et examiner les éléments supérieurs code> m code> lorsque cela n'est pas efficace. P>
Pour chaque élément, s'il y a moins de Certains tas ont des API de raccourci pour remplacer le haut du tas, mais la queue m code> dans la file d'attente, ajoutez l'élément actuel. Sinon, jeter un coup d'œil au sommet du tas. Si c'est moins que l'élément actuel, jetez-le et ajoutez l'élément actuel à la place. Sinon, jetez l'élément actuel. Lorsque tous les éléments ont été traités, la file d'attente contiendra les éléments
M code> Poids le plus élevé. P>
de Java (code> ne le fait pas. Malgré tout, la grande complexité est la même. P>
Bonne suggestion. La complexité de cet algorithme est O (n log m) pour obtenir le top-m de n éléments total.
@Tnay: vous avez un point sur ne pas effectuer une comparaison. Malheureusement, votre exemple de code effectue toujours un. Ceci résout le problème:
public int compare(ListElement i, ListElement j) { return i.getValue() - j.getValue(); }
Et, bien sûr, ce comparateur est bon à condition qu'il soit garanti que la différence entre I et J ne dépasse jamais INTEGER.MAX_VALUE.
En général, la soustraction est un choix médiocre de la mise en œuvre de la comparaison sur les valeurs de point flottant (la question indique clairement que le poids est un double code>). Si la différence est inférieure à une, elle sera mal forcée à zéro lors de la mise en oeuvre du résultat à un
int code>.
@Software singe: true. @erickson: Je n'avais pas remarqué que nous utilisions des valeurs à virgule flottante.
En plus du "Peek en haut de l'algorithme de l'enceinte", qui vous donne une complexité O (N log M) pour obtenir les éléments Top-M de N, voici deux autres solutions.
La mise en œuvre prioritaire de la JDK est un tas binaire équilibré. Vous devriez être capable de diffuser plus de performances d'un Fibonacci Heap Mise en œuvre. Il aura amorti de l'insert de temps constant, tandis que l'insertion dans un tas binaire a une complexité î © (journal n) de la taille du tas. Si vous faites cela pour chaque élément, alors vous êtes à Î © (N Log N). Trouver les éléments Top-M of N à l'aide d'un tas FIB a une complexité O (n + m journal n). Combinez ceci avec la suggestion de ne jamais insérer que des éléments M dans le tas et que vous avez O (N + M Log M), qui est aussi proche du temps linéaire que vous allez obtenir. P> < Solde> Solution 2: Traverser la liste M fois. strong> p> Vous devez être capable d'obtenir l'élément KTH-plus important dans une heure définie dans O (N). Tout simplement lire dans une liste et procéder à ce qui suit: p> qui vous donne O (n) heure. En cours d'exécution, vous devriez être capable d'obtenir les objets Top-M dans votre ensemble dans le temps O (NM), qui sera strictement inférieur à N Log N pour suffisamment grand N et suffisamment petit m. Par exemple, obtenir le top 10 sur un million d'articles prendra la moitié tant que l'utilisation d'une file d'attente de priorité binaire du tas, toutes les autres choses étant égales. P> p>
Votre réclamation sur le facteur de différence de vitesse entre un tas de fibonacci et un tas binaire suppose un logarithme binaire et aucune différence de facteurs constants, c'est-à-dire que c'est probablement faux.
Avez-vous exécuté un profileur sur ce code? Comment votre comparateur est-il écrit?
Public int Comparer (ListElement I, ListeElement J) {if (i.gevalue () - J.Getvalue ()> 0) Retour 1; sinon retour -1; }
ID suggère fortement que vous profilez de votre code et découvrez ce que fait exactement que votre code fonctionne plus lentement que vous le souhaitez. Avec aucun code affiché, et aucune information supplémentaire, il est difficile de répondre à cette question. Quelle partie fonctionne lentement?
Je ne sais pas si le compilateur l'optimise automatiquement cela dans l'absence de pertinence, mais sinon faire une comparaison telle que le public Int comparer (liste d'écoute i, liste j) {return (i.gevalue ()> = j.gevalue ())? 1: -1;} peut vous faire économiser un peu de temps.
Note latérale: Vous pouvez simplifier votre comparateur en tant que retour I.gevalue () - J.Getvalue ();
Comme indiqué par Tnay, sans autre information de profilage, vous «optimiser sans représentation» - c'est-à-dire optimiser sans savoir où votre problème est réellement. Je recommanderais d'obtenir un bon profileur - j'ai utilisé votre kilomètre dans le passé pour beaucoup de succès (500-800% des gains) dans le passé, bien qu'il existe d'autres profileurs Java.
L'utilisation de la soustraction pour mettre en œuvre un comparateur sur les doubles semble extrêmement risquée. Le résultat du comparateur est distribué à un int, tant de (la plupart? Tous?) Les différences significatives entre les poids pourraient être contraintes à zéro.
Le profilage ne révélera que des facteurs constants qui vous ralentissent. Améliorer d'abord l'algorithme.