【发布时间】:2011-04-01 00:28:59
【问题描述】:
我只是改写我刚才问的question。
我有一个排序数组{2.0,7.8,9.0,10.5,12.3}
如果我输入 9.5 找到 9.0 和 10.5 以表明 9.5 在 9.0 和 10.5 之间(9.5 >=9.0 和
如果还有其他合适的数据结构请评论。
【问题讨论】:
-
请接受您之前问题的答案。
我只是改写我刚才问的question。
我有一个排序数组{2.0,7.8,9.0,10.5,12.3}
如果我输入 9.5 找到 9.0 和 10.5 以表明 9.5 在 9.0 和 10.5 之间(9.5 >=9.0 和
如果还有其他合适的数据结构请评论。
【问题讨论】:
我会那样做的
double valuebefore = 0;
double valueafter = 0;
double comparevalue = 9;
foreach (var item in a)
{
valueafter = item;
if (item > comparevalue)
{
break;
}
valuebefore = item;
}
System.Console.WriteLine("Befor = {0} After = {1}", valuebefore, valueafter);
【讨论】:
二分查找肯定是“标准”方法 - http://en.wikipedia.org/wiki/Binary_search_algorithm。速度是 O(log(N)) 而不是线性的。
在某些特殊情况下,您可以做得比 O(log(N)) 更好。但是,除非您正在处理真正巨大的数组大小并且满足这些特殊情况,否则您的二进制搜索确实是最快的方法。
【讨论】:
确实,您可以使用Arrays.binarySearch 快速定位 9.0 和 10.0。
【讨论】:
对于少量的 bin,排序链表将是最优雅的。你扫描它,当你发现一个更大的数字时,你就有了范围。
对于非常大的数字,值得将它们放入 BTree 或类似的树结构中以获得 O(log(N)) 性能。
在 Java 中,您可以为此使用 TreeSet。
lowerBound = bounds.headSet(yourNumber).last(); upperBound = bounds.tailSet(yourNumber).first();
或类似的将是 O(logN) 大数。
【讨论】:
如果输入的数字在一个数组中,那么二分查找会很方便。每次搜索失败时,表示数组中不存在该数字,索引low 和high 处的数组元素将为您提供范围。
【讨论】:
最有效的(空间和时间方面)是将其实现为修改后的二分搜索。
一个简单(但效率较低)的解决方案是将数组替换为NavigableMap<Double, Double>,并使用floorKey 和ceilingKey 来查找边界值。假设您使用TreeMap,这与二分查找具有相同的复杂性。
【讨论】:
这是我刚刚为你写的一个二分搜索算法,它可以解决问题:
import java.util.Random;
public class RangeFinder {
private void find(double query, double[] data) {
if (data == null || data.length == 0) {
throw new IllegalArgumentException("No data");
}
System.out.print("query " + query + ", data " + data.length + " : ");
Result result = new Result();
int max = data.length;
int min = 0;
while (result.lo == null && result.hi == null) {
int pos = (max - min) / 2 + min;
if (pos == 0 && query < data[pos]) {
result.hi = pos;
} else if (pos == (data.length - 1) && query >= data[pos]) {
result.lo = pos;
} else if (data[pos] <= query && query < data[pos + 1]) {
result.lo = pos;
result.hi = pos + 1;
} else if (data[pos] > query) {
max = pos;
} else {
min = pos;
}
result.iterations++;
}
result.print(data);
}
private class Result {
Integer lo;
Integer hi;
int iterations;
long start = System.nanoTime();
void print(double[] data) {
System.out.println(
(lo == null ? "" : data[lo] + " <= ") +
"query" +
(hi == null ? "" : " < " + data[hi]) +
" (" + iterations + " iterations in " +
((System.nanoTime() - start) / 1000000.0) + " ms. )");
}
}
public static void main(String[] args) {
RangeFinder rangeFinder = new RangeFinder();
// test validation
try {
rangeFinder.find(12.4, new double[] {});
throw new RuntimeException("Validation failed");
} catch (IllegalArgumentException e) {
System.out.println("Validation succeeded");
}
try {
rangeFinder.find(12.4, null);
throw new RuntimeException("Validation failed");
} catch (IllegalArgumentException e) {
System.out.println("Validation succeeded");
}
// test edge cases with small data set
double[] smallDataSet = new double[] { 2.0, 7.8, 9.0, 10.5, 12.3 };
rangeFinder.find(0, smallDataSet);
rangeFinder.find(2.0, smallDataSet);
rangeFinder.find(7.9, smallDataSet);
rangeFinder.find(10.5, smallDataSet);
rangeFinder.find(12.3, smallDataSet);
rangeFinder.find(10000, smallDataSet);
// test performance with large data set
System.out.print("Preparing large data set...");
Random r = new Random();
double[] largeDataSet = new double[20000000];
largeDataSet[0] = r.nextDouble();
for (int n = 1; n < largeDataSet.length; n++) {
largeDataSet[n] = largeDataSet[n - 1] + r.nextDouble();
}
System.out.println("done");
rangeFinder.find(0, largeDataSet);
rangeFinder.find(5000000.42, largeDataSet);
rangeFinder.find(20000000, largeDataSet);
}
}
【讨论】: