Анализ основного принципа реализации HashMap

1. Принципы реализации put() и get() в HashMap:

1. Принцип реализации map.put(k,v)

  • Сначала инкапсулируем k и v в объекты Node (узлы).
  • Затем его нижний уровень вызовет метод hashCode() класса K для получения хэш-значения.
  • Наконец, значение хеш-функции преобразуется в нижний индекс массива с помощью функции/алгоритма хеш-таблицы. Если в позиции нижнего индекса нет элемента, к этой позиции добавляется узел. Если в позиции, соответствующей нижнему индексу, есть связанный список. В этот момент k будет равно k каждого узла в связанном списке. Если все методы равенства возвращают значение false, новый узел будет добавлен в конец связанного списка. Если один из равных возвращает true, значение этого узла будет перезаписано.

2. Принцип реализации map.get(k)

  • Сначала вызовите метод hashCode() для k, чтобы получить значение хеш-функции, и преобразуйте его в нижний индекс массива с помощью алгоритма хеширования.
  • После преобразования его в индекс массива с помощью алгоритма хеширования на предыдущем шаге он может быстро найти определенную позицию с помощью индекса массива. Если в этом месте ничего нет, возвращается ноль. Если в этой позиции находится односторонний связанный список, то для выполнения равенства потребуется K и K каждого узла в одностороннем связанном списке. Если все методы равенства возвращают значение false, метод get возвращает значение null. Если K одного из узлов и параметр K равны и возвращают true, то значение узла — это искомое значение, и метод get наконец возвращает искомое значение.

Общая проблема:

  • Добавление и удаление HashMap выполняется в связанном списке, а запросам необходимо сканировать только часть, поэтому случайные добавления и удаления, а также эффективность запросов очень высоки.
  • Ключ коллекции HashMap будет последовательно вызывать два метода: hashCode и методы равенства. Нужно ли переписывать эти два метода? Поскольку метод равенства по умолчанию сравнивает адреса памяти двух объектов.

2. Анализ принципа красно-черного дерева HashMap

По сравнению с HashMap из jdk1.7, самое важное в jdk1.8 — это введение красно-черного дерева. За исключением операции вставки, красно-черное дерево работает быстрее, чем связанный список. Когда длина один связанный список хеш-таблицы превышает 8. Когда длина массива превышает 64, структура связанного списка будет преобразована в красно-черную древовидную структуру. Когда количество узлов в красно-черном дереве меньше 6, красно-черное дерево будет преобразовано в структуру данных одностороннего связанного списка.
Почему он спроектирован таким образом? Преимущество заключается в том, что в самом крайнем случае связанный список не станет очень длинным, что приведет к очень низкой эффективности во время запросов.

Запрос красно-черного дерева: производительность доступа аналогична половинному поиску, временная сложность равна O(logn);
запрос связанного списка: в этом случае необходимо пройти все элементы, а временная сложность равна O(n);
проще говоря, красно-черное Дерево представляет собой приблизительно сбалансированное двоичное дерево поиска, главное его достоинство - "сбалансированность", то есть высота левого и правого поддерева практически одинакова, что не дает дереву выродиться в связный список Таким образом, временная сложность поиска гарантированно будет равна log(n).

 

Несколько основных характеристик красно-черных деревьев:

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

3. Разница между принципами HashMap 1.7 и 1.8

Нижний уровень в jdk1.7 реализован массивом + связанный список; нижний уровень в jdk1.8 реализован массивом + связанный список/красно-черное дерево. Могут
храниться нулевые ключи и нулевые значения. Начальный размер равен потоконебезопасен.
Начальный размер – 16. Расширение: newsize = oldsize*2, размер должен быть n, степень 2.
Расширение предназначено для всей карты. Во время каждого расширения места хранения элементов в исходном массиве пересчитываются по очереди и вставляются заново.Когда
общее количество элементов в Карте превышает 75% массива Entry, срабатывает операция расширения.Чтобы уменьшить длину связанного списка и распределить элементы более равномерно
 

4. Конфликт хешей

Когда два ключа имеют одинаковый расчет hashCod (на самом деле hashCode генерируется случайным образом, возможно, что hashCode один и тот же), возникает конфликт хэшей.

Методы решения конфликтов хэшей включают в себя: метод открытой адресации, метод повторного хэширования, метод цепочки адресов и создание общедоступной области переполнения
HashMap.Способ решения конфликтов хеширования заключается в использовании связанного списка. Когда возникает конфликт хэшей, запись, хранящаяся в массиве, устанавливается на следующее новое значение. Грубо говоря, например, A и B хэшируются и сопоставляются с индексом i. Раньше уже было A. Когда происходит конфликт хэшей, запись, хранящаяся в массиве, устанавливается на следующее новое значение. map.put(B), поместите B в индекс i, и A будет следующим за B, поэтому новое значение сохраняется в массиве, а старое значение находится в связанном списке нового значения.

Метод открытой адресации: когда хэш-адрес p=H (ключ) ключевого слова конфликтует, другой хеш-адрес p1 генерируется на основе p. Если p1 все еще конфликтует, другой хеш-адрес p1 генерируется на основе p. Хэш-адрес p2,. .., пока не будет найден неконфликтный хэш-адрес pi и в нем не будет сохранен соответствующий элемент

Метод повторного хэширования: одновременно создайте несколько разных хеш-функций. Когда хэш-адрес Hi=RH1 (ключ) конфликтует, вычисляйте Hi=RH2 (ключ)... до тех пор, пока конфликты не перестанут возникать.

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

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

Supongo que te gusta

Origin blog.csdn.net/ddwangbin520/article/details/131531226
Recomendado
Clasificación