Как выполнить бинарный поиск в NSArray?
Каков самый простой способ выполнить двоичный поиск в (уже) отсортированном NSArray
?
Некоторые потенциальные способы, которые я заметил до сих пор, включают:
- Использование
CFArrayBSearchValues
(упоминается здесь) - будет ли это работать с NSArray
?
-
Метод indexOfObject:inSortedRange:options:usingComparator:
of NSArray
предполагает, что массив отсортирован и принимает параметр opts
типа NSBinarySearchingOptions
- означает ли это, что он выполняет двоичный поиск? docs просто скажут:
Возвращает индекс в пределах указанного диапазона объекта по сравнению с элементами в массиве с использованием данного блока NSComparator.
-
Напишите мой собственный метод двоичного поиска (что-то вроде this).
Я должен добавить, что я программирую для iOS 4.3 +
Спасибо заранее.
Ответы
Ответ 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
Ответ 3
CFArrayBSearchValues
должен работать NSArray *
бесплатный мост с CFArrayRef
.
Ответ 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.
}