How to find the index of an element in a TreeSet?

末鹿安然 提交于 2019-12-17 18:34:25

问题


I'm using a TreeSet<Integer> and I'd quite simply like to find the index of a number in the set. Is there a nice way to do this that actually makes use of the O(log(n)) complexity of binary trees?

(If not, what should I do, and does anyone know why not? I'm curious why such a class would be included in Java without something like a search function.)


回答1:


As @Yrlec points out set.headSet(element).size will returns 0 though there is no this element in the set. So we'd better check:

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

Here is a test case to show the problem:

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,returns 0 though it does not exist!

}



回答2:


I poked around TreeSet and its interfaces for a while, and the best way I found to get the index of an element is:

set.headSet(element).size()

headSet(element) returns the sub-TreeSet of elements less than its argument, so the size of this set will be the index of the element in question. A strange solution indeed.




回答3:


I had the same problem. So I took the source code of java.util.TreeMap and wrote IndexedTreeMap. It implements my own IndexedNavigableMap:

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

The implementation is based on updating node weights in the red-black tree when it is changed. Weight is the number of child nodes beneath a given node, plus one - self. For example when a tree is rotated to the left:

    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;
    }
  }

updateWeight simply updates weights up to the root:

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

And when we need to find the element by index here is the implementation that uses weights:

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);
}

Also comes in very handy finding the index of a key:

    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;
}

I will implement IndexedTreeSet soon, in the meanwhile you can use the key set from IndexedTreeMap.

Update: IndexedTreeSet is implemented now.

You can find the result of this work at http://code.google.com/p/indexed-tree-map/




回答4:


The TreeSet class in Java doesn't have the ability to find the index of a number in the set. For that, you'd have to provide your own implementation - it is a Red-Black tree under the hood, and it can be augmented to support the index operation. Take a look at the OS-RANK procedure in the chapter "Augmenting Data Structures" of "Introduction to Algorithms", it's precisely what you're asking for.




回答5:


here show my function:

//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++;
        }
    }
}


来源:https://stackoverflow.com/questions/7911621/how-to-find-the-index-of-an-element-in-a-treeset

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!