11
votes

Comment puis-je définir un bon hashcode pour une liste liée circulaire en Java?

J'ai configuré une structure de données de liste liée circulaire qui représente un mot, et chaque élément de la liste est une lettre du mot. Au bas de ma question sont les définitions de la classe de la liste et de l'élément de la liste.

Le but de la structure de données de la liste est de pouvoir comparer les mots cycliques. Alors ... "image" et "Turepic" sont le même mot cyclique. Les deux listes seront donc égales. p>

donc je remplace égale () code> Lorsque vous comparez deux listes, et j'ai lu que lorsque vous devez remplacer égal () code>, vous devez Aussi remplacer hashcode () code>. Cependant, je n'ai pas vraiment une bonne idée de la façon de faire ça. P>

Comment dois-je définir un bon hashcode pour ce que j'ai mis en place? Quelles sont les choses que je devrais considérer? Dans l'exemple de la "photo" et "Turepic", les deux listes sont égales de sorte que leur code HashCode doit être identique. Toutes idées? P>

Merci, Hristo P>

public class Letter {
 char value;
 Letter theNextNode;

 /**
  * Default constructor for an element of the list.
  * 
  * @param theCharacter - the value for this node.
  */
 Letter(char theCharacter) {
  this.value = theCharacter;
 }
}


public class CircularWord {

 /*
  * Class Variables
  */
 Letter head;
 Letter tail;
 Letter theCurrentNode;

 int iNumberOfElements;


 /**
  * Default Constructor. All characters that make up 'theWord' are stored in a 
  * circular linked list structure where the tail's NEXT is the head. 
  */
 public CircularWord(String theWord) {

  char[] theCharacters = theWord.toCharArray();

  for (int iIndex = 0; iIndex < theCharacters.length; iIndex++) {
   this.addElement(theCharacters[iIndex]);
  }

  this.theCurrentNode = head;
  this.iNumberOfElements = theCharacters.length;
 }
}


0 commentaires

7 Réponses :


0
votes

Que diriez-vous de la somme des Hashcodes de tous les éléments de votre liste, chacun multiplié par une valeur arbitraire?

quelque chose comme xxx


20 commentaires

Pouvez-vous expliquer pourquoi vous pensez que cela fonctionne? Je pourrais faire ça, je ne comprends tout simplement pas. N'oubliez pas que les éléments d'une liste peuvent être identiques que dans une autre, mais ils doivent dans un ordre circulaire ... Son sommation pourrait ne pas être idéal.


A + B + C est identique à celui de B + C + A . Alors, résumant les termes donnerait la même valeur si vos listes contiennent les mêmes éléments, peu importe ce qu'ils commandent.


Ce n'est pas seulement une somme de hashcodes ... vous avez manqué 31 * Pièce hashcode, ce qui rend la position importante. S'il y a deux éléments, avec des hachages 50 et 100, puis 31 * (31 * 1 + 50) +100! = 31 * (31 * 1 + 100) +50.


@vivien: le code que vous présentez n'est pas la somme des Hashcodes de tous les éléments. Remarque 31 * HASHCODE - La valeur de code HASH précédente est multipliée par 31. Donc, avec deux éléments, il est = 31 * (31 * 1 + hashcode1) + hashcode2 . Certainement pas adapté à une liste circulaire.


@Hristo - Voir si ma solution aide. J'utilise la soustraction au lieu d'addition. La soustraction est non commutative et il semblerait donc que cela aiderait dans votre cas, qui est dépendant de l'ordre.


ERF, mauvaise lecture ... j'ai lu hashcode = hashcode + 31 * obj.hashcode (); . Mis à jour ...


@Vivin: Son cas n'est pas dépendant de l'ordre;)


Cela donnerait des hashcoodes différents pour "image" et "Turepic".


@Vivien Oops ... mon mauvais: P Mais si vous utilisez l'addition, l'image TUREPIC et TUERPCI seraient également égales, n'est-ce pas?


@Vivin: C'est ce qui est demandé. "Dans l'exemple de" Picture "et" Turepic ", les deux listes sont égales de sorte que leur hadroit doit être identique."


@ PÉTER: le code a été mis à jour. Maintenant le hashcode serait la même


@Tall ... Je pense que la soustraction est la bonne approche. "Picture" et "TUERPIC" ajouteront toujours à la même valeur, mais ce ne sont pas des listes égales. La soustraction sera donc capable de distinguer cela. Dois-je m'inquiéter des nombres négatifs?


