私は以下のコードのようなものが仕事をすると信じています。抽象メソッドとしてelement - > keyの実装を残しました。カウンタが増加する数を要素に割り当てるために使用されていることに注意してください。また、add(...)
が複数のスレッドによって呼び出されている場合、FIFO内の要素は緩やかに順序付けされるだけであることにも注意してください。それは豪華なmax(...)
とmin(...)
ロジックを強制します。またその理由は、およそです。最初と最後は特殊なケースです。最初に明確に示すことができます。現在の実装が実際のインデックスを返すため、最後は扱いにくいです。
これはおおよその場所なので、0.0
と1.0
の間のAPIをfloat
に戻して、キュー内の相対位置を示すことを検討することをおすすめします。あなたのコードがpop(...)
以外のいくつかの手段を用いて除去することをサポートする必要がある場合
、あなたはすべての適切なint
/float
キャスト&丸めて、おおよそのサイズを使用し、((id - min)/(max - min)) * size
への復帰を変更する必要があります。
public abstract class ApproximateLocation<K extends Comparable<K>, T> {
protected abstract K orderingKey(T element);
private final ConcurrentMap<K, Wrapper<T>> _map = new ConcurrentSkipListMap<K, Wrapper<T>>();
private final Deque<Wrapper<T>> _fifo = new LinkedBlockingDeque<Wrapper<T>>();
private final AtomicInteger _counter = new AtomicInteger();
public void add(T element) {
K key = orderingKey(element);
Wrapper<T> wrapper = new Wrapper<T>(_counter.getAndIncrement(), element);
_fifo.add(wrapper);
_map.put(key, wrapper);
}
public T pop() {
Wrapper<T> wrapper = _fifo.pop();
_map.remove(orderingKey(wrapper.value));
return wrapper.value;
}
public int approximateLocation(T element) {
Wrapper<T> wrapper = _map.get(orderingKey(element));
Wrapper<T> first = _fifo.peekFirst();
Wrapper<T> last = _fifo.peekLast();
if (wrapper == null || first == null || last == null) {
// element is not in composite structure; fifo has not been written to yet because of concurrency
return -1;
}
int min = Math.min(wrapper.id, Math.min(first.id, last.id));
int max = Math.max(wrapper.id, Math.max(first.id, last.id));
if (wrapper == first || max == min) {
return 0;
}
if (wrapper == last) {
return max - min;
}
return wrapper.id - min;
}
private static class Wrapper<T> {
final int id;
final T value;
Wrapper(int id, T value) {
this.id = id;
this.value = value;
}
}
}
正確な位置、または近似値が欲しいですか?また、同じデータ/キーを再度挿入しますか? –
もう少し考えれば、近似は実際は大丈夫でしょう。何かご意見は?いいえ、同じキーを再度挿入する必要はありません。 –
@Alan基本構造が検索ツリーまたはスキップリストのバリエーションである場合、深さ制限検索。 – trutheality