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

后端 未结 5 1240
执笔经年
执笔经年 2020-12-09 08:26

I\'m using a TreeSet 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

相关标签:
5条回答
  • 2020-12-09 08:44

    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.

    0 讨论(0)
  • 2020-12-09 08:53

    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++;
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-09 08:55

    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.

    0 讨论(0)
  • 2020-12-09 08:56

    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!
    
    }
    
    0 讨论(0)
  • 2020-12-09 08:59

    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/

    0 讨论(0)
提交回复
热议问题