@Vivien ah oui. Je me souviens juste que si deux objets sont égaux, ils doivent avoir les mêmes hashcodes, mais s'ils ont les mêmes hashcodes, ils ne sont pas nécessairement égaux!


@Hristo: avec des sous-traits, "Photo" et "Turepic" auraient différents hachages, bien qu'ils soient égaux. Qui brise le contrat de hashcode. Avec l'ajout, vous avez des conflits, mais cela ne casse pas le contrat HashCode (les conflits sont tolérés).


@Vivien ... bon point, mais comment éviterais-je le problème de "image" et "tuerpic" étant identique depuis l'addition de la même valeur, mais les listes ne sont pas égales?


@Vivien ... aussi, pourquoi utilisez-vous 31 ?


@Hristo comme indiqué dans la réponse 31 est une valeur arbitraire. Et il est toujours préférable que vous utilisiez un nombre premier ici.


@Hristo: Quant au pourquoi, avoir moins de collisions. "ABG" entrerait en collision avec "Aaag" sans ceci 31, par exemple.


@Vivien et @Colin ... Merci pour l'explication. Cela a du sens.


31 La prévention des collisions dans la formule actuelle est le porc. "AZ", "par", "CX", "DW", "EV", ... et obtenez le même code de hachage avec cette formule. On peut atteindre beaucoup moins de collisions avec très peu d'effort supplémentaire ... comme ma réponse montre.



15
votes

Donc, vous voulez un calcul de hashcode qui donne des résultats égaux pour "image" et "Turepic", mais (de préférence) différent du hachemode de par exemple. "Éruptic". Ainsi, il ne suffit pas de simplement ajouter les Hashcodes des lettres contenues dans le mot - vous devez également avoir des informations de position aussi, mais pourtant, il devrait être indépendant de la permutation réelle du mot. Vous devez définir des "classes d'équivalence" et calculer toujours le même hashcode pour chaque membre de la classe.

Le moyen le plus simple d'y parvenir est de sélectionner Sélectionner un membre spécifique de la classe d'équivalence et d'utiliser toujours le hashcode de cette variation pour tous les mots équivalents forts>. Par exemple. Sélectionnez la première variante alphabétiquement (merci à @Michael pour la résumer de manière concise). Pour "Photo" et al., Ce serait "Ctutrypi". "Picture" et "Turepic" (et toutes les autres variations équivalentes) doivent renvoyer le code de hachage de "Ctutrypi". Ce code de hachage pourrait être calculé par la méthode linkedlist standard, ou toute autre manière préférée. P>

