Это скорее вопрос формализации задачи. Если всё честно считать в битах, то да, Θ(N log N) и там, и там. Более того, очевидно, что, если в основном массиве непонятно что записано и мы только меняем местами его элементы, это нижняя граница по дополнительной памяти (потому что всю информацию мы берем только из дополнительной памяти, значит перед началом генерации каждой перестановки в этой памяти должно быть записано своё уникальное значение, последовательностей N!, значит нам требует не меньше log2 N! бит).
Но по факту, N ограничено сверху очень маленькой константой порядка 20 (иначе алгоритм до нашей смерти не закончит работу), поэтому если уж так хочется сравнивать по памяти алгоритмы, то разумнее уж прямо в байтах написать, сколько кому требуется, а не асимптотики сравнивать.
У меня появилась мысль об одной из возможных причин такого разделения. Просто с точки зрения получения количества плюсиков за пост (а если я не ошибаюсь, то каждый плюсик свыше какого-то числа ещё и приносит денежку для тех, кто участвует в ППА) гораздо выгоднее написать на какую-нибудь популярную тему (тему, которая понятна подавляющему большинству), чем написать или перевести техническую статью. Поэтому большинство таких тем утащили на другие ресурсы. Правда способ борьбы, конечно, радикальный.
Лучше бы при нажатии на пост делался редирект на соответствующую страницу на хабре или гиктаймс, чтобы можно было пост комментировать и оценки ставить.
В том числе потому, что вероятность ошибки при написании 3 новых классов
Нам же не с нуля надо эти классы разрабатывать с какой-то уникальной функциональностью в каждом, они весьма однотипны. Всё можно устроить так, что добавление нового класса будет требовать от нас написание одной строчки кода (например, завернуть объявление класса в макрос) или одного клика в IDE для вставки соответствующего сниппета.
Какие-то у вас странные аналогии, мы же о текстовом файле с кодом говорим, у него нету никаких слоев данных и представлений: какие символы вы нажмете на клавиатуре, те и будут записаны в файл, какие символы записаны в файле, те и будут выведены на экран.
Пробел и таб — это пустое место и воспринимается, как пустое, ничего не значащее место.
Возьмите любой сложный код (скажем, 4 уровня вложенности) на языке со скобочками, удалите из него отступы и попробуйте прочитать. Вам будет очень некомфортно. А если удалить из кода скобочки, оставив отступы, то все останется читаемо. А вы говорите, ничего не значащее место.
Скобочки, на мой взгляд, полезны тем, что не навязывают вам жесткий code style на уровне языка, однако при чтении кода основное внимание мы обращаем именно на отступы.
А что если сделать рядом с каждой статьей какую-нибудь кнопку "Скрыть", при нажатии на которую для тебя статья исчезает из ленты и списка популярных за сутки? Тогда получится, что один раз глазами отфильтровал такую статью, как не интересную тебе, и больше на неё не натыкаешься при просмотре этих двух разделов.
Мне кажется, ваш пример некорректен, отступы — это тоже вполне себе явное выделение блоков. Более того, уверен, что наткнувшись посреди С++ кода на фрагмент типа:
...
if (x == 0)
y = 10;
z = 15;
...
90% прочитают его так, как будто и первое, и второе присваивание происходит лишь при выполнении условия, то есть посмотрят не на скобочки (которых нет, и поэтому лишь первое присваивание относится к if), а на отступы.
Не уверен, что я правильно вас понял, но в данном примере обвес строится вокруг функции createDate(), а не каких-то структур данных, а типы width и height, если вы о них, — это обычные сишные структуры с одним интом внутри, которые, в свою очередь, на машинном уровне то же самое, что и простой int.
Это, кстати, поинтересней вышеприведенного решения, т.к. здесь не требуется, чтобы параметры были точно типов Day, Year и Month, а достаточно, чтобы можно было однозначно конвертировать каждый аргумент в один из этих типов. Надо бы только защититься от подобных вызовов:
Причем final ещё и оптимизировать помогает, скажем, в таком коде:
struct A { virtual void f(); }
struct B : public A { virtual void f() override final; }
struct C final : public A { virtual void f() override; }
void do_with_B(B& b) { b.f(); }
void do_with_C(C& c) { c.f(); }
в обоих функциях do_with... вызов f() будет вызвана напрямую соответствующая функция, тогда как без final там был бы вызов через таблицу виртуальных функций.
apples будет отдельным типом (в него нельзя будет присвоить int или груши, скажем), при этом по умолчанию для него будут определены все операторы сравнения и функция хеширования (поэтому, например, его можно положить в любой STL контейнер, ничего дополнительно не дописывая). Из минусов: не работают арифметические операции, не работает вывод через потоки (и то, и то можно ручками дописать) плюс проблемы с синтаксисом конструирования, т.к. единственный способ сконструировать такой тип из встроенного числового типа — это сделать явный каст:
apples a(0); // Compilation error
apples b( apples(0) ); // OK
apples c = apples{0}; // Compilation error
apples d = apples(0); // OK
Но по факту, N ограничено сверху очень маленькой константой порядка 20 (иначе алгоритм до нашей смерти не закончит работу), поэтому если уж так хочется сравнивать по памяти алгоритмы, то разумнее уж прямо в байтах написать, сколько кому требуется, а не асимптотики сравнивать.
Возьмите любой сложный код (скажем, 4 уровня вложенности) на языке со скобочками, удалите из него отступы и попробуйте прочитать. Вам будет очень некомфортно. А если удалить из кода скобочки, оставив отступы, то все останется читаемо. А вы говорите, ничего не значащее место.
Скобочки, на мой взгляд, полезны тем, что не навязывают вам жесткий code style на уровне языка, однако при чтении кода основное внимание мы обращаем именно на отступы.
90% прочитают его так, как будто и первое, и второе присваивание происходит лишь при выполнении условия, то есть посмотрят не на скобочки (которых нет, и поэтому лишь первое присваивание относится к if), а на отступы.
createDate()
, а не каких-то структур данных, а типыwidth
иheight
, если вы о них, — это обычные сишные структуры с одним интом внутри, которые, в свою очередь, на машинном уровне то же самое, что и простойint
.после подстановки параметров по умолчанию получается:
Если мы хотим создать эту же структуру только с нашим аллокатором (поменять последний параметр), то нам прийдется явно выписывать все эти параметры:
вместо какой-нибудь такой записи:
Day
:Тогда мы можем делать так:
и это реально здорово и является преимуществом вашего метода перед предложенным выше.
Но мы cможем сделать и вот так:
поэтому до конца проблема не решена.
P.S. И это уже не «без С++11» ;-)
Day
,Year
иMonth
, а достаточно, чтобы можно было однозначно конвертировать каждый аргумент в один из этих типов. Надо бы только защититься от подобных вызовов:final
ещё и оптимизировать помогает, скажем, в таком коде:в обоих функциях
do_with...
вызовf()
будет вызвана напрямую соответствующая функция, тогда как безfinal
там был бы вызов через таблицу виртуальных функций.apples
будет отдельным типом (в него нельзя будет присвоить int или груши, скажем), при этом по умолчанию для него будут определены все операторы сравнения и функция хеширования (поэтому, например, его можно положить в любой STL контейнер, ничего дополнительно не дописывая). Из минусов: не работают арифметические операции, не работает вывод через потоки (и то, и то можно ручками дописать) плюс проблемы с синтаксисом конструирования, т.к. единственный способ сконструировать такой тип из встроенного числового типа — это сделать явный каст: