У нас уже есть ответ, который предлагает деревья, но я думаю, что нам нужно быть более конкретным: единственная ситуация, в которой это действительно хорошее решение, - это если вы очень точно знаете, как построить дерево (а затем ясказал бы, что это наравне со списками пропусков, предложенными в другом ответе;).Цель состоит в том, чтобы дерево было как можно полнее влево - я поясню, что это означает в следующем.Убедитесь, что у каждого узла есть указатель на его (до) двух дочерних элементов и на его родителя , а знает глубину поддерева, укорененного в этом узле.
Сохранитьуказатель на корневой узел, чтобы вы могли выполнять поиск в O (log (n)) и сохранять указатель на последний вставленный узел N (который обязательно является узлом с самым высоким ключом - его временная метка будет самой высокой).Когда вы вставляете узел, проверьте, сколько дочерних элементов N имеет:
- Если 0, то замените N новым узлом, который вы вставляете, и сделайте N его левым потомком.(На этом этапе вам нужно обновить поле глубины дерева максимум для O (log (n)) узлов.)
- Если 1, то добавить новый узел в качестве его правого потомка.
- Если 2, то все становится интересно.Идите вверх по дереву от N до тех пор, пока не найдете узел, у которого есть только 1 дочерний элемент, или корень.Если вы найдете узел только с одним дочерним элементом (это обязательно левый дочерний элемент), то добавьте новый узел в качестве его нового правого дочернего элемента.Если все узлы вплоть до корня имеют двух дочерних элементов, то текущее дерево заполнено.Добавьте новый узел в качестве нового корневого узла и старый корневой узел в качестве его левого потомка.В противном случае не изменяйте старую древовидную структуру.
Приложение: для того, чтобы улучшить поведение кеша и использование памяти, лучшим решением, вероятно, является создание дерева или списка пропусков массивов .Вместо того чтобы каждый узел имел одну временную метку и одно значение, пусть каждый узел имеет массив, скажем, 1024 временных меток и значений.Когда массив заполняется, вы добавляете новый в структуру данных верхнего уровня, но на большинстве шагов вы просто добавляете один элемент в конец «текущего массива».Это не повлияет на поведение big-O в отношении памяти или времени, но уменьшит накладные расходы в 1024 раза, в то время как задержка все еще очень мала.