On pourrait dire que ce calcul est très coûteux. TRUE, mais on pourrait cacher le résultat, de sorte que seul le premier calcul serait coûteux. Et je suppose que la sélection de la première variante alphabétique pourrait être optimisée assez bien dans le cas commun (par rapport à la solution triviale de générer toutes les permutations dans la classe d'équivalence spécifique, puis de les trier et de choisir le premier). P>

Par exemple Dans beaucoup de mots, la première lettre alphabétique est unique ("image" en est l'une d'entre elles - sa première lettre alphabétiquement est "C", et il n'y en a qu'un "C"). Vous n'avez donc besoin que de le trouver, puis calculez le hashcode à partir de là. Si ce n'est pas unique, vous devez comparer le deuxième, troisième, etc. Lettres après cela, jusqu'à ce que vous trouviez une différence (ou que vous vous relancez). P>

Mise à jour 2 - Exemples Strong > p>

  • "Abracadabra" contient 5 'A. Les 2e personnages après les "A sont" B "," C "," D "," B "et" A ", respectivement. Donc, dans la 2e manche de comparaison, vous pouvez conclure que la variation de lexicographiquement la plus petite est "AABRACADABR". LI>
  • "abab" contient 2 'A, et un "B" après chacun (et ensuite vous roulez, atteignant un "A" à nouveau, alors la quête se termine là-bas). Vous avez donc deux variantes identiques les plus petites lexicographiquement de celle-ci. Mais comme ils sont identiques, ils produisent évidemment le même hashcode. Li> ul>

    mise à jour: strong> à la fin, tout se résume à quel point avez-vous besoin du hashcode - c'est-à-dire que vous envisagez de mettre vos listes circulaires dans une collection associative comme Définir code> ou mappe code>. Sinon, vous pouvez faire avec une méthode de hachage simple ou même triviale. Mais si vous utilisez fortement une collection associative, une implémentation de hachage triviale vous offre de nombreuses collisions, ainsi que des performances sous-optimales. Dans ce cas, il vaut la peine d'essayer de mettre en œuvre cette méthode de hachage et de mesurer si elle paie elle-même en performance. P>

    Mise à jour 3: code d'échantillon h3>

    lettre code> est fondamentalement laissé la même chose que ci-dessus, je n'ai fait que les champs privés code>, renommé antextnode code> à suivant code> et ajouté getters / setters au besoin.

    dans de la circulaire code> J'ai fait plus de modifications: déposé queue code> et thecurrentnode code> et a fait le mot vraiment circulaire (c.-à-d. last.next == tête code>). Le constructeur, tostring code> et est égal à code> ne sont pas pertinents pour calculer le hashcode, ils sont donc omis pour le souci de simplicité. P>

    public class CircularWord {
        private final Letter head;
        private final int numberOfElements;
        
        // constructor, toString(), equals() omitted
    
        @Override
        public int hashCode() {
            return hashCodeStartingFrom(getStartOfSmallestRotation());
        }
    
        private Letter getStartOfSmallestRotation() {
            if (head == null) {
                return null;
            }
            Set<Letter> candidates = allLetters();
            int counter = numberOfElements;
    
            while (candidates.size() > 1 && counter > 0) {
                candidates = selectSmallestSuccessors(candidates);
                counter--;
            }
            return rollOverToStart(counter, candidates.iterator().next());
        }
    
        private Set<Letter> allLetters() {
            Set<Letter> letters = new LinkedHashSet<Letter>();
            Letter letter = head;
    
            for (int i = 0; i < numberOfElements; i++) {
                letters.add(letter);
                letter = letter.getNext();
            }
            return letters;
        }
    
        private Set<Letter> selectSmallestSuccessors(Set<Letter> candidates) {
            Set<Letter> smallestSuccessors = new LinkedHashSet<Letter>();
    
            char min = Character.MAX_VALUE;
            for (Letter letter : candidates) {
                Letter nextLetter = letter.getNext();
                if (nextLetter.getValue() < min) {
                    min = nextLetter.getValue();
                    smallestSuccessors.clear();
                }
                if (nextLetter.getValue() == min) {
                    smallestSuccessors.add(nextLetter);
                }
            }
            return smallestSuccessors;
        }
    
        private Letter rollOverToStart(int counter, Letter lastCandidate) {
            for (; counter >= 0; counter--) {
                lastCandidate = lastCandidate.getNext();
            }
            return lastCandidate;
        }
    
        private int hashCodeStartingFrom(Letter startFrom) {
            int hash = 0;
            Letter letter = startFrom;
            for (int i = 0; i < numberOfElements; i++) {
                hash = 31 * hash + letter.getValue();
                letter = letter.getNext();
            }
            return hash;
        }
    
    }
    


17 commentaires

Vous pourriez avoir des problèmes si votre mot contient deux fois la même lettre. Qu'en est-il de alphabet et abetalpha ?


Plus simplement, la première variante alphabétiquement?


@Michael, oui - bon point, cela rend encore plus simple d'en choisir un, merci :-)


+1: entraînera très peu de collisions, même si la recherche du premier mot alphabétique peut être quelque peu chère (pire des cas: O (longueur ^ 2)).


J'aime beaucoup votre idée, mais je ne sais pas comment la mettre en œuvre. Je n'ai jamais traité avec des codes de hasch avant, mais il semble un peu trop important de le calculer? Pouvez-vous peut-être offrir un exemple?


Trier la liste d'abord, puis calculer son hachage habituel, c'est ce que vous voulez dire?


@ abhin4v, non - voir l'exemple que j'ai donné.


@ Péter ... merci pour votre aide. Je pense vraiment que votre solution aboutira au hashcode "parfait" que je recherche, mais dans le but de ce projet, le temps passé à perfectionner le code de hachage ne donnera pas d'avantages équivalents. Mais je garderai cela à l'esprit chaque fois que je suis confronté à une situation similaire et que le hashcode doit être parfait. Merci!


@Hristo, vous pourriez avoir raison - ma première réaction à votre question était en fait que vous n'avez peut-être pas besoin de mettre en œuvre un tel hashcode. Il ne serait nécessaire que si vous envisagez de stocker vos listes circulaires dans un conteneur associatif comme une carte ou un ensemble. Mais alors j'ai commencé à réfléchir au problème néanmoins, et est venu avec cette idée ...


@Hristo, note que le calcul du hashcode lui-même ne serait pas un problème ici - vous pouvez copier l'algorithme standard de java.util.abstractlist . La partie plus délicieuse trouverait la première variante alphabétiquement et avec une vitesse raisonnable. Il faut tard dans la nuit où je suis, alors je ne vais pas avoir à produire un échantillon de code de travail, mais je pourrais y revenir un jour la semaine prochaine, juste pour le plaisir :-)


@Peter: trier et prendre le hashcode habituel semble fonctionner. Voir le code ici: Ideone.com/maptf


@ abhin4v, oui, mais cela donne le même hashcode pour "image" et "Ciputer" (et toute autre de ses permutations).


Je ne vois toujours pas comment vous pouvez normaliser tous les mots possibles "AABBCC" n'a pas de lettres uniques.


@TokenmacGuy: Les deux variantes commençant par "A", dans votre cas, sont AABBCC et ABBCCA, et le premier est lexicographiquement plus petit et serait choisi. C'est ce qu'il voulait dire par «comparer le deuxième, troisième, etc. Lettres après cela, jusqu'à ce que vous trouviez une différence».


Oh, je suppose que cela pourrait fonctionner. Il y a au plus 1 rotation minimale lexicographique unique. Mais je ne suis pas sûr que c'est ce que Péter Török a réellement déclaré. Si tel était mon code, je m'occuperais de cette étape lorsque l'objet est créé (la première permutation disponible est le moins lexé))


@TokenmacGuy, je voulais dire exactement ce que @blaisorblade supposait. Oui, vous pouvez trouver la variation lexicographiquement la plus petite au moment de la création, mais vous pouvez également le calculer paresseusement, uniquement lorsque (si) est nécessaire.


@Hristo, fyi j'ai ajouté un exemple de mise en œuvre à ma réponse.



0
votes

J'ai mal interprété votre question - je pensais que vous vouliez des haschodes différentes pour "image" et "Turepic"; Je pense que dans ce cas, vous pouvez obtenir un indice du fait que deux objets égaux doivent avoir le même code de hachage, mais deux objets qui ont le même code de hachage ne peuvent pas nécessairement être égaux.

Vous pouvez donc utiliser la solution de Vivien qui garantira que "l'image" et "Turepic" auront le même code de hachage. Cependant, cela signifie également que "l'image" et "PiCure" auraient les mêmes codes de hachage. Dans ce cas, votre méthode égale devra être plus intelligente et devra déterminer si la liste des deux lettres représente réellement le même mot. Essentiellement, votre méthode Equals aide à résoudre la collision que vous pouvez obtenir de "Photo" / "Turepic" et "PitCure".


11 commentaires

Cela donnerait des hashcoodes différents pour "image" et "Turepic".


Vérifié votre code avec une fonction de scala: def hash [t] (liste: liste [t]): int = list.foltleft (1) {(ACC, E) => (13 * ACC - (si e == null) 0 autre e.hashcode))} . Il donne différentes valeurs pour "ABCDE" et "EAOBCD".


