从排序后的地图中,我想检索 n 条目的子集,在指定值 v 之前启动 m 条目。例如,对于键集 k = {0.2,0.3,0.4,0.6,0.8,0.9,1.0}, n = 5, m的查询 = 2, v = 0.5,将返回{0.3,0.4,0.6,0.8,0.9}。是否在Java中支持这样的查询的数据结构的实现,而不必迭代整个(大)集?
我需要什么?插值。我想根据地图中的值插入 v 。但是,我有很多 v 。它们被排序,并且它们之间的间距远小于 k 中的间距。因此,我从地图中取出一系列条目,用它们做一些昂贵的预备计算(例如计算多项式的系数),然后可以快速插入该范围内的另一个值(通过用该值评估多项式)。 / p>
但为什么在 v 之前需要 m 条目? k 中的值通常是等间距的,为了避免插值间隔末端的高振荡的Runge现象,我只需将它们切掉,这意味着我需要在实际之前使用一些节点插值的有效间隔。
这有意义吗?你的建议是什么?
(如果像java.util.TreeMap.ceilingEntry()这样的方法会返回一个迭代器会很有趣,我可以使用它迭代两次。)
答案 0 :(得分:1)
这比这简单得多:
将前n个元素放在右边。
double[] k = new double[] {0.2, 0.3, 0.4, 0.6, 0.8, 0.9, 1.0};
int n=5;
int m=2;
double v=0.5;
int pos = Arrays.binarySearch(k, v);
if (pos < 0)
pos = -pos - 1;
while(pos > 0 && k[pos-1]==v)
--pos;
pos = Math.max(pos-m, 0);
double[] result = Arrays.copyOfRange(k, pos, Math.min(pos+n, k.length));
答案 1 :(得分:1)
使用headMap()
和 tailMap()
可能是最简单的解决方案。如果担心两次进行相同搜索的开销,则使用列表而不是映射可能是解决方案。我延长了Petar的建议。它现在可以处理键值对,由小子类Pair
表示:
public class DataSet {
// Usage example
public static void main (String [] args) {
DataSet nn = new DataSet ();
nn.add(0.2,1);
nn.add(0.3,2);
nn.add(0.4,3);
nn.add(0.6,4);
nn.add(0.8,5);
nn.add(0.9,6);
nn.add(1.0,7);
int n = 5;
int m = 2;
double v = 0.5;
ListIterator <Pair> it = nn.iterator(v);
for (int i=0; i<m; ++i)
it.previous();
for (int i=0; i<n; ++i)
System.out.append(it.next()+"\n");
}
// Implementation
TreeSet <Pair> set = new TreeSet <Pair> (new PairComparator());
ArrayList <Pair> list = new ArrayList <Pair> ();
boolean listUpToDate = false;
// Add data
boolean add (double x, double y) {
listUpToDate = false;
return set.add(new Pair(x,y));
}
// Get iterator at specified position
ListIterator <Pair> iterator (double v) {
if (!listUpToDate) {
list = new ArrayList (set);
listUpToDate = true;
}
int pos = Collections.binarySearch(list,v);
if (pos < 0)
pos = -pos - 1;
return list.listIterator(pos);
}
// Helper class
static class Pair implements Comparable <Double> {
double x, y;
Pair (double x, double y) {
this.x = x; this.y = y;
}
public int compareTo (Double d) {
return Double.valueOf(x).compareTo(d);
}
public String toString () {
return String.format("[%.1f,%.1f]",x,y);
}
}
// Used for sorting
class PairComparator implements Comparator <Pair> {
public int compare (Pair n0, Pair n1) {
return Double.valueOf(n0.x).compareTo(Double.valueOf(n1.x));
}
}
}
当然,也可以使用该列表,并确保在调用binarySearch()
之前对其进行排序。但是TreeSet
除了排序之外还有其优点,它可以防止重复键。
答案 2 :(得分:0)
您可以将条目放在已排序的数组中,并使用Arrays.binarySearch()。
但是如果你必须有像TreeMap这样的NavigableMap,你需要做两次查找来获取headMap()和tailMap()并迭代它们。