Tôi gặp vấn đề tương tự. Vì vậy, tôi lấy mã nguồn của java.util.TreeMap và viết IndexedTreeMap. Nó thực hiện của riêng tôi IndexedNavigableMap:
public interface IndexedNavigableMap<K, V> extends NavigableMap<K, V> {
K exactKey(int index);
Entry<K, V> exactEntry(int index);
int keyIndex(K k);
}
Việc thực hiện dựa trên việc cập nhật trọng lượng nút trong cây đỏ-đen khi nó được thay đổi. Trọng lượng là số lượng các nút con bên dưới một nút nhất định, cộng với một - tự. Ví dụ khi một cây có thể xoay sang trái:
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 chỉ đơn giản là cập nhật trọng lượng lên vào thư mục gốc:
void updateWeight(int delta) {
weight += delta;
Entry<K, V> p = parent;
while (p != null) {
p.weight += delta;
p = p.parent;
}
}
Và khi chúng ta cần phải tìm ra nguyên tố theo chỉ số ở đây là việc thực hiện rằng sử dụng trọng lượng:
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);
}
Cũng có rất tiện dụng tìm kiếm các chỉ số của một phím:
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;
}
Tôi sẽ sớm triển khai IndexedTreeSet, trong khi đó bạn có thể sử dụng bộ khóa từ IndexedTreeMap.
Cập nhật: Chỉ mụcTreeSet được triển khai ngay bây giờ.
Bạn có thể tìm thấy những kết quả của công tác này tại http://code.google.com/p/indexed-tree-map/
Ít nhất nó có thể được tìm thấy trong 'O (n)' với phép lặp ... nó sẽ không làm tôi ngạc nhiên nếu có thay thế trong ổi hoặc một phần e "thư viện apache". –
Đối với ints, một mảng int [] thông thường có thể hiệu quả hơn. (bạn có thể sắp xếp nó trước và sau đó sử dụng Arrays.binarySearch). Và nó hiệu quả hơn trong mọi trường hợp, bởi vì không có quyền anh. –