ERM, A-B n'est généralement pas égal à B-A, mais le "AB" et "BA" sont censés être égaux ...


@ mériton / abhin4v j'ai mal interprété sa question. C'est pourquoi j'ai qualifié ma solution avec "si elle dépend de l'ordre". Donc, dans ce scénario, ma solution n'est pas fausse. J'ai depuis édité ma réponse


@Vivin ... Je suis sûr que mes égaux sont assez intelligents de savoir que "la photo" et "PiCure" ne sont pas égales. J'ai mis en place un tas d'essais unitaires qui testent un tas de variations différentes. Alors, que suggéreriez-vous maintenant, sachant que mes égaux sont légitimes?


@Hristo est votre égal suffisamment intelligent pour déterminer que image et tuturepic est égal? Si tel est le cas, vous devriez être prêt à partir. Dans les structures de données où l'égalité est importante (comme un hashset ou un hashmap), le code a d'abord examiné les Hashcodes. S'ils sont inégaux, il est garanti que les objets sont inégaux. Si les hashcodes sont égaux, alors est égal à est appelé pour déterminer réellement si les objets sont égaux ou inégaux


Mon équivalent est suffisamment intelligent pour connaître la "photo" et "Turepic" sont égaux. Tous mes tests de l'unité passent à l'exception du super intense où j'utilise 192 718 mots, et chacun est différent. Voici le problème: Java.Lang.AsséranceError: attendu: <192718> Mais était: <192468>. Je crois donc que mon hashcode n'est pas parfaite.


@Hristo C'est bon pour "image" et "pitcuure" pour avoir le même hashcode tant que vous pouvez résoudre l'égalité réelle dans la méthode .


