Упорядоченный связанный список против B-Tree

Если у вас есть дерево b+ в качестве индекса, то это очень похоже на упорядоченный связанный список. Но упорядоченный связанный список, по-видимому, имеет некоторые преимущества, такие как отсутствие необходимости перемещаться по древовидной структуре, а также отсутствие необходимости перестраивать узлы, когда они заполняются, и отсутствие необходимости перестраивать дерево, когда оно становится несбалансированным.

Может ли кто-нибудь ответить, в чем причина использования b-дерева, а не упорядоченного связанного списка?


person Adam Davies    schedule 05.12.2011    source источник
comment
Я думаю, что вопрос имеет гораздо больше смысла, если сравнивать со списком произвольного доступа, а не со связанным списком. Поскольку связанный список требует, чтобы вы прошли их, чтобы получить доступ к элементу, который делает их доступными для поиска O (n), даже если они отсортированы.   -  person Konstantin Schubert    schedule 25.05.2018


Ответы (3)


После некоторых исследований и чтения статей я нашел ответ.

Чтобы справиться с большими объемами данных, такими как миллионы записей, индексы должны быть организованы в кластеры. Кластер — это непрерывная группа секторов на диске, которая может быть быстро считана в память. Обычно они имеют длину около 4096 байт.

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

Итак, если мы ищем конкретную запись, как узнать, в каком кластере она находится? Мы выполняем бинарный поиск, чтобы найти рассматриваемый кластер [O(log n)].

Однако для выполнения бинарного поиска нам нужно знать диапазон значений в каждом кластере данных, поэтому нам нужны метаданные, в которых указано минимальное и максимальное значение каждого кластера и где находится этот кластер. Это замечательно. За исключением того, что каждый кластер данных содержит 100 индексов, а наш кластер метаданных также содержит 100 индексов, тогда мы можем получить доступ только к 100 кластерам данных. Что соответствует 10 000 записей (100 X 100).

Ну этого недостаточно. Давайте добавим еще один кластер метаданных, и теперь мы можем получить доступ к 1 000 000 записей. Так как же нам узнать, какой из трех кластеров метаданных нам нужно запросить, чтобы найти наш целевой кластер данных. Мы могли бы искать их один за другим, но это не масштабируется, и в среднем это O(n/2). Поэтому я добавляю еще один кластер мета-метаданных, чтобы указать, к какому из трех кластеров метаданных я должен обратиться, чтобы найти целевой кластер данных. Теперь у меня есть дерево!

Вот почему базы данных используют деревья. Дело не в скорости, а в размере индексов и необходимости иметь индексы, ссылающиеся на другие индексы. То, что я описал выше, представляет собой B+Tree — дочерние узлы содержат ссылки на другие дочерние узлы или конечные узлы, а конечные узлы содержат ссылки на данные на диске.

Фу!

person Adam Davies    schedule 06.12.2011

Отличий в характеристиках много, но я подчеркиваю время поиска.

В то время как поиск занимает O(log N) времени в дереве b+, это O(n) времени в связанном списке, даже если он отсортирован.

Источник: http://en.wikipedia.org/wiki/Linked_list, http://en.wikipedia.org/wiki/B%2B_tree

person bpgergo    schedule 05.12.2011
comment
Это не вариант. Если список упорядочен и вы знаете количество элементов в нем (что легко сделать с небольшим количеством метаданных), то вы можете использовать бинарный поиск, который составляет O(log n) en.wikipedia.org/wiki/Binary_search Кроме того, каждый узел в дереве требует, чтобы вы знали минимальное и максимальное значения, поэтому, как только вы нашел целевой узел, вам все равно придется выполнить бинарный поиск на этом узле. Следовательно, упорядоченный список должен быть быстрее (без навигации по узлу плюс перестроение и т. д.). - person Adam Davies; 05.12.2011
comment
Я также думал о бинарном поиске. У меня есть серьезные сомнения, возможно ли это в связанных списках (даже если они упорядочены). Я пришел к выводу, что каким-то образом это можно реализовать, но эта реализация будет зависеть от того, как сам список реализован и представлен в памяти. Можете ли вы сказать мне, как получить средний элемент, не перебирая половину элементов? - person bpgergo; 05.12.2011
comment
среднийЭлемент = список[длина списка-1 / 2]; // -1 зависит от того, что вы называете средним элементом, где listLength даже. См. algolist.net/Algorithms/ Binary_search для более полных алгоритмов. Впрочем, реализация не важна. Важный вопрос заключается в том, может ли он быть быстрее, чем B-дерево, принимая во внимание все другие проблемы обслуживания, которые необходимо выполнить (повторная балансировка и т. д.). Или я что-то упускаю? - person Adam Davies; 05.12.2011
comment
Адам, вот в чем дело с middleElement = list[listLength-1 / 2];. Операции, индексирующие связанный список, будут проходить по списку с начала или с конца. Это означает, что позиционный доступ, такой как list[listLength-1 / 2], требует линейного времени в связанном списке, а не постоянного времени в массиве. Вот почему бинарный поиск в связанном списке — это O(n), а не O(log n). - person bpgergo; 06.12.2011
comment
А? Если у вас есть список и вы обращаетесь к нему по индексу, вы не выполняете никакого обхода — вы обращаетесь к элементу напрямую. В этом весь смысл доступа к индексу. Вот почему бинарный поиск имеет значение log-n. Не линейно. - person Adam Davies; 06.12.2011
comment
@ Адам Дэвис, то, о чем вы говорите, - это обычный список, допускающий произвольный доступ. В связанном списке НЕТ произвольного доступа, и поэтому даже в отсортированном связанном списке поиск выполняется O(n). - person Konstantin Schubert; 25.05.2018

В бинарном дереве поиска время поиска O(log n) является средним случаем. В худшем случае, когда дерево полностью несбалансировано и напоминает связанный список, поиску требуется время O(n).

person bpgergo    schedule 05.12.2011
comment
Элементы в отсортированных списках можно найти с помощью двоичного поиска. Итак, это O (log n). Извини, приятель, но это определение бинарного поиска. Например, docs.oracle.com/javase/6/docs/api/java/util/. Чтобы было ясно, список RandomAccess — это список, элементы которого могут быть доступны для любого случайного значения индекса (пока значение находится в пределах диапазона) - person Adam Davies; 06.12.2011
comment
Из документов, на которые вы ссылаетесь: двоичный поиск выполняется за логарифмическое время (n) для списка произвольного доступа (который обеспечивает позиционный доступ почти в постоянное время). Если указанный список не реализует интерфейс RandomAccess и имеет большой размер, этот метод выполнит двоичный поиск на основе итератора, который выполняет O (n) обходов ссылок и O (log n) сравнений элементов. Подумайте об этом: Java LinkedList НЕ реализует RandomAccess интерфейс. - person bpgergo; 06.12.2011
comment
Не в java, но нет причин, по которым это нельзя сделать - person Adam Davies; 06.12.2011