Мой лектор упомянул сегодня, что в Java можно «пометить» циклы, чтобы вы могли обращаться к ним при работе с вложенными циклами. Поэтому я посмотрел эту функцию, так как не знал об этом, и во многих местах, где эта функция была объяснена, за ней последовало предупреждение, препятствующее вложенным циклам.
Я не очень понимаю, почему? Это потому, что это влияет на читабельность кода? Или это что-то более "техническое"?
java
readability
loops
DSF
источник
источник
Ответы:
Вложенные циклы хороши, если они описывают правильный алгоритм.
Вложенные циклы имеют соображения производительности (см. Ответ @ Travis-Pesetto), но иногда это совершенно правильный алгоритм, например, когда вам нужно получить доступ к каждому значению в матрице.
Маркировка циклов в Java позволяет преждевременно разорвать несколько вложенных циклов, когда другие способы сделать это будут громоздкими. Например, некоторые игры могут иметь такой код:
Хотя код, подобный приведенному выше, иногда может быть оптимальным способом выражения определенного алгоритма, обычно лучше разбить этот код на более мелкие функции и, вероятно, использовать
return
вместо негоbreak
. Так чтоbreak
с этикеткой - слабый кодовый запах ; обратите особое внимание, когда вы видите это.источник
Вложенные циклы часто (но не всегда) являются плохой практикой, потому что они часто (но не всегда) излишни для того, что вы пытаетесь сделать. Во многих случаях есть гораздо более быстрый и менее расточительный способ достижения цели, которую вы пытаетесь достичь.
Например, если у вас есть 100 элементов в списке A и 100 элементов в списке B, и вы знаете, что для каждого элемента в списке A есть один элемент в списке B, который соответствует ему (с определением «match», оставлено намеренно неясным здесь), и вы хотите создать список пар, простой способ сделать это так:
Если в каждом списке 100 элементов, это займет в среднем 100 * 100/2 (5000)
matches
операций. С большим количеством элементов или если соотношение 1: 1 не гарантировано, оно становится еще дороже.С другой стороны, есть гораздо более быстрый способ выполнить такую операцию:
Если вы делаете это таким образом, то вместо того,
matches
чтобы основывать количество операцийlength(A) * length(B)
, теперь оно основаноlength(A) + length(B)
, что означает, что ваш код будет работать намного быстрее.источник
O(n log n)
дважды, если используется быстрая сортировка.O(n^2)
для немигающих значений N.<
оператор, который, как правило, не может быть получен изmatches
оператора. Во-вторых, даже если X и Y являются числовыми, 2-й алгоритм все равно может давать неправильные результаты, например, когдаX matches Y
естьX + Y == 100
.Одна из причин избегать вложенных циклов - плохая идея слишком глубоко вкладывать блочные структуры, независимо от того, циклы они или нет.
Каждая функция или метод должны быть простыми для понимания, как для своей цели (имя должно выражать то, что они делают), так и для сопровождающих (должно быть легко понять внутреннее устройство). Если функция слишком сложна, чтобы ее было легко понять, это обычно означает, что некоторые внутренние компоненты должны быть разделены на отдельные функции, чтобы их можно было ссылаться в (теперь меньшей) главной функции по имени.
Вложенные циклы могут быть довольно трудно понять относительно быстро, хотя некоторые вложения циклов хороши - обеспечивая, как указывают другие, это не означает, что вы создаете проблему производительности, используя чрезвычайно (и излишне) медленный алгоритм.
На самом деле, вам не нужны вложенные циклы, чтобы получить абсурдно медленные ограничения производительности. Рассмотрим, например, один цикл, который на каждой итерации берет один элемент из очереди, а затем, возможно, возвращает несколько назад - например, поиск лабиринта в ширину. Производительность определяется не глубиной вложенности цикла (которая составляет всего 1), а количеством элементов, которые помещаются в эту очередь до того, как она в конце концов исчерпана ( если она когда-либо исчерпана) - насколько велика достижимая часть лабиринт есть.
источник
Учитывая случай многих вложенных циклов, вы получите полиномиальное время. Например, учитывая этот псевдокод:
Это будет считаться O (n ^ 2) время, которое будет график, похожий на:
Где ось Y - это количество времени, которое требуется вашей программе для завершения, а ось X - количество данных.
Если вы получите слишком много данных, ваша программа будет работать слишком медленно, никто не будет ждать ее. и это не так много, около 1000 записей данных, я думаю, это займет слишком много времени.
источник
Вождение 30-тонного грузовика вместо небольшого легкового автомобиля - плохая практика. За исключением случаев, когда вам нужно перевезти 20 или 30 тонн груза.
Когда вы используете вложенный цикл, это неплохая практика. Это либо совершенно глупо, либо именно то, что нужно. Вам решать.
Однако кто-то жаловался на маркировку петель. Ответ на этот вопрос: если вам нужно задать вопрос, не используйте маркировку. Если вы знаете достаточно, чтобы решить сами, то вы решаете сами.
источник
В вложенных циклах нет ничего плохого или обязательно плохого. Однако у них есть определенные соображения и подводные камни.
Статьи, к которым вас привели, вероятно, во имя краткости или из-за психологического процесса, известного как сгорание, пропускающего специфику.
Быть сожженным - это когда вы испытываете негативный опыт чего-либо с вовлеченным существом, тогда вы избегаете этого. Например, я могу резать овощи острым ножом и резать себя. Я мог бы тогда сказать, что острые ножи плохи, не используйте их для нарезки овощей, чтобы попытаться сделать так, чтобы этот плохой опыт не повторился. Это, очевидно, очень непрактично. На самом деле вам просто нужно быть осторожным. Если вы говорите кому-то еще, чтобы нарезать овощи, то у вас это ощущается еще сильнее. Если бы я велел детям нарезать овощи, я бы очень чувствовал, что им не следует пользоваться острым ножом, особенно если я не могу пристально следить за ними.
Проблема в программировании состоит в том, что вы не достигнете пиковой эффективности, если будете всегда отдавать предпочтение безопасности. В этом случае дети могут резать только мягкие овощи. Столкнувшись с чем-то еще, и они только испортят это, используя тупой нож. Важно изучить правильное использование циклов, включая вложенные, и вы не сможете этого сделать, если они считаются плохими и вы никогда не пытаетесь их использовать.
Как многие ответы здесь указывают на то, что вложенный цикл for является показателем характеристик производительности вашей программы, которые могут экспоненциально ухудшаться с каждым вложением. То есть O (n), O (n ^ 2), O (n ^ 3) и т. Д., Которые содержат O (n ^ глубина), где глубина представляет, сколько циклов вы вложили. По мере роста вашего вложения необходимое время растет в геометрической прогрессии. Проблема в том, что это не уверенность в том, что ваша временная или пространственная сложность такова, что (довольно часто a * b * c, но не все гнездовые циклы могут выполняться все время), и это не уверенность, что вы будете есть проблемы с производительностью, даже если это так.
Для многих людей, особенно студентов, писателей и лекторов, которые, если честно, редко программируют на жизнь или на повседневной основе для петель, могут также быть тем, к чему они не привыкли, и это вызывало слишком большую когнитивную нагрузку на ранних встречах. Это проблемный аспект, потому что всегда есть кривая обучения, и избегание ее не будет эффективным в превращении студентов в программистов.
Вложенные циклы могут разрастаться, то есть они могут оказаться вложенными очень глубоко. Если я пройду через каждый континент, затем через каждую страну, затем через каждый город, затем через каждый магазин, затем через каждую полку, затем через каждый продукт, если это будет банка бобов через каждый боб, и измерить его размер, чтобы получить среднее значение, затем вы Я вижу, что это будет очень глубоко. У вас будет пирамида и много пустого пространства подальше от левого края. Вы можете даже уйти со страницы.
Это проблема, которая исторически была бы более существенной, если бы экраны были маленькими и с низким разрешением. В этих случаях даже несколько уровней вложенности могут действительно занимать много места. Сегодня это менее важно, когда порог выше, хотя он все еще может представлять проблему, если достаточно вложенности.
С этим связан эстетический аргумент. Многие люди не находят вложенные петли эстетически приятными в отличие от макетов с более последовательным выравниванием, это может или не может быть связано с тем, к чему привыкли люди, отслеживанием глаз и другими проблемами. Однако это проблематично тем, что он имеет тенденцию быть самоусиливающимся и в конечном итоге может усложнить чтение кода, поскольку разбивает блок кода и инкапсулирует циклы за абстракциями, такими как функции, также рискует нарушить отображение кода в потоке выполнения.
Существует естественная тенденция к тому, что люди привыкли. Если вы программируете что-то самым простым способом, вероятность того, что вам не понадобится вложение, является самой высокой, вероятность того, что вам нужен один уровень, уменьшается на порядок, а вероятность другого уровня снова падает. Частота падает и, по сути, означает, что чем глубже вложение, тем менее обученные человеческие чувства должны его предвидеть.
С этим связано то, что в любой сложной конструкции, которую можно рассматривать как вложенный цикл, всегда следует спрашивать, является ли самое простое из возможных решений, поскольку существует вероятность пропущенного решения, требующего меньшего количества циклов. Ирония заключается в том, что вложенное решение часто является самым простым способом создания чего-то, что работает с минимальными затратами усилий, сложности и когнитивной нагрузки. Часто бывает естественным гнездо для петель. Если вы рассмотрите, например, один из ответов выше, где гораздо более быстрый способ, чем вложенный цикл for, также гораздо сложнее и состоит из значительно большего количества кода.
Необходима большая осторожность, поскольку часто можно абстрагировать петли или сгладить их, но конечный результат, в конечном итоге, излечит хуже, чем болезнь, особенно если вы, например, не получаете измеримых и значительных улучшений производительности от усилий.
Люди часто испытывают проблемы с производительностью в связи с циклами, которые говорят компьютеру многократно повторять действие и по своей природе часто будут связаны с узкими местами производительности. К сожалению, ответы на это могут быть очень поверхностными. Люди часто видят цикл и видят проблему с производительностью там, где ее нет, а затем скрывают цикл от глаз к реальному результату. Код «выглядит» быстро, но поставьте его на дорогу, включите зажигание, включите акселератор и посмотрите на спидометр, и вы, возможно, обнаружите, что он все еще примерно такой же быстрый, как старуха, идущая по своей оправе.
Этот вид сокрытия похож на то, если на вашем маршруте десять грабителей. Если вместо того, чтобы идти прямым путем туда, куда вы хотите пойти, вы устроите его так, чтобы за каждым углом находился грабитель, тогда, когда вы начинаете путешествие, создается иллюзия, что грабителей нет. С глаз долой, из сердца вон. тебя все равно будут ограбить десять раз, но теперь ты не увидишь, что это произойдет.
Ответ на ваш вопрос заключается в том, что это и то и другое, но ни одна из проблем не является абсолютной. Они либо полностью субъективны, либо только контекстуально объективны. К сожалению, иногда полностью субъективное или, вернее, мнение занимает прецедент и доминирует.
Как правило, если для этого требуется вложенный цикл или это кажется следующим очевидным шагом, то лучше не думать и просто делать это. Однако, если какие-либо сомнения сохраняются, это должно быть позже рассмотрено.
Другое эмпирическое правило заключается в том, что вы всегда должны проверять количество элементов и спрашивать себя, будет ли этот цикл проблемой. В моем предыдущем примере я прошел через города. Для тестирования я могу пройти только десять городов, но какое максимальное количество городов ожидать в реальном мире? Тогда я мог бы умножить это на континенты. Эмпирическое правило всегда учитывать циклы, особенно те, которые повторяют динамическое (переменное) количество раз, что это может перевести вниз.
Независимо от того, всегда делать то, что работает в первую очередь. Когда вы видите возможность оптимизации, вы можете сравнить оптимизированное решение с самым простым в работе и подтвердить, что оно принесло ожидаемые выгоды. Вы также можете провести слишком долгую преждевременную оптимизацию, прежде чем начнутся измерения, что приведет к YAGNI или большому количеству потерянного времени и пропущенных сроков.
источник
n
, это геометрический или многочленом .