假设我订了NSArray
NSNumbers
的订单{/ 1}:
2, 4, 8, 15, 16, 20 // for simplicity let's treat it as array of int's instead of NSNumbers
现在我需要找到最接近的索引,让我们说value == 19
。
searchValue = 19;
minIndex = 0;
maxIndex = array.count - 1;
currentIndex = (int)floorf(maxIndex / 2.f);
while (maxIndex - minIndex == 1) {
if (array[currentIndex] < searchValue) { // go right
minIndex = currentIndex;
} else if (array[currentIndex] > searchValue) { // go left
maxIndex = currentIndex;
} else { // exact value, rather low probability of happening
return currentIndex;
}
currentIndex = (int)floorf((maxIndex - minIndex) / 2.f);
}
// let's check values around, who has smaller difference
int leftDifference = (currentIndex - 1 >= 0) ? abs(array[currentIndex - 1] - searchValue) : INT_MAX;
int rightDifference = (currentIndex + 1 < array.count) ? abs(array[currentIndex + 1] - searchValue) : INT_MAX;
int centralDifference = abs(array[currentIndex] - searchValue);
if (leftDifference < rightDifference && leftDifference < centralDifference) {
return currentIndex - 1;
} else if () {
return currentIndex + 1;
} else {
return currentIndex;
}
这是我能想象到的最快的方式,也许有人有不同的想法?如何改进算法?
我已经查看了例如SOF question,但它搜索的是值而不是索引,并通过浏览所有值来完成。如果是索引,我们不必浏览完整数组。
答案 0 :(得分:9)
让我们假设你有一个NSNumbers数组:
NSArray *array = @[@(2), @(4), @(8), @(15), @(16), @(20)];
您正在寻找myValue
,如下所示:
NSNumber *myValue = @(17);
使用indexOfObject:inSortedRange:options:usingComparator
方法查找与您值最接近的数组索引。二进制搜索具有O(log n)性能,因此非常快。
NSInteger searchIndex = MIN([array indexOfObject: myValue inSortedRange:NSMakeRange(0, array.count)
options:NSBinarySearchingFirstEqual | NSBinarySearchingInsertionIndex
usingComparator:^NSComparisonResult(NSNumber *obj1, NSNumber *obj2) {
return [obj1 compare:obj2];
}], [array count] - 1);
然后检查myValue
索引上是否存在与您searchIndex - 1
最近的数字:
if (searchIndex > 0) {
CGFloat leftHandDiff = ABS(((NSNumber *)array[searchIndex - 1]).floatValue - myValue.floatValue);
CGFloat rightHandDiff = ABS(((NSNumber *)array[searchIndex]).floatValue - myValue.floatValue);
if (leftHandDiff == rightHandDiff) {
//here you can add behaviour when your value is in the middle of range
NSLog(@"given value is in the middle");
} else if (leftHandDiff < rightHandDiff) {
searchIndex--;
}
}
NSLog(@"The nearest value to %f is %d in array at index %d", myValue.floatValue, array[searchIndex], searchIndex);
瞧,瞧!现在,您现在是与myValue
最接近的值。
请记住,您的array
必须按升序排序以制作此技巧。