Коэффициент нагрузки и повторное хеширование
Предварительные требования: Введение в хеширование и обработка конфликтов путем отдельного объединения в цепочку.
Как работает хеширование:
Для вставки пары ключ (K) - значение (V) в хеш-карту требуется 2 шага:
- K преобразуется в небольшое целое число (называемое его хеш-кодом) с помощью хеш-функции.
- Хэш-код используется для поиска индекса (hashCode% arrSize), и сначала выполняется поиск всего связанного списка по этому индексу (отдельная цепочка) на наличие K уже.
- Если он найден, его значение обновляется, а если нет, пара KV сохраняется как новый узел в списке.
Сложность и коэффициент загрузки
- Для первого шага затраченное время зависит от K и хэш-функции.
Например, если ключ представляет собой строку «abcd», то ее хеш-функция может зависеть от длины строки. Но для очень больших значений n количество записей в карте, длина ключей почти ничтожна по сравнению с n, поэтому можно считать, что вычисление хеш-функции происходит в постоянное время, то есть за O (1) . - На втором этапе необходимо выполнить обход списка пар KV, присутствующих в этом индексе. Для этого наихудший случай может заключаться в том, что все n записей имеют один и тот же индекс. Таким образом, временная сложность будет O (n) . Но было проведено достаточно исследований, чтобы заставить хэш-функции равномерно распределять ключи в массиве, поэтому этого почти никогда не происходит.
- Итак, в среднем , если имеется n записей, а b - размер массива, в каждом индексе будет n / b записей. Это значение n / b называется коэффициентом загрузки, который представляет нагрузку, которая присутствует на нашей карте.
- Этот коэффициент загрузки необходимо поддерживать на низком уровне, чтобы количество записей в одном индексе было меньше, а сложность была почти постоянной, т. Е. O (1).
Перефразируя:
Как следует из названия, повторное хеширование означает повторное хеширование . В основном, когда коэффициент нагрузки увеличивается до значения, превышающего его предварительно определенное значение (значение коэффициента нагрузки по умолчанию составляет 0,75), сложность возрастает. Таким образом, чтобы преодолеть это, размер массива увеличивается (удваивается), и все значения снова хешируются и сохраняются в новом массиве двойного размера, чтобы поддерживать низкий коэффициент загрузки и низкую сложность.
Зачем перефразировать?
Повторное хеширование выполняется, потому что всякий раз, когда пары ключ-значение вставляются в карту, коэффициент загрузки увеличивается, что означает, что временная сложность также увеличивается, как описано выше. Это может не дать требуемой временной сложности O (1).
Следовательно, необходимо выполнить повторное хеширование, увеличив размер bucketArray, чтобы уменьшить коэффициент загрузки и временную сложность.
Как делается перехеширование?
Rehashing can be done as follows:
- For each addition of a new entry to the map, check the load factor.
- If it’s greater than its pre-defined value (or default value of 0.75 if not given), then Rehash.
- For Rehash, make a new array of double the previous size and make it the new bucketarray.
- Then traverse to each element in the old bucketArray and call the insert() for each so as to insert it into the new larger bucket array.
Program to implement Rehashing:
// Java program to implement Rehashing import java.util.ArrayList; class Map<K, V> { class MapNode<K, V> { K key; V value; MapNode<K, V> next; public MapNode(K key, V value) { this .key = key; this .value = value; next = null ; } } // The bucket array where // the nodes containing K-V pairs are stored ArrayList<MapNode<K, V> > buckets; // No. of pairs stored - n int size; // Size of the bucketArray - b int numBuckets; // Default loadFactor final double DEFAULT_LOAD_FACTOR = 0.75 ; public Map() { numBuckets = 5 ; buckets = new ArrayList<>(numBuckets); for ( int i = 0 ; i < numBuckets; i++) { // Initialising to null buckets.add( null ); } System.out.println( "HashMap created" ); System.out.println( "Number of pairs in the Map: " + size); System.out.println( "Size of Map: " + numBuckets); System.out.println( "Default Load Factor : " + DEFAULT_LOAD_FACTOR + "
" ); } private int getBucketInd(K key) { // Using the inbuilt function from the object class int hashCode = key.hashCode(); // array index = hashCode%numBuckets return (hashCode % numBuckets); } public void insert(K key, V value) { // Getting the index at which it needs to be inserted int bucketInd = getBucketInd(key); // The first node at that index MapNode<K, V> head = buckets.get(bucketInd); // First, loop through all the nodes present at that index // to check if the key already exists while (head != null ) { // If already present the value is updated if (head.key.equals(key)) { head.value = value; return ; } head = head.next; } // new node with the K and V MapNode<K, V> newElementNode = new MapNode<K, V>(key, value); // The head node at the index head = buckets.get(bucketInd); // the new node is inserted // by making it the head // and it"s next is the previous head newElementNode.next = head; buckets.set(bucketInd, newElementNode); System.out.println( "Pair(" + key + ", " + value + ") inserted successfully.
" ); // Incrementing size // as new K-V pair is added to the map size++; // Load factor calculated double loadFactor = ( 1.0 * size) / numBuckets; System.out.println( "Current Load factor = " + loadFactor); // If the load factor is > 0.75, rehashing is done if (loadFactor > DEFAULT_LOAD_FACTOR) { System.out.println(loadFactor + " is greater than " + DEFAULT_LOAD_FACTOR); System.out.println( "Therefore Rehashing will be done.
" ); // Rehash rehash(); System.out.println( "New Size of Map: " + numBuckets + "
" ); } System.out.println( "Number of pairs in the Map: " + size); System.out.println( "Size of Map: " + numBuckets + "
" ); } private void rehash() { System.out.println( "
***Rehashing Started***
" ); // The present bucket list is made temp ArrayList<MapNode<K, V> > temp = buckets; // New bucketList of double the old size is created buckets = new ArrayList<MapNode<K, V> >( 2 * numBuckets); for ( int i = 0 ; i < 2 * numBuckets; i++) { // Initialised to null buckets.add( null ); } // Now size is made zero // and we loop through all the nodes in the original bucket list(temp) // and insert it into the new list size = 0 ; numBuckets *= 2 ; for ( int i = 0 ; i < temp.size(); i++) { // head of the chain at that index MapNode<K, V> head = temp.get(i); while (head != null ) { K key = head.key; V val = head.value; // calling the insert function for each node in temp // as the new list is now the bucketArray insert(key, val); head = head.next; } } System.out.println( "
***Rehashing Ended***
" ); } public void printMap() { // The present bucket list is made temp ArrayList<MapNode<K, V> > temp = buckets; System.out.println( "Current HashMap:" ); // loop through all the nodes and print them for ( int i = 0 ; i < temp.size(); i++) { // head of the chain at that index MapNode<K, V> head = temp.get(i); while (head != null ) { System.out.println( "key = " + head.key + ", val = " + head.value); head = head.next; } } System.out.println(); } } public class GFG { public static void main(String[] args) { // Creating the Map Map<Integer, String> map = new Map<Integer, String>(); // Inserting elements map.insert( 1 , "Geeks" ); map.printMap(); map.insert( 2 , "forGeeks" ); map.printMap(); map.insert( 3 , "A" ); map.printMap(); map.insert( 4 , "Computer" ); map.printMap(); map.insert( 5 , "Portal" ); map.printMap(); } } |
HashMap created Number of pairs in the Map: 0 Size of Map: 5 Default Load Factor : 0.75 Pair(1, Geeks) inserted successfully. Current Load factor = 0.2 Number of pairs in the Map: 1 Size of Map: 5 Current HashMap: key = 1, val = Geeks Pair(2, forGeeks) inserted successfully. Current Load factor = 0.4 Number of pairs in the Map: 2 Size of Map: 5 Current HashMap: key = 1, val = Geeks key = 2, val = forGeeks Pair(3, A) inserted successfully. Current Load factor = 0.6 Number of pairs in the Map: 3 Size of Map: 5 Current HashMap: key = 1, val = Geeks key = 2, val = forGeeks key = 3, val = A Pair(4, Computer) inserted successfully. Current Load factor = 0.8 0.8 is greater than 0.75 Therefore Rehashing will be done. ***Rehashing Started*** Pair(1, Geeks) inserted successfully. Current Load factor = 0.1 Number of pairs in the Map: 1 Size of Map: 10 Pair(2, forGeeks) inserted successfully. Current Load factor = 0.2 Number of pairs in the Map: 2 Size of Map: 10 Pair(3, A) inserted successfully. Current Load factor = 0.3 Number of pairs in the Map: 3 Size of Map: 10 Pair(4, Computer) inserted successfully. Current Load factor = 0.4 Number of pairs in the Map: 4 Size of Map: 10 ***Rehashing Ended*** New Size of Map: 10 Number of pairs in the Map: 4 Size of Map: 10 Current HashMap: key = 1, val = Geeks key = 2, val = forGeeks key = 3, val = A key = 4, val = Computer Pair(5, Portal) inserted successfully. Current Load factor = 0.5 Number of pairs in the Map: 5 Size of Map: 10 Current HashMap: key = 1, val = Geeks key = 2, val = forGeeks key = 3, val = A key = 4, val = Computer key = 5, val = Portal
Вниманию читателя! Не прекращайте учиться сейчас. Освойте все важные концепции DSA с помощью самостоятельного курса DSA по приемлемой для студентов цене и будьте готовы к работе в отрасли. Чтобы завершить подготовку от изучения языка к DS Algo и многому другому, см. Полный курс подготовки к собеседованию .
Если вы хотите посещать живые занятия с отраслевыми экспертами, пожалуйста, обращайтесь к Geeks Classes Live и Geeks Classes Live USA.