一般に、キュー内のオブジェクトに連続したメモリ チャンクを強制的に占有させる良い方法はありません。ただし、特殊なケースに適したテクニックがいくつかあります。
大まかに言うと、これらの手法には、バイト配列の使用と、配列との間でのデータの「シリアル化」が含まれます。これは、非常に単純なオブジェクトを格納している場合、実際には非常に効果的です。たとえば、多数の 2D ポイント + 重みを格納している場合、重み、x 座標、y 座標に相当するバイトを単純に書き込むことができます。
もちろん、この時点での問題は、ピーク/ポッピング中にインスタンスを割り当てることです。これは、コールバックを使用することで回避できます。
格納されるオブジェクト自体が複雑な場合でも、これと同様の手法を使用して、重み用に 1 つの配列を保持し、実際のオブジェクトの参照の別の配列を保持することで、絶対に必要になるまでオブジェクト参照をたどることを回避できることに注意してください。
単純な不変の値型を格納するためのアプローチに戻ると、これは何ができるかの不完全なスケッチです。
abstract class LowLevelPQ<T> {
interface DataHandler<R, T> {
R handle(byte[] source, int startLoc);
}
LowLevelPQ(int entryByteSize) { ... }
abstract encode(T element, byte[] target, int startLoc);
abstract T decode(byte[] source, int startLoc);
abstract int compare(byte[] data, int startLoc1, int startLoc2);
abstract <R> R peek(DataHandler<R, T> handler) { ... }
abstract <R> R pop(DataHandler<R, T> handler) { ... }
}
class WeightedPoint {
WeightedPoint(int weight, double x, double y) { ... }
double weight() { ... }
double x() { ... }
...
}
class WeightedPointPQ extends LowLevelPQ<WeightedPoint> {
WeightedPointPQ() {
super(4 + 8 + 8); // int,double,double
}
int compare(byte[] data, int startLoc1, int startLoc2) {
// relies on Java's big endian-ness
for (int i = 0; i < 4; ++i) {
int v1 = 0xFF & (int) data[startLoc1];
int v2 = 0xFF & (int) data[startLoc2];
if (v1 < v2) { return -1; }
if (v1 > v2) { return 1; }
}
return 0;
}
...
}