Невозможно перебрать все строки в 2D-массиве при двоичном поиске по строкам

Почему мой цикл for не выполняет итерацию по строкам в 2D-массиве?

#include <iostream>
using namespace std;

//row-wise binary search.

int search2DArray(int matrix[][4], int n, int m, int key){
int start = 0, end = m-1;

    for(int i=0; i<n; i++){
    
        while(start<=end){
            int mid = (start+end)/2;
    
            if (matrix[i][mid] == key){
                cout<<"FOUND\n";
                return 0;
            }else if (matrix[i][mid] < key){ 
                start = mid + 1;
            }else{
                end = mid - 1;
            }   
        }
    
    }
    cout<<"NOT FOUND\n";
    return -1;

}

int main(){

    int matrix[4][4] = {{10,20,30,40},
                        {15,25,35,45},
                        {27,29,37,48},
                        {32,33,39,50}};
    
    search2DArray(matrix, 4, 4, 29);
    
    return 0;

}

Я пытался применить цикл for для перебора всех строк 2D-массива, но не смог пройти первую строку и всегда печатал NOT FOUND для любого ввода для строки > 0.

Обратите внимание, что это C++, передача массива как int matrix[4] не рекомендуется, вы теряете информацию о размере, используя const std::array<std::array<int,4>,4>& matrix или лучше инкапсулирует данные в матричный класс.

Pepijn Kramer 01.08.2024 04:48
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Когда вы заканчиваете строку, вы не сбрасываете start и end, поэтому следующая строка начинается с start и end в состоянии выхода и сразу же выходит.

int search2DArray(int matrix[][4], int n, int m, int key){
//    int start = 0, end = m-1; <<-- move this line 

    for(int i=0; i<n; i++){
        int start = 0, end = m-1; // <<-- to here
        while(start<=end){
            int mid = (start+end)/2;

            if (matrix[i][mid] == key){
                cout<<"FOUND\n";
                return 0;
            }else if (matrix[i][mid] < key){
                start = mid + 1;
            }else{
                end = mid - 1;
            }
        }

    }
    cout<<"NOT FOUND\n";
    return -1;

}

Мы можем улучшить эту функцию с помощью старой доброй магии шаблонов C++:

template<size_t N, size_t M> // template deduction eliminates need for 
                             // m and n as parameters and arguments.
                             // code you don't have to write has no bugs.  
int search2DArray(int (&matrix)[N][M], int key)
{

    for (const auto & row : matrix) //range-based for loop allows easy 
                                    // processing of each row as a row
    {
        size_t start = 0; // split into two lines to make it harder to screw up.
        size_t end = M - 1; // using size_t because it can handle any array you 
                            // can give it.

        while (start <= end) // rest is pretty much the same
        {
            size_t mid = (start + end) / 2;

            if (row[mid] == key) // since we operate on rows we no longer 
                                 // care about the outer dimension
            {
                cout << "FOUND\n";
                return 0;
            }
            else if (row[mid] < key)
            {
                start = mid + 1;
            }
            else
            {
                end = mid - 1;
            }
        }

    }
    cout << "NOT FOUND\n";
    return -1;

}

Эта версия будет называться примерно так:

int matrix[][4] = // compiler figures out the outer dimension
{                 // I don't have a good way to infer the inner dimension 
                  // without getting weirder than this problem requires.
    { 10, 20, 30, 40 },
    { 15, 25, 35, 45 },
    { 27, 29, 37, 48 },
    { 32, 33, 39, 50 } 
};

search2DArray(matrix, 29); // compiler figures out the template arguments 
                           // from the array

Примечание: многие распространенные проблемы с программным обеспечением уже решены в стандартной библиотеке C++. Использование std::binary_search и обобщение контейнера на итераторы с помощью std::begin и std::end позволяет сократить тело функции до

for (const auto & row : matrix) 
{
    if (std::binary_search(std::cbegin(row), 
                           std::cend(row), 
                           key))
    {
        std::cout << "FOUND\n";
        return 0;
    }
}
std::cout << "NOT FOUND\n";
return -1;

и использовать его для массивов и любого библиотечного контейнера (хотя для большинства контейнеров это не имеет смысла. Зачем двоичный поиск map?).

Я близок к +1, но мне бы хотелось более «версию на C++». Было бы неплохо использовать цикл for на основе диапазона.

Ted Lyngmo 01.08.2024 00:14

@Ted Для захвата массива для получения цикла на основе диапазона потребовалось углубиться в шаблоны или заменить массив на std::array. Оба варианта, вероятно, заслуживают примечания, но достаточно значительно отклоняться от заданного вопроса. Немного удивляет, если сдавать в качестве домашнего задания. Посмотрим, насколько похожим я смогу его сохранить.

user4581301 01.08.2024 00:45
using matrix_t = std::array<std::array<int,4>,4> НЕ используйте стиль «C» для 2D-массивов.
Pepijn Kramer 01.08.2024 04:49

В таких случаях я ценю простую глупость старого доброго массива.

user4581301 01.08.2024 04:54

Мы также могли бы использовать template<size_t N> using Vector = int[N];template<size_t M, size_t N> using Matrix = Vector<N>[M];template<size_t M, size_t N> int search2DArray(Matrix<M, N> &matrix, int key);, чтобы сохранить семантику матрицы в математическом виде и сделать ее более читабельной.

Jakkapong Rattananen 01.08.2024 09:40

«Немного удивление, если сдать домашнее задание» - :-) +1

Ted Lyngmo 01.08.2024 11:33

Другие вопросы по теме