Smas: Sorted Multi Array Struct — Альтернатива Двоичному Дереву Поиска.



Введение Здравствуйте, Хабравяне.

Это моя первая публикация, в которой я хочу поделиться структурой данных SMAS. В конце статьи будет предоставлен класс C++ предлагаемой структуры данных.

Реализация рекурсивная, но моя цель — передать идею.

Реализация нерекурсивной версии — дело второе.

Важно «слышать» мнения.



Что не так с деревом?

Да, всё, можно заканчивать статью, всем спасибо.

Это была бы трата значительных накладных расходов памяти на вспомогательные данные в виде ссылок на левое-правое поддеревья и флага балансировки (разного в зависимости от используемой методики - красно-черные, AVL и т.п.

деревья).

Еще один, не такой уж и минус, — постоянная модификация дерева при вставке для балансировки (здесь особенно важна сложность и трудоемкость методов для новичков).

На этом недостатки заканчиваются и сложно представить что-то лучшее и универсальное (хеш-таблицы, ИМХО, еще круче, но ОХ МОИ СТОЛКНОВЕНИЯ).



Почему не отсортированные массивы?

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

Но что не так с отсортированными массивами? Да, все верно, мы можем закончить статью и использовать отсортированные массивы вместо бинарных деревьев поиска и наслаждаться сэкономленными ресурсами, если только нам не нужно добавлять или удалять элементы из такого массива, потому что если мы добавим новые элементы (удалим старые), тогда массив скажет: «сломи меня, пересортируй меня» полностью».

Но беда сортировки в том, что она медленная, если нужно вставить новый элемент где-то между остальными, особенно в начале.

Но есть и идеальный случай — когда новый элемент больше остальных и его достаточно просто добавить в конец.

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

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



Частный случай или закономерность?

Но давайте рассмотрим массив, состоящий всего из одного элемента.

Неважно, какое значение введено — оно всегда укладывается в начало ранее пустого массива и одноэлементный массив, естественно, всегда сортируется.

Что, если мы хотим вписать второй элемент в нашу структуру данных? Давайте просто создадим еще один одноэлементный массив и получим два отсортированных одноэлементных массива.

Получить новый отсортированный массив из двух отсортированных — задача простая, хотя и не очень быстрая.

Но в этом случае нам уже нужно сортировать массив не при каждой вставке, а при каждой второй вставке.

Мы используем «отложенную сортировку».

Что делать, если мы хотим добавить более двух элементов? Захотеть не помешает - напишем где-нибудь новый 2-х элементный массив и продолжим добавлять элементы в одноэлементные массивы, а также на 4-м элементе у нас будет 2 2-х элементных отсортированных массива, которые мы сможем объединить таким же образом в один 4-х элемент и так до тех пор, пока не выскочит синий экран смерти и процессор не взорвется с сопутствующим образованием черной дыры, втягивающей в себя все окружающее пространство-время (что-то меня унесло.

) пока наша память это позволяет.

Распределение нагрузки

Понятно, что этот алгоритм уже значительно сокращает количество сортировок относительно сортировки обычного массива, поскольку первый уровень массивов нужно сортировать через раз, 2-й уровень - каждую 4-ю вставку, 3-й уровень - каждую 8-ю вставку - по сути, это логарифмическая сложность.

На этом можно было бы успокоиться, но для слабаков попробуем распределить нагрузку равномерно при каждой вставке, дополняя нашу «отложенную сортировку» пошаговым подходом и выполняя каждый шаг при вставке очередного элемента для всех уровней — это позволит нам равномерно распределить нагрузку по всем вставкам — что и требуется.



Поиск

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

Поэтому логарифмическая сложность поиска оспаривается (если не ошибаюсь, это двойная логарифмическая сложность).

Но для поставленной задачи это вполне приемлемо, учитывая сэкономленную память.



Выполнение

Пока чайник кипел, я вспомнил, что еще хочу писать, но тут чайник закипел, и его свист заставил меня забыть, что я еще хотел написать.

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

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



Фактический код

   

#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <windows.h> #define

Теги: #SMAS #структуры данных #упорядоченные массивы #двоичный поиск #Алгоритмы
Вместе с данным постом часто просматривают: