如何在NSArray上执行二进制搜索?

时间:2012-06-25 23:33:48

标签: objective-c ios algorithm nsarray binary-search

对(已)排序NSArray进行二进制搜索的最简单方法是什么?

到目前为止,我发现的一些潜在方式包括:

  1. 使用CFArrayBSearchValues(提及here) - 这会在NSArray上发挥作用吗?
  2. indexOfObject:inSortedRange:options:usingComparator:的方法NSArray假定数组已排序并采用类型为opts的{​​{1}}参数 - 这是否意味着它执行二进制搜索? docs只是说:

      

    使用给定的NSComparator块返回对象在指定范围内的索引与数组中的元素进行比较。

  3. 编写我自己的二分查找方法(类似于this)。

  4. 我应该补充说我正在为iOS 4.3 +

    编程

    提前致谢。

5 个答案:

答案 0 :(得分:15)

第二种选择绝对是最简单的。 Ole Begemann有关于如何使用NSArray的{​​{1}}方法的博客文章:

indexOfObject:inSortedRange:options:usingComparator:

请参阅NSArray Binary Search

答案 1 :(得分:7)

1和2都有效。 #2可能更容易;除了二进制搜索之外,对于该方法做任何事情当然没有意义(如果范围高于某个大小,比方说)。您可以在大型阵列上验证它只进行少量比较。

答案 2 :(得分:3)

CFArrayBSearchValues应该有效 - NSArray * toll-free bridged CFArrayRef。{/ p>

答案 3 :(得分:3)

我很惊讶没有人提到使用NSSet,[当它包含具有良好散列的对象时,例如大多数基础数据类型]执行恒定时间查找。不是将对象添加到数组中,而是将其添加到集合中(或者如果您需要为其他目的保留排序顺序,则将它们添加到两者中[或者在iOS 5.0或Mac OS X 10.7上有NSOrderedSet ])。

确定对象中是否存在对象:

NSSet *mySet = [NSSet setWithArray:myArray]; // try to do this step only once

if ([mySet containsObject:someObject])
{
    // do something
}

可替换地:

NSSet *mySet = [NSSet setWithArray:myArray]; // try and do this step only once

id obj = [mySet member:someObject];

// obj is now set to nil if the object doesn't exist or it is
// set to an object that "isEqual:" to someObject (which could be
// someObject itself).

重要的是要知道,如果每次执行查找时将数组转换为集合,将会失去任何性能优势,理想情况下,您将使用包含要测试的对象的预构造集。

答案 4 :(得分:3)

//Method to pass array and number we are searching for.
- (void)binarySearch:(NSArray *)array numberToEnter:(NSNumber *)key{


    NSUInteger  minIndex = 0;
    NSUInteger  maxIndex = array.count-1;
    NSUInteger  midIndex = array.count/2;


    NSNumber *minIndexValue = array[minIndex];
    NSNumber *midIndexValue = array[midIndex];
    NSNumber *maxIndexValue = array[maxIndex];

    //Check to make sure array is within bounds
    if (key > maxIndexValue || key < minIndexValue) {
        NSLog(@"Key is not within Range");
        return;
    }

    NSLog(@"Mid indexValue is %@", midIndexValue);

    //If key is less than the middleIndexValue then sliceUpArray and recursively call method again
    if (key < midIndexValue){
        NSArray *slicedArray = [array subarrayWithRange:NSMakeRange(minIndex, array.count/2)];
        NSLog(@"Sliced array is %@", slicedArray);
        [self binarySearch:slicedArray numberToEnter:key];

     //If key is greater than the middleIndexValue then sliceUpArray and recursively call method again
    } else if (key > midIndexValue) {
        NSArray *slicedArray = [array subarrayWithRange:NSMakeRange(midIndex+1, array.count/2)];
        NSLog(@"Sliced array is %@", slicedArray);
        [self binarySearch:slicedArray numberToEnter:key];

    } else {
      //Else number was found
        NSLog(@"Number found");
    }

}


//Call Method

@interface ViewController ()
@property(nonatomic)NSArray *searchArray;
@end


- (void)viewDidLoad {
    [super viewDidLoad];
//Initialize the array with 10 values
    self.searchArray = @[@1,@2,@3,@4,@5,@6,@7,@8,@9,@10];

//Call Method and search for any number
    [self binarySearch:self.searchArray numberToEnter:@5];
    // Do any additional setup after loading the view, typically from a nib.
}