2.2.1.12 — insertion sort без вложенного цикла и без отдельной переменной key2.2.1.12 — insertion sort with no nested loop and no separate key variable

Гномья СортировкаGnome Sort

Названа по аналогии с садовым гномом, сортирующим горшки с цветами: он смотрит на текущий и предыдущий горшок, идёт на шаг вперёд, если они в порядке, и меняет их местами, делая шаг назад, если нет. Это ровно та же логика, что у insertion sort, но записанная одним указателем и одним циклом вместо вложенных — что делает её одной из самых простых для запоминания и реализации сортировок вообще.Named after a garden gnome sorting flower pots: it looks at the current and previous pot, steps forward if they're in order, and swaps them while stepping back if not. This is exactly insertion sort's logic, but expressed with a single pointer and a single loop instead of nested ones — making it one of the simplest sorting algorithms to remember and implement at all.

stable in-place без вложенных цикловno nested loops

Идея и инвариантIdea & invariant

Единственный указатель i движется по массиву. Если i == 0 или a[i-1] ≤ a[i], пара в порядке — i увеличивается на 1 (шаг вперёд). Иначе пара нарушена — элементы меняются местами, и i уменьшается на 1 (шаг назад, чтобы проверить новую пару перед переставленным элементом). Алгоритм завершается, когда i достигает конца массива. Инвариант в точности как у insertion sort — префикс [0, i) в момент шага вперёд всегда отсортирован — но здесь это следует не из явного вложенного while, а из того, что каждый шаг назад "протаскивает" неуместный элемент ровно на одну позицию влево, точно так же, как внутренний цикл insertion sort, просто в других терминах.A single pointer i moves through the array. If i == 0 or a[i-1] ≤ a[i], the pair is in order — i increases by 1 (step forward). Otherwise the pair is violated — the elements are swapped, and i decreases by 1 (step back, to check the new pair in front of the swapped element). The algorithm finishes when i reaches the array's end. The invariant is exactly insertion sort's — the prefix [0, i) at the moment of a forward step is always sorted — but here it follows not from an explicit nested while but from each backward step "dragging" a misplaced element exactly one position left, the same as insertion sort's inner loop, just phrased differently.

[3, 5, 2, 4] — i = 2 3 5 2 4 a[1]=5 > a[2]=2 — меняем, i-- (шаг назад) [3, 2, 5, 4] — i = 1 3 2 a[0]=3 > a[1]=2 — снова меняем, i-- ещё раз

каждый "шаг назад" — это ровно один шаг внутреннего while insertion sort, просто без отдельной переменной для негоeach "step back" is exactly one iteration of insertion sort's inner while, just without a dedicated variable for it

void gnome_sort(std::vector<int>& a) {
    int i = 0;
    int n = (int)a.size();
    while (i < n) {
        if (i == 0 || a[i - 1] <= a[i]) {
            ++i;                          // пара в порядке — шаг вперёд// pair is fine — step forward
        } else {
            std::swap(a[i - 1], a[i]);
            --i;                          // пара нарушена — свап и шаг назад// pair violated — swap and step back
        }
    }
}

Демонстрация вживуюLive demonstration

Указатель (жёлтая подсветка пары) движется вперёд или назад в зависимости от одного простого сравнения. Обратите внимание, как отсутствие вложенного цикла не меняет число операций — оно просто "размазано" по одному внешнему циклу.The pointer (yellow pair highlight) moves forward or backward based on one simple comparison. Notice how the absence of a nested loop doesn't change the operation count — it's just "spread out" over a single outer loop.

i: 0   перестановок:swaps: 0

нажмите «Вперёд» или «Играть», чтобы начатьpress "Forward" or "Play" to begin

Почему сложность в точности совпадает с insertion sortWhy the complexity exactly matches insertion sort

Каждый шаг назад в gnome sort соответствует ровно одной итерации внутреннего while в insertion sort (2.2.1.1) — оба сдвигают один "неуместный" элемент на одну позицию влево. Каждый шаг вперёд соответствует переходу insertion sort к следующему i во внешнем цикле. Поэтому число элементарных операций у обоих алгоритмов совпадает день в день: Θ(n²) в худшем случае (например, при массиве, отсортированном по убыванию), Θ(n) на уже отсортированном входе — та же адаптивность, что и у insertion sort, просто выраженная другим управлением потоком. Разница чисто синтаксическая, а не алгоритмическая.Every backward step in gnome sort corresponds to exactly one iteration of insertion sort's (2.2.1.1) inner while — both shift one "misplaced" element one position left. Every forward step corresponds to insertion sort's outer loop advancing to the next i. So both algorithms' operation counts match exactly: Θ(n²) worst case (e.g. a descending array), Θ(n) on an already-sorted input — the same adaptivity as insertion sort, just expressed with different control flow. The difference is purely syntactic, not algorithmic.

Где встречаетсяWhere it shows up

01

Учебный пример "одна и та же идея, другое выражение"A teaching example of "the same idea, expressed differently"

Gnome sort почти никогда не используется в продакшене — его практическая ценность в основном учебная: показать, что сложность алгоритма определяется тем, что он делает, а не тем, как это записано (вложенный цикл vs. один указатель) — важный концептуальный урок при анализе сложности произвольного кода.Gnome sort is almost never used in production — its practical value is mostly pedagogical: showing that an algorithm's complexity is determined by what it does, not by how it's written (a nested loop vs. a single pointer) — an important conceptual lesson when analyzing the complexity of arbitrary code.

02

Минималистичные встраиваемые реализации без стека вызововMinimalist embedded implementations without a call stack

Отсутствие вложенного цикла и рекурсии делает gnome sort иногда предпочтительным в очень ограниченных средах (микроконтроллеры с минимальным ПЗУ), где важна каждая строка кода — хотя в подавляющем большинстве случаев insertion sort со вложенным циклом работает так же и читается яснее.The lack of a nested loop or recursion sometimes makes gnome sort preferable in very constrained environments (microcontrollers with minimal ROM) where every line of code matters — though in the vast majority of cases insertion sort with a nested loop works identically and reads more clearly.