Можете ли вы встраивать циклы (друг в друга) в C ++ - PullRequest
2 голосов
/ 20 апреля 2009

Я работаю над функцией сортировки слиянием. Я получил сортировку - я пытаюсь закончить свою часть слияния. Предположим, что я изучаю C ++, обладаю беглым знанием указателей и не понимаю всех правил std :: vector :: iterator (или std :: vector, в этом отношении).

Предположим, что num - это размер исходного std :: vector, который скопировал (std :: copy) значения из массива размером "int ar [num]." Предположим, что farray имеет значения от (0 до (num / 2)), а sarray имеет значения от ((num / 2) до num).

int num = original.size();
std::vector<int> final(num);

for (std::vector<int>::iterator it = farray.begin(); it != farray.end(); ++it) {
     for (std::vector<int>::iterator iter = sarray.begin(); iter != sarray.end(); ++iter) {
         if (*it > *iter) final.push_back(*it);
          else
               final.push_back(*iter);
     }
}

Этот код компилируется, и моя последняя стабильная сборка Bloodshed Dev-C ++ не выдает никаких предупреждений или ошибок. Я не знаю, если это действительно так, мне все еще нужно попытаться определить все значения final. Я просто хочу знать, распространено ли это, склонно к ошибкам или просто плохому стилю. И если да, то как бы вы

Ответы [ 6 ]

7 голосов
/ 20 апреля 2009

Это действительно ... но цикл for, вероятно, не то, что вы хотите. Когда вы используете два цикла for, ваш внутренний цикл продолжает возвращаться к началу каждый раз, когда внешний цикл повторяется. Так что, если ваши векторы содержат:

farray: 10 9 8 4 3
sarray: 7 6 4 3 1

Тогда ваш окончательный массив будет содержать что-то вроде:

10 10 10 10 10 9 9 9 9 9 8 8 8 8 8 7 6 4 4 4 7 6 4 3 3

потому что вы тестируете каждую комбинацию и добавляете большую в окончательный список. Лучшим решением может быть запоминание итератора для каждого списка и использование только одного цикла. Вместо того, чтобы зацикливаться на списке, просто просмотрите оба из них вместе - если sarray имеет большее число, то увеличьте свой итератор sarray и сравните его со старым итератором farray. Остановите ваш цикл, когда sarray и farray пусты.

vector<int> fiter = farray.begin();
vector<int> siter = sarray.begin();
vector<int> final;

// Let's traverse both farray and sarray.
// We'll want to stop this loop once we've traversed both lists.
while (fiter != farray.end() && siter != sarray.end())
{
    if (fiter == farray.end())
    {
        // we must have gone right through farray - 
        // so use the value from sarray, and go to the next one
        final.push_back(*siter);
        siter++;
    }
    else if (siter == sarray.end())
    {
        // we must have gone right through sarray - 
        // so use the value from farray, and go to the next one
        final.push_back(*fiter);
        fiter++;
    }
    else if (*siter > *fiter)
    {
        // siter is the bigger of the two - add it to the final list, and
        // go to the next sarray entry
        final.push_back(*siter);
        siter++;
    }
    else // *fiter >= *siter
    {
        // fiter is the bigger of the two - add it to the final list, and
        // go to the next farray entry
        final.push_back(*fiter);
        fiter++;
    }
}

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

2 голосов
/ 20 апреля 2009

Алгоритм сортировки слиянием в стороне, вложенный для цикла с итераторами так же действителен, как и вложенный для циклов с двумя переменными i и j .

1 голос
/ 20 апреля 2009

Вложение в циклы - абсолютно законный способ сделать что-то. Например, это классический способ «старой школы» для обхода двумерного массива - один цикл идет вниз по оси y, а другой цикл - по оси x.

В настоящее время, с этими детьми и их для каждого цикла, итератора и функции отображения, возможно, существует «лучший» способ сделать это (для некоторого определения лучше), но вложенные циклы работают просто отлично. Использование C ++ или указателей не меняет этого.

1 голос
/ 20 апреля 2009

Вы можете вкладывать циклы любого вида (для while, do while), если вы не используете переменные цикла повторно. Если вы попытаетесь это сделать, он скомпилируется, но может потерпеть неудачу во время выполнения. Хотя технически разрешено использовать одно и то же имя для переменных вложенного цикла в современных C и C ++, это сбивает с толку и его следует избегать.

Он не более или менее подвержен ошибкам, чем один цикл, за исключением уже упомянутой проблемы с повторным использованием переменных цикла.

Подробнее о ограничениях вложенных циклов.

0 голосов
/ 20 апреля 2009

Да, вы можете вкладывать циклы или другие операторы практически на любую глубину, которую хотите (в пределах разумного; существуют ограничения, как упомянуто в другом ответе, но они намного выше того, что вам когда-либо понадобится).

0 голосов
/ 20 апреля 2009

Да, вы можете сделать это. И да, он часто подвержен ошибкам. На самом деле, написание циклов само по себе подвержено ошибкам, что является одним из аргументов в пользу использования алгоритмов в STL, таких как for_each, copy и transform.

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