Comment trouver l'indice d'un élément dans un TreeSet?

j'utilise un TreeSet<Integer> et je voudrais tout simplement à trouver l'indice d'un nombre dans l'ensemble. Y a-t-il une bonne façon de le faire qui utilise réellement la complexité O(log(n)) des arbres binaires?

(Si non, que dois-je faire, et personne ne sait pourquoi pas? Je suis curieux de savoir pourquoi une telle classe serait incluse dans Java sans quelque chose comme une fonction de recherche.)

25
demandé sur Óscar López 2011-10-27 08:08:46

5 réponses

comme le souligne @Yrlec set.headSet(element).size retourne 0 s'il n'existe pas de cet élément dans l'ensemble. Donc, nous ferions mieux de vérifier:

 return set.contains(element)? set.headSet(element).size(): -1;

Voici un test pour montrer le problème:

public static void main(String args[]){
    TreeSet<Integer> set = new TreeSet<>();
    set.add(4);
    set.add(2);
    set.add(3);
    set.add(1);

    System.out.println(set.headSet(1).size());//0
    System.out.println(set.headSet(2).size());//1
    System.out.println(set.headSet(3).size());//2
    System.out.println(set.headSet(4).size());//3
    System.out.println(set.headSet(-1).size());//0!!Caution!,retusn 0 though it does not exits

}
11
répondu Jaskey 2015-04-24 05:06:14

J'ai parcouru TreeSet et ses interfaces pendant un certain temps, et la meilleure façon que j'ai trouvée pour obtenir L'index d'un élément est:

set.headSet(element).size()

headSet(element) renvoie le sous -TreeSet des éléments de moins que son argument, de sorte que la taille de cet ensemble sera l'indice de l'élément en question. Une solution étrange en effet.

46
répondu jtbandes 2011-10-27 04:26:24

j'ai eu le même problème. Alors j'ai pris le code source de java.util.TreeMap et écrit IndexedTreeMap. Il implémente mon propre IndexedNavigableMap:

public interface IndexedNavigableMap<K, V> extends NavigableMap<K, V> {
   K exactKey(int index);
   Entry<K, V> exactEntry(int index);
   int keyIndex(K k);
}

l'implémentation est basée sur la mise à jour des poids des noeuds dans l'arbre rouge-noir quand il est modifié. Le poids est le nombre de noeuds enfant sous un noeud donné, plus un-moi. Par exemple, lorsqu'un arbre tourne à gauche:

    private void rotateLeft(Entry<K, V> p) {
    if (p != null) {
        Entry<K, V> r = p.right;

        int delta = getWeight(r.left) - getWeight(p.right);
        p.right = r.left;
        p.updateWeight(delta);

        if (r.left != null) {
            r.left.parent = p;
        }

        r.parent = p.parent;


        if (p.parent == null) {
            root = r;
        } else if (p.parent.left == p) {
            delta = getWeight(r) - getWeight(p.parent.left);
            p.parent.left = r;
            p.parent.updateWeight(delta);
        } else {
            delta = getWeight(r) - getWeight(p.parent.right);
            p.parent.right = r;
            p.parent.updateWeight(delta);
        }

        delta = getWeight(p) - getWeight(r.left);
        r.left = p;
        r.updateWeight(delta);

        p.parent = r;
    }
  }

updatewweight met tout simplement à jour les poids jusqu'à la racine:

   void updateWeight(int delta) {
        weight += delta;
        Entry<K, V> p = parent;
        while (p != null) {
            p.weight += delta;
            p = p.parent;
        }
    }

Et quand nous avons besoin de trouver l'élément à l'index ici est la mise en œuvre qui utilise des pondérations:

public K exactKey(int index) {
    if (index < 0 || index > size() - 1) {
        throw new ArrayIndexOutOfBoundsException();
    }
    return getExactKey(root, index);
}

private K getExactKey(Entry<K, V> e, int index) {
    if (e.left == null && index == 0) {
        return e.key;
    }
    if (e.left == null && e.right == null) {
        return e.key;
    }
    if (e.left != null && e.left.weight > index) {
        return getExactKey(e.left, index);
    }
    if (e.left != null && e.left.weight == index) {
        return e.key;
    }
    return getExactKey(e.right, index - (e.left == null ? 0 : e.left.weight) - 1);
}

est également très pratique pour trouver l'index d'une clé:

    public int keyIndex(K key) {
    if (key == null) {
        throw new NullPointerException();
    }
    Entry<K, V> e = getEntry(key);
    if (e == null) {
        throw new NullPointerException();
    }
    if (e == root) {
        return getWeight(e) - getWeight(e.right) - 1;//index to return
    }
    int index = 0;
    int cmp;
    if (e.left != null) {
        index += getWeight(e.left);
    }
    Entry<K, V> p = e.parent;
    // split comparator and comparable paths
    Comparator<? super K> cpr = comparator;
    if (cpr != null) {
        while (p != null) {
            cmp = cpr.compare(key, p.key);
            if (cmp > 0) {
                index += getWeight(p.left) + 1;
            }
            p = p.parent;
        }
    } else {
        Comparable<? super K> k = (Comparable<? super K>) key;
        while (p != null) {
            if (k.compareTo(p.key) > 0) {
                index += getWeight(p.left) + 1;
            }
            p = p.parent;
        }
    }
    return index;
}

J'implémenterai bientôt IndexedTreeSet, en attendant vous pouvez utiliser le jeu de touches de IndexedTreeMap.

mise à Jour: la version indexée de TreeSet est implémentée maintenant.

Vous pouvez découvrir le résultat de ce travail à http://code.google.com/p/indexed-tree-map/

11
répondu Vitaly Sazanovich 2014-01-09 10:41:28

TreeSet classe en Java n'a pas la capacité de trouver l'indice d'un nombre dans l'ensemble. Pour cela, vous devez fournir votre propre implémentation - c'est un arbre rouge-noir sous le capot, et il peut être augmenté pour supporter l'opération d'index. Jetez un oeil à l' OS-RANK procédure dans le chapitre "augmentation des Structures de données" de "Introduction aux algorithmes", c'est précisément ce que vous demandez.

0
répondu Óscar López 2011-10-27 04:29:57

ici montrer ma fonction:

/ / FUNCTION FOR GIVE A STRING POSITION INTO TREESET

private static void get_posistion(TreeSet abre, String codig) {
    Iterator iterator;
    iterator = abre.iterator();
    int cont = 0;
    String prova = "";

    while (iterator.hasNext()) {                      
        prova = iterator.next().toString();
        if (codig.equals(prova)) {
            System.out.println(cont);
        } else {
            cont++;
        }
    }
}
-2
répondu Geff 2015-11-16 19:34:04