【问题标题】:NSArray -> Find closest value - fastest wayNSArray -> 找到最接近的值 - 最快的方法
【发布时间】:2014-11-27 19:46:30
【问题描述】:

假设我已经订购了NSArrayNSNumbers

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;
}

这是我能想象到的最快的方式,也许有人有不同的想法?如何改进算法?

我查看了 egSOF question,但它搜索值而不是索引,并通过浏览所有值来实现。在索引的情况下,我们不必浏览整个数组。

【问题讨论】:

  • 为什么需要优化这个特定的操作?我建议您最好使用更快的容器类,而不是优化搜索。即使您检查每个元素,搜索也是 O(n)
  • @RogerNolan 我已经有一个数组,其中包含我的自定义类的许多对象。在其他之间,它也有我想要执行搜索的这些值。我不想复制所有这些,甚至是选定的值,因为这需要时间和内存。要更改容器类,我需要更改几乎整个应用程序,这是不可能完成任务的时间。我需要对其进行优化,因为该算法将每秒调用一次(计时器...)。
  • 看起来很适合binary search

标签: objective-c algorithm


【解决方案1】:

假设你有一个 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 的值。

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

【讨论】:

  • 我最初写了一个支持捕捉的 UICollectionViewLayout 拖放引擎——我写的很复杂。有了这个答案,我考虑在准备方法中缓存一些 x/y 值 - 在更新位置函数中,我现在使用您的 searchIndex 技巧来检查这些值和单元格框架原点。工作得非常好。太感谢了! ?
猜你喜欢
  • 2013-12-20
  • 2021-10-28
  • 2017-03-15
  • 1970-01-01
  • 2021-11-27
  • 2015-03-01
  • 2021-11-25
  • 2021-11-26
  • 1970-01-01
相关资源
最近更新 更多