Двоичные деревья по сравнению со связанными списками по сравнению с хеш-таблицами

Примечание: попытка получить свойство ошибки, отличной от объекта

Случается, когда вы пытаетесь получить доступ к объекту объекта, пока нет объекта.

Типичный пример для non-object notice будет

$users = json_decode('[{"name": "hakre"}]');
echo $users->name; # Notice: Trying to get property of non-object

В этом случае $users представляет собой массив (а не объект), и он не имеет никаких свойств.

Это похоже для доступа к несуществующему индексу или ключу массива (см. Примечание: Undefined Index ).

Этот пример значительно упрощен. Чаще всего такое уведомление сигнализирует неконтролируемое возвращаемое значение, например. когда библиотека возвращает NULL, если объект не существует или просто неожиданное значение, отличное от объекта (например, в результате Xpath, структуры JSON с непредвиденным форматом, XML с неожиданным форматом и т. д.), но код не проверяет такой условие.

Поскольку эти не-объекты часто обрабатываются дальше, часто возникает фатальная ошибка при вызове метода объекта для не-объекта (см.: Неустранимая ошибка: вызов члену function ... на не-объекте ), останавливая скрипт.

Его можно легко предотвратить, проверив условия ошибки и / или переменную, соответствующую ожиданию. Здесь такое уведомление с примером DOMXPath:

$result  = $xpath->query("//*[@id='detail-sections']/div[1]");
$divText = $result->item(0)->nodeValue; # Notice: Trying to get property of non-object

Проблема заключается в доступе к свойству nodeValue первого поля, пока он не был проверен, существует ли он или нет в $result коллекция. Вместо этого он платит, чтобы сделать код более явным, назначив переменные объектам, на которых работает код:

$result  = $xpath->query("//*[@id='detail-sections']/div[1]");
$div     = $result->item(0);
$divText = "-/-";
if ($div) {
    $divText = $div->nodeValue;
}
echo $divText;

Связанные ошибки:

72
задан Philip Kirkbride 24 October 2016 в 22:04
поделиться

10 ответов

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

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

я поэтому думал бы, что HashTable был самым подходящим алгоритмом для использования, поскольку это просто генерирует хеш ключевого объекта и использует это для доступа к целевым данным - это - O (1). Другие - O (N) (Связанные списки размера N - необходимо выполнить итерации через список по одному, в среднем времена N/2) и O (регистрируют N) (Двоичное дерево - Вы делите на два пространство поиска с каждым повторением - только если дерево сбалансировано, таким образом, это зависит от Вашей реализации, несбалансированное дерево может иметь значительно худшую производительность).

Просто удостоверяются, что существует достаточно пробелов (блоки) в HashTable для Ваших данных (R.e., комментарий Soraz к этому сообщению). Большинство реализаций платформы (Java.NET, и т.д.) будет иметь качество, которое Вы не должны будете волновать по поводу реализаций.

Вы делали курс о структурах данных и алгоритмах в университете?

48
ответ дан JeeBee 24 November 2019 в 12:32
поделиться

Стандартная торговля offs между этими структурами данных применяется.

  • Двоичные деревья
    • средняя сложность для реализации (принятие Вас не может получить их от библиотеки)
    • вставки являются O (logN)
    • , поиски являются O (logN)
  • Связанные списки (неотсортированные)
    • низкая сложность для реализации
    • , вставки являются O (1)
    • , поиски являются O (N)
  • Хэш-таблицы
    • высокая сложность для реализации
    • , вставки являются O (1) [в среднем 1 124]
    • , поиски являются O (1) [в среднем 1 125]
75
ответ дан Philip Kirkbride 24 November 2019 в 12:32
поделиться

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

существует известная кавычка из Примечаний Щуки по Программированию в C: "Правило 3. Необычные алгоритмы являются медленными, когда n является маленьким, и n является обычно маленьким. Необычные алгоритмы имеют большие константы. Пока Вы не знаете, что n часто будет большим, не становитесь необычными". http://www.lysator.liu.se/c/pikestyle.html

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

42
ответ дан Joel Borggrén-Franck 24 November 2019 в 12:32
поделиться

Мне нравится ответ счета, но он действительно не синтезирует вещи.

От этих трех вариантов:

Связанные списки относительно не спешат объекты поиска от (O (n)). Таким образом, если Вы имеете партия из объектов в Вашей таблице, или Вы собираетесь быть выполнением большого количества поисков, тогда они не лучший выбор. Однако их легко создать, и легкий записать также. Если таблица является маленькой, и/или Вы только когда-либо делаете одно небольшое сканирование через нее после того, как она создается, то это могло бы быть выбором для Вас.

Хэш-таблицы могут быть ослепительно быстрыми. Однако для него для работы необходимо выбрать хороший хеш для входа, и необходимо выбрать таблицу, достаточно большую для содержания всего без большого количества хэш-коллизий. То, что это означает, является Вами, должны знать что-то о размере и количестве Вашего входа. Если Вы портите это, Вы заканчиваете с действительно дорогим и сложным набором связанных списков. Я сказал бы, что, если Вы не знаете заранее примерно, как большой таблица будет, не используйте хэш-таблицу. Это не соглашается с Вашим "принятым" ответом. Извините.

, Который оставляет деревья. У Вас есть опция здесь хотя: балансироваться или не балансироваться. Что я нашел путем изучения этой проблемы на коде C и Фортрана, который мы имеем, вот то, что вход таблицы символов имеет тенденцию быть достаточно случайным, который Вы только теряете о древовидном уровне или два, не балансируя дерево. Учитывая, что сбалансированные деревья медленнее для вставки элементов в и более тверды реализовать, я не обеспокоился бы ими. Однако, если у Вас уже есть доступ к хорошим отлаженным библиотекам компонентов (например: STL C++), тогда Вы могли бы также идти вперед и использовать сбалансированное дерево.

