Pourquoi Chaîne.hashCode() en Java, ont de nombreux conflits?

Pourquoi Chaîne.hashcode() ont tant de conflits?

Je suis en train de lire la Chaîne de caractères.hashCode() en jdk1.6, ci-dessous la des codes de

public int hashCode() {
    int h = hash;
    if (h == 0) {
        int off = offset;
        char val[] = value;
        int len = count;

        for (int i = 0; i < len; i++) {
            h = 31*h + val[off++];
        }
        hash = h;
    }
    return h;
}

Cela ressemble assez déroutant pour moi car il a de nombreux conflits; bien qu'il n'est pas nécessaire d'être unique (nous pouvons toujours compter sur la equals()), mais moins de conflits signifie de meilleures performances sans visiter les entrées dans une liste liée.

Supposons que nous avons deux personnages, alors, aussi longtemps que nous pouvons trouver deux chaînes de caractères qui correspondent au-dessous de l'équation, alors nous aurons le même hashcode()

a * 31 +b = c * 31 +d

Il sera facile de conclure que (a-c) * 31 = d-b
prenons un exemple simple, c'est de faire un-c = 1 et d-b = 31;
j'ai donc écrit ci-dessous les codes de test simple

public void testHash() {
    System.out.println("A:" + (int)'A');
    System.out.println("B:" + (int)'B');
    System.out.println("a:" + (int)'a');

    System.out.println("Aa".hashCode() + "," + "BB".hashCode());
    System.out.println("Ba".hashCode() + "," + "CB".hashCode());
    System.out.println("Ca".hashCode() + "," + "DB".hashCode());
    System.out.println("Da".hashCode() + "," + "EB".hashCode());        
}

il permet d'imprimer ci-dessous les résultats qui signifie que toutes les chaînes ont le même hashcode(), et il est facile de le faire dans une boucle.

A:65 
B:66
a:97
2112,2112
2143,2143
2174,2174
2205,2205

pire encore, supposons que nous avons 4 caractères dans la chaîne, en fonction de l'algorithme, supposons que les 2 premiers caractères produire de l'a2, le 2ème 2 caractères produire b2;
le hashcode sera toujours a2 * 31^2 + b2
ainsi, avec a2 et b2 de l'égalité entre les 2 chaînes de caractères, nous allons obtenir plus de chaînes avec hashcode() de conflit.
de tels exemples sont "AaAa", "BBBB" et ainsi de suite;
ensuite, nous aurons 6 caractères 8 caractères......

supposons que la plupart du temps on utilise des caractères ascii tableau dans une chaîne de caractères qui sera utilisée dans une table de hachage ou de table de hachage, puis le choisi le premier numéro 31 ici est vraiment trop petite;

une solution facile est d'utiliser un plus grand nombre premier (heureusement, 257 est un nombre premier), ce qui peut éviter ce conflit. bien sûr, choisir un trop grand nombre sera la cause renvoyée int valeur d'être débordé si la chaîne est très longue, mais je suppose que la plupart du temps la chaîne utilisée comme une clé n'est pas que les grandes?
bien sûr, il pouvait toujours retourner une valeur de type long pour éviter cela.

ci-dessous est ma version modifiée de betterhash (), qui peut résoudre de tels conflits facilement
en exécutant les codes, il permet d'imprimer les valeurs ci-dessous, qui est efficace pour résoudre ce problème.

16802,17028
17059,17285
17316,17542
17573,17799

mais pourquoi jdk ne pas le fixer? thx.

@Test
public void testBetterhash() {
    System.out.println(betterHash("Aa") + "," + betterHash("BB"));      
    System.out.println(betterHash("Ba") + "," + betterHash("CB"));
    System.out.println(betterHash("Ca") + "," + betterHash("DB"));
    System.out.println(betterHash("Da") + "," + betterHash("EB"));
}

public static int betterHash(String s) {
    int h = 0;
    int len = s.length();

    for (int i = 0; i < len; i++) {
        h = 257*h + s.charAt(i);
    }
    return h;
}
  • Si vous souhaitez obtenir des pinailleurs, il y a théoriquement un nombre infini de collisions, peu importe la force de votre hash.
  • Je crois que vous vouliez dire des clés dans une carte au lieu d'entrées dans une LinkedList.
  • Si vous voulez demander votre hash est "mieux", vous devriez réellement de la procédure de hachage, dire, chaque chaîne de caractères (au moins ascii) de moins de 8 ou autant de personnages, puis de comparer le nombre de collisions par rapport à l'original. J'imagine que 8 caractères est beaucoup plus proche de la moyenne de la taille de la clé de 4 (si ce n'est pas encore sur le bas côté!).
  • En effet, hetaoblog dit que la nouvelle valeur de hachage débordement si la clé est "très long"; en fait, il va le faire avec seulement 5 caractères.
  • thx pour le signaler, je ne savais pas ce-- il suffit d'exécuter un test et ce qui se passe comme vous l'avez dit--
  • J'ai peut-être un malentendu, mais votre meilleur hash solution est de remplacer un facteur constant avec l'autre (les deux premiers, de sorte qu'ils ont fondamentalement les mêmes propriétés mathématiques) et jugent qu'il est mieux, car il n'y a pas de collisions sur la base de 4 arbitraire choisi cordes? Que faire si je pick 4 arbitraire d'autres chaînes? Soudain, l'ancienne version est mieux encore.. Il y a de mieux hashcodes là-bas et que vous pouvez prouver mathématiquement qu'ils sont mieux, mais ils sont beaucoup plus complexe et plus lent.
  • Je pars de ce commentaire comme une plainte pour ceux qui ont eu cela comme un non-constructive de la question. La question "Pourquoi la Chaîne.hashcode() ont tant de conflits?" est vraiment celui qui mérite discussion dans toute technologie Q&A. les Gens ont besoin de comprendre l'objectif, factuel réponse à cette question. Je pense aussi que les réponses à cette question ont fait du bon boulot pour répondre à l'objectif en question. Je pense aussi que l'affiche a fourni une belle solution à ce problème spécifique, il a fait face. Nous avons tous besoin d'écrire un domaine spécifique de fonctions de hachage, de temps à autre.

InformationsquelleAutor hetaoblog | 2012-02-23