我只是改寫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和10.5 <)之間的最快方法是什麼? 二進制搜索是一個選項嗎?但是因爲輸入不需要在數組中。我不知道我應該怎麼做。
另外如果有其他任何適合的數據結構請評論。
我只是改寫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和10.5 <)之間的最快方法是什麼? 二進制搜索是一個選項嗎?但是因爲輸入不需要在數組中。我不知道我應該怎麼做。
另外如果有其他任何適合的數據結構請評論。
這裏是一個二進制搜索算法我只寫了你做的伎倆:
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);
}
}
我會那樣做
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);
這就是線性掃描。對於小型陣列來說不錯,但Emil想要一個更優雅的解決方案(我假設Emil知道如何以某種方式實現它)。 – helios 2010-08-19 09:28:21
二進制搜索肯定會是「標準」的做法 - http://en.wikipedia.org/wiki/Binary_search_algorithm。速度是O(log(N))而不是線性。
在某些特殊情況下,您可以比O(log(N))做得更好。但除非你正在處理真正龐大的陣列尺寸和滿足這些特殊情況,那麼你的二分查找確實是最快的方法。
實際上,您可以使用Arrays.binarySearch
快速找到9.0和10.0。
對於少量垃圾箱,排序後的鏈接列表最爲優雅。你掃描它,當你發現一個更大的數字你有範圍。
對於非常大的數字,爲了獲得O(log(N))性能,將它們放在BTree或類似的樹結構中是值得的。
在Java中,您可以爲此使用TreeSet。
lowerBound = boundaries.headSet(yourNumber).last(); upperBound = boundaries.tailSet(yourNumber).first();
或類似的將爲O(logN)爲大數字。
如果輸入數字在一個數組中,那麼二分法搜索將很方便。每次搜索失敗時,表示該數字不存在於數組中,索引low
和high
上的數組元素將爲您提供範圍。
最有效的(空間和時間)是將其作爲修改的二進制搜索來實現。
一個簡單(但效率較低)的解決方案是用NavigableMap<Double, Double>
替換陣列,並使用floorKey
和ceilingKey
來查找邊界值。假設您使用TreeMap
,這與二分查找具有相同的複雜度。
接受的回答你剛纔的問題,請。 – 2010-08-19 09:16:04