8
votes

Table de hachage triée (Carte, Dictionnaire) Conception de la structure de données

Voici une description de la structure de données:

Il fonctionne comme une carte régulière avec obtenez , mettre et supprimer des méthodes , mais a un trier méthode qui peut être appelée à trier la carte. Cependant, la carte se souvient de sa structure triée, les appels ultérieurs à trier peuvent être beaucoup plus rapides (si la structure ne change pas trop entre les appels vers trier ).

Par exemple:

  • J'appelle le Mettez Méthode 1 000 000 fois.
  • J'appelle la méthode trier .
  • J'appelle le Mettez la méthode 100 fois plus.
  • J'appelle la méthode trier .

    La deuxième fois que j'appelle la méthode doit être une opération beaucoup plus rapide, car la structure de la carte n'a pas beaucoup changé. Notez que la carte ne doit pas nécessairement maintenir l'ordre trié entre les appels vers Trier .

    Je comprends que cela pourrait ne pas être possible, mais j'espère que o (1) obtenir , mettre et supprimer Opérations . Quelque chose comme Treemap assure garantie O (journal (n)) Coût de temps pour ces opérations, mais maintient toujours une commande triée (no trier méthode).

    Alors, quelle est la conception de cette structure de données?

    Modifier 1 - retourner les entrées Top-K

    Alhough J'aurais aimé entendre la réponse à l'affaire Général ci-dessus, mon cas d'utilisation est devenu plus spécifique: je n'ai pas besoin de tout ce qui est trié; Juste les meilleurs éléments K.

    Data Structure pour renvoyer efficacement les entrées top-k d'une table de hachage (carte, dictionnaire)

    Merci!


0 commentaires

6 Réponses :


0
votes

Je ne suis pas au courant d'une classification de la structure de données avec ce comportement exact, du moins pas dans des collections Java (ou de la classe de structures de données non linéaires). Peut-être que vous pouvez la mettre en œuvre, et il sera désormais connu comme le rudigermap .


1 commentaires

Une sorte de hashmap hybride / Treemap peut-être? Les insertions entrent dans le hashmap, trichent puis transfèrent les éléments HASHMAP dans le TREEMAP. Je ne sais pas comment vous obtiendriez O (1) pour les déménagements aussi bien que ... hmmm ..



1
votes

Je ne sais pas s'il y a un nom, mais vous pourriez stocker l'index actuel de chaque article sur le hachage.

C'est-à-dire que vous avez un hashmap et une liste objets

Lorsque vous Mettez , ajoutez à la queue ou à la tête de la liste et insérez-le dans le hachoir avec vos données et l'index de l'insertion. Ceci est O (1) .

Lorsque vous Obtenez , tirez-le de la HASHMAP et ignorez l'index. Ceci est O (1) .

Lorsque vous Supprimer , vous tirez de la carte. Prenez l'index et supprimez également de la liste. Ceci est O (1)

Lorsque vous Trier , triez simplement la liste. Soit mettre à jour les index sur la carte pendant le tri ou la mise à jour après la fin du tri complet. Cela n'affecte pas le tri O (nlgn) , car il s'agit d'une étape linéaire. O (nlgn + n) == O (nlgn)


2 commentaires

Je ne pense pas supprimer est o (1) ... lorsque vous appelez supprimer , il supprime de la liste et décède les index .


Juste parce que vous supprimer un objet à partir d'une liste triée ne signifie pas que ce n'est toujours pas trié ... c'est-à-dire. [3, 5, 6]. Il n'y a pas de 4 dans la liste, mais il est toujours trié correctement ... Donc, le tri ne devrait donc se produire après que le mettre .



8
votes

pour "o (1) obtenir, mettre et supprimer des opérations" Vous avez essentiellement besoin d'une recherche O (1) O (1), ce qui implique une fonction de hachage (comme vous le savez), mais les exigences d'une bonne fonction de hachage brisent souvent l'exigence de être facilement trié. (Si vous aviez une table de hachage dans laquelle des valeurs adjacentes sont mappées sur le même seau, elle serait dégénérée à O (n) sur de nombreuses données communes, ce qui est un cas pire que vous souhaitez généralement une fonction de hachage à éviter.)

Je peux penser à comment vous procurer 90% du chemin. Configurez une hache à côté d'un indice parallèle trié. L'index a une partie propre (commandée) et une partie sale (non ordonnée). L'index planerait les clés des valeurs (ou des références aux valeurs stockées dans la haquetable - selon laquelle vous vous convient en termes de performances ou d'utilisation de la mémoire). Lorsque vous ajoutez à la HASHTABLE, la nouvelle entrée est poussée à l'arrière de la liste sale. Lorsque vous retirez de la haquetable, l'entrée est annulée / retirée des parties propres et sales de l'index. Vous pouvez trier l'index, qui trie les entrées sales uniquement, puis la fusionne dans la partie "propre" de l'index déjà triée. Et évidemment, vous pouvez itérer sur l'indice.

