Хороший ли тон сравнивать с изменяющимися значениями в цикле на C++?

StackOverflow https://stackoverflow.com/questions/767099

Вопрос

Без сомнения, некоторые из вас видели мои недавние публикации, посвященные одной и той же программе.Я постоянно сталкиваюсь с проблемами с этим.Повторить:все еще учусь, не очень продвинут, не очень хорошо понимаю указатели, не посещаю курсы, вообще не понимаю концепций ООП и т. д.Этот код просто объединяет два отсортированных вектора, Farray и sarray, в один отсортированный вектор.По крайней мере, я надеюсь, что именно это и происходит.Скажи мне:

    //int num is to find the size of the original vector and
    //build up farray and sarray; not used in the merge process
    int num = original.size() 
    std::vector<int> final;

    std::vector<int>::iterator it = farray.begin();
    std::vector<int>::iterator iter = sarray.begin();

    //farray.size() == (0 thru (num / 2))
    //sarray.size() == ((num / 2) thru num)
    for (;it != farray.end() && iter != sarray.end();) {
        if (*it > *iter) {
            final.push_back(*it);
            it++;
        }    
        else
        {
            final.push_back(*iter);
            iter++;
        }

            if (it == farray.end()) {
                for (int i = 0; iter < sarray.end(); i++) {
                    final.push_back(*iter);
                }
            }

            if (iter == sarray.end()) {
                for (int i = 0; it < farray.end(); i++) {
                    final.push_back(*iter);
                }
            }
        }

Я переписал часть слияния моей функции сортировки слиянием, чтобы... ну, заставить ее работать.На самом деле у меня есть несколько вопросов по поводу этого кода:

  1. Будет ли хорошим тоном сравнивать std::vector::iterators с && iter для моих последних двух операторов if, если цикл for может изменить их на следующем проходе?
  2. Изменятся ли значения iter и it на последнем проходе этого цикла и испортят ли мой код?Будет ли мое последнее утверждение if перед сравнением *it и *it?
  3. Ссылается ли функция-член end() на последнее значение того, что ее вызывает?Кажется, что это может каким-то образом выйти за рамки этого.

РЕДАКТИРОВАТЬ:Я отвечу на все ответы завтра, так что заходите позже, если хотите узнать больше.Уже за полночь.Спокойной ночи.

Это было полезно?

Решение

1 .Сравнивать итераторы, которые находятся в том же контейнере, что и условие цикла for, можно, но это имеет смысл только в том случае, если вы перемещаете тот или иной итератор либо в часть приращения оператора цикла for, либо в тело самого цикла for.В этом цикле for вы сравниваете iter против sarray.end() но цикл for никогда не меняется iter.Это означает, что либо итераций не будет, либо цикл for никогда не завершится.Кроме того, вы, вероятно, захотите использовать != и не < для сравнения. == и != работать для всех итераторов, < нет.

            for (int i = 0; iter != sarray.end(); i++) {
                final.push_back(*iter);
            }

Как iter начинается там, где вы хотите, чтобы цикл начинался, вы можете захотеть что-то вроде этого:

            for (; iter != sarray.end(); ++iter) {
                final.push_back(*iter);
            }

Поскольку вы все еще учитесь (хотя не все мы!), вероятно, будет поучительно работать с таким алгоритмом, но вы должны знать о std::merge который, вероятно, делает то, что вы хотите.

std::merge( farray.begin(), farray.end(), sarray.begin(), sarray.end(), std::back_inserter( final ) );

(Вам нужно #include <iterator> и <algorithm>.)

2 .Я не вижу, чтобы приращение iter или it во внешнем цикле for делало недействительной логику в последующих циклах for, точку в 1.в стороне.

3 . end() указывает на один из концов контейнера, поэтому вы можете использовать его для проверки завершения цикла, но вам не следует пытаться разыменовать итератор, который "==" к ".end()".

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

Я не проверял реализацию вашего алгоритма, я просто сошлюсь на ваши три вопроса:

  1. Итераторы во многом похожи на указатели на значения контейнера.Это точно так же, как использование size_t i, а затем ++i в цикле for.считаете ли вы, что сравнивать Farray[i] с sarray[i] проблематично?вероятно, нет, поэтому все в порядке.
  2. Я вижу, что вы делаете здесь в своем коде то, что вы просто читаете значения *it и *iter, на самом деле вы их не меняете, поэтому они не изменятся.
  3. Конец() указывает на недопустимое место.Он указывает не на последнее значение, а на «после него».Если хотите, это похоже на «NULL», поэтому, если (iter == sarray.end()) истинно, вы потерпите крах, если напишите *iter, потому что вы не можете разыменовать итератор, равный end().

Несколько общих советов:Вам нужно подумать об именах переменных.Называя ваши итераторы «it» и «iter», вы в какой-то момент запутаетесь.На самом деле, если присмотреться, оно уже есть.Если «фаррей» и «саррай» — осмысленные имена, то как насчет «фитер» и «ситер»?

Также подумайте, что делает сортировка слиянием.Эти последние два блока нужны только для того, чтобы «осушить» тот итератор, у которого еще что-то осталось.Поэтому им не обязательно находиться в первом цикле.

Я бы, наверное, написал это как (псевдокод):

while not (list1.empty and list2.empty):
    if list1.empty:
        result.push(list2.pop)
    else if list2.empty:
        result.push(list1.pop)
    else if list1.top > list2.top:
        result.push(list2.pop)
    else:
        result.push(list1.pop)

Или в несколько заржавевшем C++, культивирующем грузы:

std::vector<int>::iterator fiter = farray.begin();
std::vector<int>::iterator siter = sarray.begin();

while (fiter != farray.end() || siter != sarray.end()) {
    if (fiter == farray.end())      final.push_back(*siter++);
    else if (siter == sarray.end()) final.push_back(*fiter++);
    else if (*fiter > *siter)       final.push_back(*siter++);
    else                            final.push_back(*siter++);
}

Здесь вам есть над чем подумать.

Во-первых, если вы объединяете два диапазона, вам будет гораздо лучше использовать станд::слияние функция, а не катание самостоятельно.

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

Первая часть вашего цикла for кажется правильной реализацией слияния:

for (;it != farray.end() && iter != sarray.end();) {
    if (*it > *iter) {
        final.push_back(*it);
        it++;
    }    
    else
    {
        final.push_back(*iter);
        iter++;
    }

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

Вторая часть вашего цикла имеет пару проблем:

   for (;it != farray.end() && iter != sarray.end();) {
         :   :
            if (it == farray.end()) {
                for (int i = 0; iter < sarray.end(); i++) {
                    final.push_back(*iter);
                }
            }

            if (iter == sarray.end()) {
                for (int i = 0; it < farray.end(); i++) {
                    final.push_back(*iter);
                }
            }
        }

Во-первых, условия for() написаны так, что оба it и iter не должен указывать на end() соответствующей коллекции, иначе цикл завершится.Так it никогда не смогу указать на sarray.end(), iter никогда не смогу указать на farray.end(), и ни один if заявление может когда-либо сработать.Оба они являются мертвым (недостижимым) кодом.

Но даже если это не мертвый код, в них есть ошибки.Условное в. for(...) разрывает цикл, когда итератор указывает на конец коллекции, но этот итератор никогда не перемещается, поэтому получается бесконечный цикл.

Опять и то и другое for(...)s — ненужный мертвый код, поскольку итераторы никогда не могут указывать на конец вектора.

Один простой комментарий:почему бы не использовать while (condition) вместо for(; !condition; ).

Последняя конструкция нестандартна и сложна для понимания!

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top