Цель C isEqual не оценивается при сравнении int и id - PullRequest
0 голосов
/ 10 октября 2018

Я пытаюсь реализовать бинарный поиск в Objective C. Я в основном борюсь с этой строкой кода if ([searchItem isEqual:midElement]){, потому что она оценивается как истина, когда значения различаются searchItem = 1 и midElement = 4:

@implementation NSArray (BinarySearch)

- (NSInteger) binarySearch : (id) searchItem {
    NSLog(@"SearchItem: %@", searchItem);
    return [self binarySearch:searchItem min:0 max:[self count] - 1];
}

- (NSInteger) binarySearch:(id)searchItem min:(NSInteger)min max:(NSInteger)max {
    if (max < min) {
        return NSNotFound;
    }

    NSInteger mid = (max + min) / 2;
    id midElement = [self objectAtIndex:mid];
    NSLog(@"Search Item: %d, Current Value: %@, Min: %d, Mid: %d, Max: %d", searchItem, midElement, min, mid ,max);

    NSLog(@"IsEqual: %d", [searchItem isEqual:midElement]);


    if ([searchItem isEqual:midElement]){
        return mid;
    }
    else if (searchItem < midElement){
        return [self binarySearch:searchItem min:min max:mid];
    }
    else{
        return [self binarySearch:searchItem min:mid max:max];
    }
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSArray *orderedList = @[@1, @2, @4, @7, @8, @10];
        NSLog(@"Binary search on a list: %d", [orderedList binarySearch: 1]);
    }
    return 0;
}

Вывод кода:

SearchItem:
Search Item: 1, Current Value: 4, Min: 0, Mid: 2, Max: 5
IsEqual: 1
Binary search on a list: 2
Program ended with exit code: 0 

Правка для Genecode, когда я изменил его на это:

NSInteger mid = (max + min) / 2;
int midElement = [self objectAtIndex:mid];
NSLog(@"Search Item: %d, Current Value: %@, Min: %d, Mid: %d, Max: %d", searchItem, midElement, min, mid ,max);

NSLog(@"IsEqual: %d", searchItem == midElement);


if (searchItem == midElement){
    return mid;
}

searchItem == midElement оценивается в ноль, несмотря ни на что.Вывод кода:

SearchItem:
Search Item: 1, Current Value: 4, Min: 0, Mid: 2, Max: 5
IsEqual: 0
Search Item: 1, Current Value: 2, Min: 0, Mid: 1, Max: 2
IsEqual: 0
Search Item: 1, Current Value: 1, Min: 0, Mid: 0, Max: 1
IsEqual: 0
Binary search on a list: -1

Ответы [ 3 ]

0 голосов
/ 10 октября 2018

Вы передаете скалярное целое число 1 в -binarySearch:, которое обрабатывает его как указатель объекта id.Вам нужно передать @1 или другой NSNumber* (по крайней мере, указатель объекта).

Кроме того, поскольку searchItem является указателем объекта, вы должны регистрировать его с %@, а не %d(как предупреждение пытался сказать вам).Единственная причина, по которой %d не произошел сбой - это другая ошибка.Эти две ошибки уничтожили друг друга.

Вы должны не использовать <, чтобы сравнить два объекта по значению.Это сравнивает их адреса, что вообще бессмысленно.Вы должны использовать -compare: вместо -isEqual: или <.

0 голосов
/ 10 октября 2018

Ваша проблема проистекает из того, что @1 на самом деле является в Objective-C.Это не NSInteger.Это буквальное сокращение от [NSNumber numberWithInt:1].т.е. он создает объект.

Затем вы пытаетесь сравнить NSInteger со ссылкой на объект, и, что неудивительно, он не работает.

Фактически эта строка:

NSLog(@"Binary search on a list: %d", [orderedList binarySearch: 1]);

Должно выдавать ошибку и предупреждение, указывающее на проблему:

Запрещено неявное преобразование 'int' в 'id' в ARC Несовместимое преобразование целочисленного значения в указатель, отправляющее 'int' в параметр типа 'id '

Признавая, что вы на самом деле имеете дело с объектами, и используя метод compare, вы получаете:

@implementation NSArray (BinarySearch)

- (NSInteger) binarySearch : (id) searchItem {
    NSLog(@"SearchItem: %@", searchItem);
    return [self binarySearch:searchItem min:0 max:[self count] - 1];
}

- (NSInteger) binarySearch:(id)searchItem min:(NSInteger)min max:(NSInteger)max {


    if (max-min < 2) {
        return NSNotFound;
    }

    NSInteger mid = (max + min) / 2;

    NSNumber *midElement = [self objectAtIndex:mid];
    NSLog(@"Search Item: %@, Current Value: %@, Min: %ld, Mid: %ld, Max: %ld", searchItem, midElement, min, mid ,max);

    NSComparisonResult result = [midElement compare:searchItem];

    switch (result) {
        case NSOrderedSame:
            return mid;
            break;

        case NSOrderedAscending:
            return [self binarySearch:searchItem min:mid max:max];
            break;

        case NSOrderedDescending:
            return [self binarySearch:searchItem min:min max:mid];
            break;
    }

}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSArray *orderedList = @[@1, @2, @4, @7, @8, @10];
            NSLog(@"Binary search on a list: %ld", [orderedList binarySearch: @7]);
    }
    return 0;
}

Это дает вывод

SearchItem: 7

Поиск элемента: 7, Текущее значение: 4, Мин .: 0, Середина: 2, Макс: 5

Поиск элемента: 7, Текущее значение: 7, Мин .:2, Mid: 3, Max: 5

Двоичный поиск по списку: 3

Программа завершилась с кодом выхода: 0

У вас также была проблема сваше условие завершения, которое приведет к бесконечной рекурсии, если элемент не найден.

0 голосов
/ 10 октября 2018

Как isEqual: Реализовано, ваш оператор <вряд ли даст вам то, что вы хотите, вы пытаетесь сравнить с объектами, target-c не поддерживает перегрузку операторов, если вы хотите реализовать свой собственный двоичный файлsearch, посмотрите на реализацию метода compare:, который может возвращать значение, указывающее, как два объекта должны быть упорядочены, таким образом, у вас есть только один вызов метода вместо двух, что более эффективно.Более того, NSArray имеет метод indexOfObject: inSortedRange: options: usingComparator:, который может быть передан для выполнения двоичного поиска. </p>

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...