Простые примеры использования циклов while - PullRequest
0 голосов
/ 08 сентября 2018

Я пытаюсь написать несколько примеров, объясняющих, когда следует использовать цикл while и когда следует использовать цикл for.

Когда я искал «интересные» примеры для молодых и начинающих программистов, я понял, что подавляющее большинство примеров учебников для циклов while будет выглядеть примерно так:

i = 0
while i < 10:
    do something
    i = i + 1

«сделать что-то» может быть печать нечетных чисел, возведение в квадрат i и т. Д. Однако все это, очевидно, легче записать с помощью цикла for!

Я ищу более интересные примеры. Они должны быть:

  1. Подходит для младших программистов (например, не слишком много математики, такой как числовой поиск корней или последовательность в гипотезе Коллатца)
  2. Проще (или более интуитивно понятно) решаться с помощью циклов while, а не для.
  3. Имей к этому какое-то реальное применение (например, я мог бы сделать while random() < 0.95, но какой реальный смысл в этом?)

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

1 Ответ

0 голосов
/ 08 сентября 2018

Принципиальная разница между циклом FOR и циклом WHILE заключается в том, что для цикла FOR число итераций ограничено константой, известной до запуска цикла, тогда как для WHILE цикл, число итераций может быть неограниченным, неизвестным или бесконечным.

В результате язык, предлагающий только циклы WHILE, является Turing-complete, а язык, предлагающий только циклы FOR, - нет.

Итак, первая очевидная вещь, которую может сделать только цикл WHILE, - это бесконечный цикл. Вещи, которые легко моделируются как бесконечные циклы, это, например, веб-сервер, клиент Netflix, игровой цикл, цикл событий GUI или операционная система:

WHILE (r = nextHttpRequest):
    handle(r)
END

WHILE (p = nextVideoStreamPacket):
    frame = decode(p)
    draw(frame)
END

WHILE (a = playerAction):
    computeNextFrame(a)
END

WHILE (e = nextEvent):
    handle(e)
END

WHILE (s = sysCall):
    process(s)
END

Хороший пример, где цикл не бесконечен, но граница не известна заранее, - это (как вы уже упоминали в своем вопросе) запрос пользовательского ввода. Примерно так:

WHILE (askBoolean("Do you want to play again?")):
    playGame()
END

Другим хорошим примером является обработка строки, подобной C, где длина строки неизвестна, но конечна. Это та же самая ситуация для связанного списка или для любой структуры данных, где есть понятие «следующий», но не понятие «размер», вместо этого есть некоторое значение часового, которое отмечает конец (например, NUL -определенные строки в C) или способ проверить, есть ли следующий элемент (например, Iterator в Java):

WHILE ((element = getNext()) != END_MARKER):
    process(element)
END

WHILE (hasNextElement):
    process(getNext())
END

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

К сожалению, я не могу придумать хороший реальный пример этого, может быть, кто-то другой может. Цикл FOR для этого обычно будет выглядеть следующим образом, чтобы пропустить итерации от фактического числа итераций до верхней границы:

FOR (i FROM 1 TO $SOME_LARGE_UPPER_BOUND):
    IF (terminationConditionReached):
        NOOP()
    ELSE:
        doSomethingInteresting()
    END
END

Что было бы гораздо лучше выразить как

WHILE (NOT terminationConditionReached):
    doSomethingInteresting()
END

Использование FOR цикла может иметь смысл в этой ситуации, если значение i представляет интерес:

FOR (i FROM 1 TO $SOME_LARGE_UPPER_BOUND):
    IF (terminationConditionReached):
        NOOP()
    ELSE:
        doSomethingInterestingWithI(i)
    END
END

Последняя ситуация, о которой я могу подумать, когда цикл WHILE более уместен, чем цикл FOR, даже если число итераций ограничено известной константой, если эта константа не "семантически интересна" для петли.

Например, игровой цикл для крестики-нолики требует не более 9 ходов, поэтому его можно смоделировать как цикл FOR:

FOR (i FROM 1 TO 9):
    IF (player1Won OR player2Won):
        NOOP
    ELSE:
        makeMove()
    END
END

Но число "9" здесь не очень интересно. Гораздо интереснее, есть ли у одного игрока или доска заполнена:

WHILE (NOT (player1Won OR player2Won OR boardFull)):
    makeMove()
END

[Примечание: по крайней мере, если вы играете против ребенка, это также является примером второй до последней ситуации, а именно, что известно, что верхняя граница равна 9, но многие игры будут короче 9 ходов , Однако я все еще хотел бы найти пример для этого, который не является также примером семантически неинтересного условия завершения.]

Итак, у нас есть два класса ситуаций: один, где цикл FOR просто не может быть использован (когда граница неизвестна, не существует или бесконечна), и один, где цикл FOR может использоваться, но цикл WHILE является более раскрывающим намерение .

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