Вопрос с подвохом!
Лучший способ - использовать STL и воспользоваться тем фактом, что отсортированный ассоциативный контейнер ADT, набор которого является реализацией, требует вставки отсортированных диапазонов с амортизированным линейным временем. Любой проходимый набор основных структур данных для любого языка должен предлагать аналогичную гарантию. Чтобы получить реальный ответ, см. Довольно умные решения, предоставленные другими.
Что это? Я должен предложить что-то полезное?
Hum ...
Как насчет этого?
Наименьшее возможное значимое дерево в сбалансированном бинарном дереве - это 3 узла.
Родитель и двое детей. Самым первым экземпляром такого дерева являются первые три элемента. Ребенок-родитель-ребенок. Давайте теперь представим это как один узел. Хорошо, у нас больше нет дерева. Но мы знаем, что нам нужна форма Child-parent-Child.
Сделано на мгновение нашим воображением, мы хотим сохранить указатель на родителя в этом начальном триумвирате. Но это однозначно!
Мы хотим иметь четыре указателя, которые я назову A, B, C и D. Итак, мы переместим A в 1, установим B равным A и переместим его на единицу. Установите C равным B, и продвиньте это два. Узел под B уже указывает на своего правого потомка. Мы строим наше первоначальное дерево. Мы оставляем B у родителя первого дерева. Си сидит в узле, который будет иметь два наших минимальных дерева в качестве детей. Установите A равным C и продвиньте его на единицу. Установите D равным A и продвиньте его на единицу. Теперь мы можем построить наше следующее минимальное дерево. D указывает на корень этого дерева, B указывает на корень другого, а C указывает на ... новый корень, из которого мы будем вешать два наших минимальных дерева.
Как насчет картинок?
[A][B][-][C]
С нашим изображением минимального дерева в качестве узла ...
[B = Tree][C][A][D][-]
А потом
[Tree A][C][Tree B]
За исключением того, что у нас есть проблема. Узел два после D - наш следующий корень.
[B = Tree A][C][A][D][-][Roooooot?!]
Нам было бы намного проще, если бы мы могли просто поддерживать указатель на него, а не на него и C. Получается, поскольку мы знаем, что это будет указывать на C, мы можем пойти дальше и начать строить узел в двоичное дерево, которое будет содержать его, и как часть этого мы можем ввести C в него как левый узел. Как мы можем сделать это элегантно?
Установить указатель узла под C на узел под B.
Это обман во всех смыслах этого слова, но, используя этот трюк, мы освобождаем B.
Кроме того, вы можете быть в здравом уме, и на самом деле начать строить структуру узла. В конце концов, вы действительно не можете повторно использовать узлы из SLL, они, вероятно, являются структурами POD.
Так что теперь ...
[TreeA]<-[C][A][D][-][B]
[TreeA]<-[C]->[TreeB][B]
И ... Подожди секунду. Мы можем использовать этот же трюк, чтобы освободить C, если мы просто будем думать о нем как об одном узле вместо дерева. Ведь в конце концов, это всего лишь один узел.
[TreeC]<-[B][A][D][-][C]
Мы можем обобщить наши уловки.
[TreeC]<-[B][TreeD]<-[C][-]<-[D][-][A]
[TreeC]<-[B][TreeD]<-[C]->[TreeE][A]
[TreeC]<-[B]->[TreeF][A]
[TreeG]<-[A][B][C][-][D]
[TreeG]<-[A][-]<-[C][-][D]
[TreeG]<-[A][TreeH]<-[D][B][C][-]
[TreeG]<-[A][TreeH]<-[D][-]<-[C][-][B]
[TreeG]<-[A][TreeJ]<-[B][-]<-[C][-][D]
[TreeG]<-[A][TreeJ]<-[B][TreeK]<-[D][-]<-[C][-]
[TreeG]<-[A][TreeJ]<-[B][TreeK]<-[D][-]<-[C][-]
Мы пропустили важный шаг!
[TreeG]<-[A]->([TreeJ]<-[B]->([TreeK]<-[D][-]<-[C][-]))
Становится:
[TreeG]<-[A]->[TreeL->([TreeK]<-[D][-]<-[C][-])][B]
[TreeG]<-[A]->[TreeL->([TreeK]<-[D]->[TreeM])][B]
[TreeG]<-[A]->[TreeL->[TreeN]][B]
[TreeG]<-[A]->[TreeO][B]
[TreeP]<-[B]
Очевидно, что алгоритм может быть значительно очищен, но я подумал, что было бы интересно продемонстрировать, как можно оптимизировать свою работу путем итеративной разработки алгоритма. Я думаю, что такой процесс - это то, что хороший работодатель должен искать больше всего на свете.
Суть в том, что каждый раз, когда мы достигаем следующей средней точки, которая, как мы знаем, является будущим родителем, мы знаем, что его левое поддерево уже закончено.Другой трюк заключается в том, что мы закончили с узлом, когда у него есть два дочерних элемента и что-то указывает на него, даже если все поддеревья не завершены.Используя это, мы можем получить то, что, я уверен, является линейным решением по времени, так как каждый элемент касается только 4 раза.Проблема в том, что это зависит от получения списка, который сформирует действительно сбалансированное двоичное дерево поиска.Другими словами, существуют некоторые скрытые ограничения, которые могут сделать это решение более сложным для применения или невозможным.Например, если у вас нечетное количество элементов или много неуникальных значений, это приводит к довольно глупому дереву.
Соображения:
- Сделать элемент уникальным.
- Вставить фиктивный элемент в конце, если число узлов нечетное.
- Пойте с тоской для более наивной реализации.
- Используйте деку, чтобы сохранить корни завершенных поддеревьев и средних точек, вместо того, чтобы копаться со вторым трюком.