Autant que je puisse le voir, cela vous donne le O (1) partout partout, sauf sur la mise en évidence et reste assez simple à mettre en œuvre avec des conteneurs standard (au moins comme prévu par C ++, Java ou Python). Il vous donne également la condition «deuxième tri est moins cher» en ne nécessitant que pour trier les entrées d'index sale, puis vous laisser faire une (n) fusionner. Le coût de tout cela est évidemment une mémoire supplémentaire pour l'index et l'indirection supplémentaire lors de l'utilisation.


1 commentaires

Vous pouvez également obtenir O (1) sur le Supprimer également, en faisant la saisie de la haquetable, citons une liaison à l'emplacement correspondant de l'index.



1
votes

Dictionnaire commandé

Les versions récentes de Python (2.7, 3.1) ont des "dictionnaires commandés" qui ressemblent à ce que vous décrivez.

Le "Dictionnaire commandé" de Python officiel est inspiré par les précédentes implémentations tiers, comme décrit dans le PEP 372 .

Références:


2 commentaires

CommandéDict conserve des entrées dans l'ordre d'insertion, pas un ordre de tri des clés naturels.


Vrai, mais il est triable, comme décrit dans la documentation Python. Cela semble être un ajustement assez raisonnable à la description de la question.



1
votes

Qu'est-ce que vous envisagez est une haquetable avec des pointeurs dans les entrées à la prochaine entrée dans la commande triée. C'est beaucoup comme le LinkedHashMap dans Java, sauf que les liens suivent un ordre de tri plutôt que l'ordre d'insertion. Vous pouvez réellement mettre en œuvre cela totalement en enveloppant une liaison LinkedHashMap et que la mise en oeuvre de transfert de tri les entrées du LinkedHashMap dans un Treemap, puis de nouveau dans une liaison LinkedHashMap.

Voici une implémentation qui trie les entrées dans une liste de matrices plutôt que de transférer à une carte d'arbre. Je pense que l'algorithme de tri utilisé par Collection.Sort fera un bon travail de fusion des nouvelles entrées dans la partie déjà triée. P>

public class SortaSortedMap<K extends Comparable<K>,V> implements Map<K,V> {

    private LinkedHashMap<K,V> innerMap;

    public SortaSortedMap() {
        this.innerMap = new LinkedHashMap<K,V>();
    }

    public SortaSortedMap(Map<K,V> map) {
        this.innerMap = new LinkedHashMap<K,V>(map);
    }

    public Collection<V> values() {
        return innerMap.values();
    }

    public int size() {
        return innerMap.size();
    }

    public V remove(Object key) {
        return innerMap.remove(key);
    }

    public V put(K key, V value) {
        return innerMap.put(key, value);
    }

    public Set<K> keySet() {
        return innerMap.keySet();
    }

    public boolean isEmpty() {
        return innerMap.isEmpty();
    }

    public Set<Entry<K, V>> entrySet() {
        return innerMap.entrySet();
    }

    public boolean containsKey(Object key) {
        return innerMap.containsKey(key);
    }

    public V get(Object key) {
        return innerMap.get(key);
    }

    public boolean containsValue(Object value) {
        return innerMap.containsValue(value);
    }

    public void clear() {
        innerMap.clear();
    }

    public void putAll(Map<? extends K, ? extends V> m) {
        innerMap.putAll(m);
    }

    public void sort() {
        List<Map.Entry<K,V>> entries = new ArrayList<Map.Entry<K,V>>(innerMap.entrySet());
        Collections.sort(entries, new KeyComparator());
        LinkedHashMap<K,V> newMap = new LinkedHashMap<K,V>();
        for (Map.Entry<K,V> e: entries) {
            newMap.put(e.getKey(), e.getValue());
        }
        innerMap = newMap;
    }

    private class KeyComparator implements Comparator<Map.Entry<K,V>> {

        public int compare(Entry<K, V> o1, Entry<K, V> o2) {
            return o1.getKey().compareTo(o2.getKey());
        }

    }

}


0 commentaires

4
votes

Pourquoi avez-vous besoin exactement d'une fonction de tri ()?
Que voulez-vous peut-être et besoin d'un arbre noir rouge.

http://fr.wikipedia.org/wiki/red-black_tree

Ces arbres sont automatiquement trier votre entrée par un comparateur que vous donnez. Ils sont complexes, mais ont d'excellentes caractéristiques O (n). Couple de vos entrées d'arbres comme clé avec un hachage Carte comme dictionnaire et vous obtenez votre DataStructure.

en Java, il est implémenté comme Treemap en tant qu'instance de type.


0 commentaires