D'accord merci. Je vais essayer de tester mes égaux plus soigneusement. Toute suggestion sur la façon de tester le hashcode?


@Hristo La chose la plus importante est que hashcode doit renvoyer le même code de hachage pour deux objets conceptuellement égaux. Dans votre cas, "Photo" et "Turepic" sont égaux, vous devez donc vous assurer que vous obtenez le même hashcode pour eux (ou même pour "ICTREP"). Cependant, cela signifie également que "PiCure" a le même code de hachage. Je recommanderais un test qui consolide à la fois Hashcode et est égal et teste réellement pour l'égalité. Comme je l'ai mentionné, c'est ce que certaines des classes de collecte (comme hashmap / hashset) font, pour tester l'égalité.


@Vivin ... l'a eu! Mon est égal () était si bon que cela a effectivement attrapé mon erreur personnelle dans l'assumation de quelque chose était vrai :) Merci pour votre aide!



3
votes
int hashcode() {
    int hash = 0;
    for (c in list) {
        hash += c * c;
    }
    return hash;
}
Since + is commutative, equal words will have equal hashcodes. The hashcode is not very discriminating (all letter permutations get the same hash code), but it should do the trick unless you usually put many permutations into the HashSet.Note: I add c * c rather than simply c in order to get less collisions for distinct letters.Note 2: Unequal lists with equal hash codes do not violate of the contract for hashcode. Such "collisions" should be avoided because they reduce performance, but they do not threaten the correctness of the program. In general, collisions can not be avoided, though it is certainly possible to avoid them more than in my answer, but doing so makes the hashcode more expensive to compute, which might more than eat any performance gain.

3 commentaires

Bien que cela donnerait le même hashcode pour "image" et "Turepic", mais aussi pour "Ciputer" et toute autre permutation des mêmes lettres.


+1 Pour indiquer que vous n'avez pas besoin de générer différents hashcodes pour différentes listes pour maintenir le contrat. Strictement parler, c'est impossible - à moins que vous n'envisens à une compression infinie et peut encoder chaque combinaison possible d'objets dans 32 bits!


Nitpick: Ce n'est pas impossible "à proprement parler", c'est tout simplement impossible (principe de trou de Pidgeon) :-).



0
votes
  1. Définir égale () et hashcode () pour lettre . Faites cela en utilisant uniquement le champ char .
  2. pour circulaire mot , implémente hashcode () en itérant à partir de tête à queue xor'ing les valeurs respectives de lettre.hashcode . Enfin xor le résultat avec une certaine constante.

    Une autre manière serait de canoniser les mots cicariques, représentant eux comme quelque chose comme: xxx

    Vous seriez ensuite implémenter égal () et hashcode () en déléguant à la chaîne string implémentations.


8 commentaires

J'aime Xor, donc je suis intéressé par votre idée. Cependant, la "image" xoring et "tuerpic" entraîneraient la même valeur? Si oui, ce n'est pas ce que je cherche depuis "image" et "tuerpic" ne sont pas des listes égales.


Aura de nombreuses collisions: "AB", "CD", "EF", "GH", "IJ", ... Tous obtenir le même hashcode.


@meriton hachage ('a') ^ hash ('B') me donne 3, hachage ('c') ^ hash ('d') me donne 7. Utilisation de Java 6 (Sun JVM) et Caractère.Accode () . Bien sûr, il y aura beaucoup de collisions, mais avec cette implémentation est difficile à faire mieux.


@Hristo Vous devez garantir que A = B implique hachage (a) = hachage (b), mais vous n'avez pas besoin (et en général, il est impossible) de garantir hachage (a) = hachage (b) implique A = b.


GPECHE: Mes excuses, l'exemple aurait dû être "BC", "DE", "FG", "HI", "JK", ... avec le code de ma réponse, ces mots ont tous différents hashcodes.


@meriton, il dépendra de votre implémentation particulière de lettre.HashCode () . Notez que j'ai dit "Faites cela en utilisant uniquement le champ de caractère" mais n'a pas spécifié ce que à faire avec le champ Char. Bien sûr, je pensais caractère.hashcode () ferait mieux, mais à Sun JVM, il semble être assez trivial.


@meriton De toute façon, il y aura beaucoup de collisions car avec des lettres XOR apparaissant un nombre pair de fois s'annuler s'annuler.


C'est pourquoi j'ai utilisé + au lieu de xor :-)



0
votes

