objective-c - NSArray -> 找到最接近的值 - 最快的方法

标签 objective-c algorithm

假设我有一个 NSNumbers 的有序 NSArray:

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 ,但它搜索值而不是索引并通过浏览所有值来实现。在索引的情况下,我们不必浏览完整数组。

最佳答案

假设你有一个 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);

然后检查 searchIndex - 1 索引中是否存在与您的 myValue 最接近的数字:

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

记住您的数组必须按升序排序才能实现此技巧。

关于objective-c - NSArray -> 找到最接近的值 - 最快的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25864880/

相关文章:

ios - 可以使用此代码检测iPhone屏幕尺寸吗?

objective-c - 更新 MKMapView (iPhone) 的中心点和缩放

ios - 由于 "GCKConnectionSuspendReasonNetworkNotReachable",Cast session 暂停

algorithm - 不使用递归重写递归函数

algorithm - SPOJ 水 : Developing a BFS algorithm

从 C 中的另一个数组创建数组

java - 生成特定的数字序列

ios - 合并 NSDictionaries - NSUnknownKeyException

javascript - 验证 JavaScript 中的数学表达式?

ios - 如何修改文本字段数组中选定的 UITexFiled 值