Подсчет инверсий в NSArray

Я новичок в Objective-C, поэтому я пытаюсь учиться, реализуя алгоритмы. Я выполняю поиск A* для решения задачи с 8 головоломками. Перед запуском самого алгоритма я хочу проверить, разрешима ли данная комбинация головоломок. Я уже писал этот код на C++ и Swift раньше, но у меня он не работает корректно в Objective-C. Для этого массива количество инверсий равно 7, хотя должно быть равно 0. Может быть, мне следует использовать метод [NSArray objectAtIndex:] для доступа к элементам, а затем преобразовать их в целые числа для сравнения? Я тестировал разные способы, и сравнение работает правильно. Пожалуйста, помогите мне найти ошибку.

    NSArray *test = @[@1, @2, @3, @4, @5, @6, @7, @0, @8];
    NSInteger inv_count = 0;

    for (NSInteger i = 0; i < 8; i++) {
        for (NSInteger j = i + 1; j < 9; j++) {
            if (test[j] && test[i] && test[i] > test[j]) {
                inv_count++;
            }
        }
    }

    NSLog(@"inv_count = %ld", (long)inv_count);

    if (inv_count % 2 == 0) {
        NSLog(@"Solvable.");
    } else {
        NSLog(@"Not solvable.");
    }

person denysowova    schedule 23.07.2017    source источник
comment
Условие будет ложным, когда мы получим доступ к элементу 0 с помощью test[j]. См. это: geeksforgeeks.org/check-instance-8-puzzle-solvable   -  person denysowova    schedule 23.07.2017
comment
@VolodymyrDenysov test[j] никогда не возвращает 0, потому что это указатель на экземпляр NSNumber   -  person ninjaproger    schedule 23.07.2017
comment
Да, я думаю, если бы этот алгоритм был написан на другом языке. Этот комментатор неправильно понял алгоритм.   -  person denysowova    schedule 23.07.2017


Ответы (1)


В основном эта строка кода неверна:

if(test[j] && test[i] && test[i]>test[j])

test представляет собой массив из NSNumber экземпляров или в основном содержит указатели. Итак, чтобы проверить, равен ли элемент этого массива нулю или сравнить его, вы должны получить целочисленное значение элемента:

if(((NSNumber*)test[j]).integerValue && ((NSNumber*)test[i]).integerValue && ((NSNumber*)test[i]).integerValue > ((NSNumber*)test[j]).integerValue)

В качестве альтернативы вы можете использовать - (NSComparisonResult)compare:(NSNumber *)aNumber метод NSNumber

PS: пожалуйста, проверьте это для получения дополнительной информации .

person ninjaproger    schedule 23.07.2017
comment
Спасибо! Это сработало! Но почему это работает: if(test[3]›test[1]) NSLog(@works) - person denysowova; 23.07.2017
comment
Я думал, что когда я использую нотацию нижнего индекса, он вызывает метод [objectAtIndex:], который возвращает идентификатор типа, верно? Поэтому мне нужна конвертация в NSNumber? - person denysowova; 23.07.2017
comment
@VolodymyrDenysov, потому что id является указателем на любой тип;) if(test[3]›test[1]) NSLog(@works) может работать, если указатель test[3] расположен по старшему адресу в памяти устройства - person ninjaproger; 23.07.2017
comment
@VolodymyrDenysov - Re: test[3]>test[1]. Это сравнивает указатели, что является законным, хотя в Objective-C вы бы редко делали это (в C вы могли бы это сделать). Однако вы могли заметить, что он похоже работает, упорядочив некоторые NSNumber объекты по их значению. Это случайность реализации, и если вам интересно, посмотрите помеченные указатели. - person CRD; 23.07.2017
comment
Ага, я тоже об этом подумал! Большое спасибо! И еще один вопрос, могу ли я преобразовать прямо в NSInteger, например: (NSInteger)test[index] и сравнить? Или я должен сначала преобразовать в NSNumber? - person denysowova; 23.07.2017
comment
@CRD спасибо за ссылку, обязательно проверю! - person denysowova; 23.07.2017
comment
Выражение ((NSNumber*)test[j]).integerValue является приведением, а не преобразованием, оно сообщает компилятору, что test[j] типа id, означающее ссылку на любой объект, на самом деле ссылка на NSNumber. Здесь используется приведение, чтобы компилятор мог обработать ссылку на свойство .integerValue. Вы не можете просто указать NSNumber ссылку на NSInteger, чтобы получить значение, такое приведение вернет целочисленный эквивалент значения ссылки и не вызовет integerValue. - person CRD; 23.07.2017