【问题标题】:How to perform binary search on NSArray?如何在 NSArray 上执行二进制搜索?
【发布时间】:2012-06-27 06:32:57
【问题描述】:

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

目前我发现的一些潜在方法包括:

  1. CFArrayBSearchValues 的使用(提到了here) - 这对NSArray 有效吗?

  2. NSArray 的方法 indexOfObject:inSortedRange:options:usingComparator: 假定数组已排序并采用 opts 类型的参数 NSBinarySearchingOptions - 这是否意味着它执行二进制搜索? docs 就说:

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

  3. 编写我自己的二进制搜索方法(类似于this)。

我应该补充一点,我正在为 iOS 4.3+ 编程

提前致谢。

【问题讨论】:

  • 为什么不使用 NSDictionary 呢? objectForKey: 会搜索你。
  • 关于这个的几个问题 - 对于对象搜索,字典比数组有什么好处?另外,为了使用您建议的方法,我不需要知道对象的键吗?我首先在数组中搜索对象的原因是我不知道它的索引 - 如果我更改为字典实现,那么这意味着我不知道键。

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


【解决方案1】:

CFArrayBSearchValues 应该可以工作——NSArray *toll-free bridgedCFArrayRef

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 这就是我的想法 - 文档似乎有点缺乏,因为他们实际上并没有声明它执行二进制搜索(他们只是强烈建议)。如果我有时间做你建议的测试,我一定会在这里发布我的结果。
    【解决方案3】:

    第二个选项绝对是最简单的。 Ole Begemann 有一篇关于如何使用NSArrayindexOfObject:inSortedRange:options:usingComparator: 方法的博文:

    NSArray *sortedArray = ... // must be sorted
    id searchObject = ...
    NSRange searchRange = NSMakeRange(0, [sortedArray count]);
    NSUInteger findIndex = [sortedArray indexOfObject:searchObject 
                                    inSortedRange:searchRange
                                          options:NSBinarySearchingFirstEqual
                                  usingComparator:^(id obj1, id obj2)
                                  {
                                      return [obj1 compare:obj2];
                                  }];
    

    NSArray Binary Search

    【讨论】:

    • 请记住,如果您稍后使用 findIndex,您必须确保 findIndex 低于 [sortedArray count]。如果该项目不存在并且您尝试使用 sortedArray[findIndex] 获取它,这将崩溃。
    【解决方案4】:

    我很惊讶没有人提到NSSet 的使用,它[当它包含具有良好散列的对象时,例如大多数 Foundation 数据类型时] 执行恒定时间查找。不要将对象添加到数组中,而是添加到集合中(或者如果您需要为其他目的保留排序顺序,则将它们添加到两者中[或者在 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).
    

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

    【讨论】:

    • 确实如此!这是一个非常优雅的解决方案。
    【解决方案5】:
    //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.
    }
    

    【讨论】:

      猜你喜欢
      • 2010-11-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-18
      • 2020-10-25
      • 2013-12-12
      • 2012-01-27
      • 1970-01-01
      • 2014-03-10
      相关资源
      最近更新 更多