Gardez à l'esprit que les hachons ne sont pas uniques. Deux objets différents peuvent hacher exactement la même valeur. Ainsi, HashCode est insuffisant pour déterminer l'égalité; Vous devez faire la comparaison réelle dans les égaux (). [Commentaire spéculatif supprimé. Omg]

hashcode () peut simplement retourner une constante dans tous les cas. Cela peut affecter les performances, mais c'est totalement valide. Une fois que vous avez effectué tout le reste, vous pouvez travailler sur un algorithme de hashcode plus efficace ().

C'est un bon article . Notez la section «paresseux hashcode».


6 commentaires

"En outre, je ne suis même pas sûr que deux valeurs identiques doivent avoir le même hashcode" - mais si elles ne le font pas, des choses étranges se produiront si vous stockez vos objets dans un hashset ou un hashmap. Pas une bonne idée.


Rien de bizarre ne se passera. Vous obtiendrez une recherche sous-optimale, selon le site que j'ai lié. Je ne dis pas que retourner une constante est une bonne idée, seulement qu'elle fonctionnera.


Non, le résultat de la recherche serait incorrect car la carte de hachage rechercherait la valeur dans le mauvais godet. Equals Les objets doivent avoir des hachices égaux. Les hachices égaux ne doivent pas nécessairement être d'objets égaux.


Donc, la manière dont le site fonctionne est pour les lecteurs de continuer à appuyer sur -1 jusqu'à ce que l'auteur supprime une déclaration spéculative avec une responsabilité appropriée? J'ai compris.


@Tony Ennis Bien sûr, c'est comme ça que ça va. Si la PPL n'aurait pas pressé l'Église, nous croyions toujours que le monde est plat. Mauvaise réponse -> -1, surtout si c'est quelque chose de fondamental. Et au lieu de deviner, vous pourriez aller vérifier (votre 2e déclaration est fausse, aussi).


Ne le prenez pas personnellement. L'objectif principal est de filtrer de bonnes informations du mauvais. Continuez simplement à répondre et à poser des questions, ne pensez pas trop à votre score, et cela augmentera progressivement. Ou alors tout le monde dit, et il semble être surtout vrai.



5
votes

Avez-vous réellement besoin d'utiliser vos hashcodes? Si vous n'avez pas l'intention de placer les membres de l'objet dans une structure de hasch, vous pouvez simplement ignorer le problème:

hash = 0
for each rotation
    hash += hash(permutation)
end
hash %= MAX_HASH


7 commentaires

+1 Pour une solution pragmatique - bien que je craignais toujours que ce type de raccourci de mise en œuvre quittera une personne avec une mauvaise régression de la performance dans quelques années lorsque quelqu'un finit par commencer à utiliser les structures en tant que touches de hashmap :-)


"Je" n'utilise pas les codes Hash, mais java.util.set.set les utilise chaque fois que je fais un appel sefiniquewords.contains (ce mot de page); . Donc, il est important que je le définisse correctement. Je l'ai travaillé cependant :)


Premièrement, toutes les permutations ne sont pas considérées comme égales. Seules les "rotations" sont. Ensuite, l'ajout des hachages peut provoquer des collisions. Par exemple, si vous prenez l'approche standard de l'interprétation des lettres comme coefficients d'un polynôme et utilisez une évaluation de ce polynôme comme un point autre que 0 que le hachage, l'addition sur toutes les rotations créerait un polynôme où tous les coefficients sont égaux, Perdant ainsi toute information sur l'ordre des lettres.


@meriton: Eh bien, si c'est la méthode utilisée derrière la fonction de hachage, un noyau différent (disons, hachage * = hachage (permutation)) résoudrait cela.


Probablement (mes compétences en mathématiques sont trop rouillées pour tenter une preuve d'une bonne distribution). Oui, cette méthode de calcul d'une fonction de hachage pour une séquence est l'approche standard dans la terre Java, présentée, par exemple dans la génération de code de l'Eclipse IDE et dans la bibliothèque standard (c.f. java.util.abstractlist.hashcode).


Je l'ai essayé, cela produit des résultats différents, au moins pour 1 + 2x + 3x ^ 2 (et ses permutations) contre 3 + 2x + x ^ 2 (et ses permutations).


+1, idée pratique. Si un gars vient et essaie d'utiliser cela sans vérifier la méthode HashCode , sa faute. Il suffit d'ajouter un avertissement dans un commentaire. OTOH, si l'op est en utilisant hashset / hashmap ou appelez autrement cette méthode, mieux le mettre en œuvre correctement.