如何在TreeSet中找到元素的索引?

时间:2011-10-27 04:08:46

标签: java algorithm data-structures treeset sortedset

我正在使用TreeSet<Integer>而我非常想在集合中找到数字的索引。有没有一种很好的方法来实际利用二叉树的O(log(n))复杂度?

(如果没有,我应该怎么做,有谁知道为什么不呢?我很好奇为什么这样的类会被包含在Java中,而不需要搜索功能。)

5 个答案:

答案 0 :(得分:47)

我在TreeSet及其接口周围探索了一段时间,我发现获取元素索引的最佳方法是:

set.headSet(element).size()

headSet(element)返回小于其参数的元素的子TreeSet,因此该集合的大小将是所讨论元素的索引。确实是一个奇怪的解决方案。

答案 1 :(得分:14)

由于@Yrlec指出set.headSet(element).size将返回0,尽管该集合中没有此元素。所以我们最好检查一下:

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

这是一个显示问题的测试用例:

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

}

答案 2 :(得分:12)

我遇到了同样的问题。所以我获取了java.util.TreeMap的源代码并编写了 IndexedTreeMap 。它实现了我自己的 IndexedNavigableMap

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

实现基于更改红黑树中的节点权重。权重是给定节点下的子节点数加一个自身。例如,当树向左旋转时:

    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只是更新权重到根:

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

当我们需要通过索引找到元素时,这是使用权重的实现:

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

还可以非常方便地找到密钥的索引:

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

我很快就会实现IndexedTreeSet,同时你可以使用IndexedTreeMap中的键集。

更新:现在已实施IndexedTreeSet。

您可以在http://code.google.com/p/indexed-tree-map/

找到这项工作的结果

答案 3 :(得分:0)

Java中的TreeSet类无法在集合中查找数字的索引。为此,您必须提供自己的实现 - 它是一个红黑树,它可以扩充以支持索引操作。请查看“算法简介”中“扩充数据结构”一章中的OS-RANK过程,这正是您所要求的。

答案 4 :(得分:-2)

这里显示我的功能:

//为树木带来一席之地的功能

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