7
ответ дан T.E.D. 24 November 2019 в 12:32
поделиться

Это кажется, что следующее может все быть верным:

  • Ваши ключи являются строками.
  • Вставки сделаны однажды.
  • Поиски часто делаются.
  • количество пар "ключ-значение" является относительно маленьким (скажите, меньше, чем приблизительно один K).

Если так, Вы могли бы рассмотреть отсортированный список по любой из этих других структур. Это работало бы хуже, чем другие во время вставок, поскольку отсортированный список является O (N) на вставке, по сравнению с O (1) для связанного списка или хэш-таблицы и O (журнал 2 Н для сбалансированного двоичного дерева. Но поиски в отсортированном списке могут быть быстрее, чем любая из этих структур других (я объясню это вскоре), таким образом, можно будет преуспеть. Кроме того, если Вы выполняете все свои вставки сразу (или иначе не требуйте поисков, пока все вставки не завершены), тогда можно упростить вставки до O (1) и сделать один намного более быстрый вид в конце. Кроме того, отсортированный список использует меньше памяти, чем любая из этих других структур, но единственный способ, которым это, вероятно, будет иметь значение, состоит в том, если у Вас есть много маленьких списков. Если у Вас будут один или несколько больших списков, то хэш-таблица, вероятно, превзойдет отсортированный список по характеристикам.

, Почему поиски могли бы быть быстрее с отсортированным списком? Ну, ясно, что это быстрее, чем связанный список с O последнего (N) время поиска. С двоичным деревом поиски только остаются O (журнал 2 Н, если дерево остается отлично сбалансированным. Хранение сбалансированного дерева (красно-черный, например) добавляет ко времени вставки и сложности. Кроме того, и со связанными списками и с двоичными деревьями, каждый элемент является отдельно выделенным <глоток> 1 узел , что означает, что необходимо будет разыменовать указатели и вероятно перейти к потенциально широко переменным адресам памяти, увеличивая возможности неудачного обращения в кэш.

Что касается хэш-таблиц, необходимо, вероятно, читать пара из другие вопросы здесь на StackOverflow, но основные моменты интереса здесь:

  • хэш-таблица А может ухудшиться к O (N) в худшем случае.
  • стоимость хеширования является ненулевой, и в некоторых реализациях это может быть значительно, особенно в случае строк.
  • Как в связанных списках и двоичных деревьях, каждая запись узел хранение больше, чем просто ключ и значение, также отдельно выделенное в некоторых реализациях, таким образом, Вы используете больше памяти и возможностей увеличения неудачного обращения в кэш.

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

  1. для реализации возможно предварительно выделить массив узлов, которые помогли бы с проблемой неудачного обращения в кэш. Я не видел это ни в какой реальной реализации связанных списков или двоичных деревьев (не, что я видел всех, конечно), хотя Вы могли, конечно, самокрутка. У Вас все еще была бы немного более высокая возможность неудачного обращения в кэш, тем не менее, начиная с узел , объекты будут обязательно больше, чем пары ключ/значение.
8
ответ дан Community 24 November 2019 в 12:32
поделиться

Несколько вещей не упустить.

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

  • Хэш-таблицы дают O (1) средняя вставка и сложность поиска, но существует протест здесь, также. Если Ваша хеш-функция плоха (и я имею в виду действительно плохой), Вы могли бы закончить тем, что создали связанный список здесь также. Любая разумная строковая хеш-функция должна сделать, тем не менее, таким образом, это предупреждение действительно только, чтобы удостовериться, что Вы знаете, что это могло произойти. Необходимо быть в состоянии просто протестировать ту хеш-функцию, не имеет многих коллизий по ожидаемому диапазону исходных данных, и Вы будете в порядке. Еще один незначительный недостаток состоит в том при использовании хэш-таблицы фиксированного размера. Большинство реализаций хэш-таблицы растет, когда они достигают определенного размера (коэффициент загрузки, чтобы быть более точным, см. здесь для деталей). Это должно избежать проблемы, которую Вы получаете при вставке миллиона символов в десять блоков. Это просто приводит к десяти связанным спискам со средним размером 100 000.

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

6
ответ дан Bill the Lizard 24 November 2019 в 12:32
поделиться

Другие комментарии сфокусировались на добавляющих/получающих элементах, но это обсуждение не завершено, не рассматривая то, что оно берет для итерации по всему набору. Короткий ответ здесь - то, что хэш-таблицы требуют, чтобы меньше памяти выполнило итерации, но деревья требуют меньшего количества времени.

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

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

, Но ситуация инвертируется когда дело доходит до синхронизации. Для хэш-таблицы время это берет для итерации, зависит от способности таблицы, не количества сохраненных элементов. Таким образом, таблица, загруженная на 10% способности, сопроводит в 10 раз дольше для итерации, чем связанный список с теми же элементами!

1
ответ дан 24 November 2019 в 12:32
поделиться

Этот вопрос проходит различные контейнеры в C#, но они подобны на любом языке, который Вы используете.

0
ответ дан Community 24 November 2019 в 12:32
поделиться

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

0
ответ дан unwind 24 November 2019 в 12:32
поделиться

Если Вы не ожидаете, что Ваша таблица символов будет маленькой, я должен избегать связанных списков. Список 1 000 объектов в среднем возьмет 500 повторений для нахождения любого объекта в нем.

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

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

0
ответ дан Martin Cowie 24 November 2019 в 12:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: