Подтвердить что ты не робот

Как выполнить бинарный поиск в NSArray?

Каков самый простой способ выполнить двоичный поиск в (уже) отсортированном NSArray?

Некоторые потенциальные способы, которые я заметил до сих пор, включают:

  • Использование CFArrayBSearchValues (упоминается здесь) - будет ли это работать с NSArray?
  • Метод indexOfObject:inSortedRange:options:usingComparator: of NSArray предполагает, что массив отсортирован и принимает параметр opts типа NSBinarySearchingOptions - означает ли это, что он выполняет двоичный поиск? docs просто скажут:

    Возвращает индекс в пределах указанного диапазона объекта по сравнению с элементами в массиве с использованием данного блока NSComparator.

  • Напишите мой собственный метод двоичного поиска (что-то вроде this).

Я должен добавить, что я программирую для iOS 4.3 +

Спасибо заранее.

4b9b3361

Ответ 1

1 и 2 будут работать. # 2, вероятно, проще; для этого метода не имеет смысла делать ничего, кроме бинарного поиска (если диапазон превышает определенный размер, скажем). Вы можете проверить на большом массиве, что он делает только небольшое количество сравнений.

Ответ 2

Второй вариант, безусловно, самый простой. Ole Begemann имеет запись в блоге о том, как использовать метод NSArray indexOfObject: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

Ответ 4

Я удивлен, что никто не упомянул об использовании 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).

Важно знать, что вы потеряете любое преимущество в производительности, если вы конвертируете массив в набор каждый раз, когда выполняете поиск, в идеале вы будете использовать предварительно сконфигурированный набор, содержащий объекты, которые вы хотите проверить.

Ответ 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.
}