Изменение размера массива для хэш-картыJAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Изменение размера массива для хэш-карты

Сообщение Anonymous »

У меня возникли проблемы с изменением размера массива хэш-карты для аппаратного назначения структур данных и алгоритмов. Вот инструкции:

Если добавление в таблицу приведет к превышению коэффициента нагрузки (LF) (т. е. больше, не больше или равно) константу максимального коэффициента загрузки, указанную в файле Java, размер таблицы следует изменить, чтобы она имела емкость 2n + 1.

Я пытаюсь изменить его размер до 2n+1, где n — исходный размер массива. Но почему-то это не работает? Всякий раз, когда я тестирую это, размер массива никогда не изменяется так, как я хочу.
Я считаю, что проблема может заключаться в одном из этих фрагментов кода:
  • Размещение вызываемого метода внутри метода put:

    Код: Выделить всё

    if ((countEntries(table)) / table.length > MAX_LOAD_FACTOR) {
    resizeBackingTable(table.length);
    }
    
  • Или код внутри самого метода resizeBackingTable.

    Код: Выделить всё

    private void resizeBackingTable(int length) {
    // WRITE YOUR CODE HERE (DO NOT MODIFY METHOD HEADER)!
    ExternalChainingMapEntry[] newBackingArray = (ExternalChainingMapEntry[]) new ExternalChainingMapEntry[2 * length + 1];
    
    for (ExternalChainingMapEntry entry : table) {
    while (entry != null) {
    int hash = calculateHash(entry.getKey(), newBackingArray.length);
    
    ExternalChainingMapEntry next = entry.getNext();
    
    entry.setNext(newBackingArray[hash]);
    newBackingArray[hash] = entry;
    
    entry = next;
    }
    }
    table = newBackingArray;
    }
    
Вот весь код, извините, если он выглядит беспорядочным.

Код: Выделить всё

import java.util.NoSuchElementException;

/**
* Your implementation of a ExternalChainingHashMap.
*/
public class ExternalChainingHashMap {

/*
* The initial capacity of the ExternalChainingHashMap when created with the
* default constructor.
*
* DO NOT MODIFY THIS VARIABLE!
*/
public static final int INITIAL_CAPACITY = 13;

/*
* The max load factor of the ExternalChainingHashMap.
*
* DO NOT MODIFY THIS VARIABLE!
*/
public static final double MAX_LOAD_FACTOR = 0.67;

/*
* Do not add new instance variables or modify existing ones.
*/
private ExternalChainingMapEntry[] table;
private int size;

/**
* Constructs a new ExternalChainingHashMap with an initial capacity of INITIAL_CAPACITY.
*/
public ExternalChainingHashMap() {
//DO NOT MODIFY THIS METHOD!
table = (ExternalChainingMapEntry[]) new ExternalChainingMapEntry[INITIAL_CAPACITY];
}

/**
* Adds the given key-value pair to the map. If an entry in the map
* already has this key, replace the entry's value with the new one
* passed in.
*
* In the case of a collision, use external chaining as your resolution
* strategy. Add new entries to the front of an existing chain, but don't
* forget to check the entire chain for duplicate keys first.
*
* If you find a duplicate key, then replace the entry's value with the new
* one passed in. When replacing the old value, replace it at that position
* in the chain, not by creating a new entry and adding it to the front.
*
* Before actually adding any data to the HashMap, you should check to
* see if the table would violate the max load factor if the data was
* added. Resize if the load factor (LF) is greater than max LF (it is
* okay if the load factor is equal to max LF). For example, let's say
* the table is of length 5 and the current size is 3 (LF = 0.6). For
* this example, assume that no elements are removed in between steps.
* If another entry is attempted to be added, before doing anything else,
* you should check whether (3 + 1) / 5 = 0.8 is larger than the max LF.
* It is, so you would trigger a resize before you even attempt to add
* the data or figure out if it's a duplicate. Be careful to consider the
* differences between integer and double division when calculating load
* factor.
*
* When regrowing, resize the length of the backing table to
* (2 * old length) + 1. You should use the resizeBackingTable method to do so.
*
* @param key   The key to add.
* @param value The value to add.
* @return null if the key was not already in the map.  If it was in the
*         map, return the old value associated with it.
* @throws java.lang.IllegalArgumentException If key or value is null.
*/
public V put(K key, V value) {
// WRITE YOUR CODE HERE (DO NOT MODIFY METHOD HEADER)!

int hash = calculateHash(key, table.length);

// Create a new node with the new key-value pair
ExternalChainingMapEntry newNode = new ExternalChainingMapEntry(key, value);

// Check if the linked list at the given index is null
if (table[hash] == null) {
// If it's null, instantiate a new ExternalChainingMapEntry to represent the head
table[hash] = newNode;
size++;

if ((countEntries(table)) / table.length > MAX_LOAD_FACTOR) {
resizeBackingTable(table.length);
}
return null;
}

// Search through the linked list to find if the key already exists
ExternalChainingMapEntry current = table[hash];
while (current != null) {
if (current.getKey().equals(key)) {
// If the key already exists, replace the old value with the new value
current.setValue(value);
return null; // Key found and replaced, exit the entire method
}
current = current.getNext();
}

// Sets the "next" reference of the newNode to be the current head of the linked list at the specified index (table[hash]).
// It's saying, "the next element after this new node is the current head of the list."
// This way, you are linking the new node to the existing elements in the list.
newNode.setNext(table[hash]);

// Set the new node as the new head of the linked list at the specified index
table[hash] = newNode;
size++;
if ((countEntries(table)) / table.length > MAX_LOAD_FACTOR) {
resizeBackingTable(table.length);
}
return null;
}

/**
* Removes the entry with a matching key from the map.
*
* @param key The key to remove.
* @return The value associated with the key.
* @throws java.lang.IllegalArgumentException If key is null.
* @throws java.util.NoSuchElementException   If the key is not in the map.
*/
public V remove(K key) {
// WRITE YOUR CODE HERE (DO NOT MODIFY METHOD HEADER)!
if (key == null) {
throw new IllegalArgumentException("Error: key is null");
}

int hash = calculateHash(key, table.length);

if(table[hash] == null) {
throw new NoSuchElementException("Error: entry is empty");
}

ExternalChainingMapEntry current = table[hash];
ExternalChainingMapEntry prev = null;

while (current != null && !current.getKey().equals(key)) {
prev = current;
current = current.getNext();
}

if (current == null) {
throw new NoSuchElementException("Error: key not found");
}

V removedValue = current.getValue();

if (prev == null) {
// If the entry to be removed is the head of the linked list
table[hash] = current.getNext();
} else {
// If the entry to be removed is not the head of the linked list
prev.setNext(current.getNext());
}

size--;  // Decrement size when removing an entry

return removedValue;
}

/**
* Helper method stub for resizing the backing table to length.
*
* This method should be called in put() if the backing table needs to
* be resized.
*
* You should iterate over the old table in order of increasing hash and
* add entries to the new table in the order in which they are traversed.
*
* Since resizing the backing table is working with the non-duplicate
* data already in the table, you won't need to explicitly check for
* duplicates.
*
* Hint: You cannot just simply copy the entries over to the new table.
*
* @param Length The new length of the backing table.
*/
private void resizeBackingTable(int length) {
// WRITE YOUR CODE HERE (DO NOT MODIFY METHOD HEADER)!
ExternalChainingMapEntry[] newBackingArray = (ExternalChainingMapEntry[]) new ExternalChainingMapEntry[2 * length + 1];

for (ExternalChainingMapEntry entry : table) {
while (entry != null) {
int hash = calculateHash(entry.getKey(), newBackingArray.length);

ExternalChainingMapEntry next = entry.getNext();

entry.setNext(newBackingArray[hash]);
newBackingArray[hash] = entry;

entry = next;
}
}
table = newBackingArray;
}

//The hash function
private int calculateHash(K key, int array) {
if (key == null) {
throw new IllegalArgumentException("Error: key is null");
}

int hash = Math.abs(key.hashCode() % array);
return hash;
}

//Counts number of non-null entries in an array
private int countEntries(ExternalChainingMapEntry[] table) {
int count = 0;
for (int i = 0; i < table.length; i++) {
if (table[i] != null) {
count++;
}
}
return count;
}

/**
* Returns the table of the map.
*
* For grading purposes only. You shouldn't need to use this method since
* you have direct access to the variable.
*
* @return The table of the map.
*/
public ExternalChainingMapEntry[] getTable() {
// DO NOT MODIFY THIS METHOD!
return table;
}

/**
* Returns the size of the map.
*
* For grading purposes only. You shouldn't need to use this method since
* you have direct access to the variable.
*
* @return The size of the map.
*/

public int size() {
// DO NOT MODIFY THIS METHOD!
return size;
}
}
Я пробовал вызывать resizeBackingTable в разных местах, но, похоже, это не дало эффекта. Я уже поместил его в самое начало метода put, но это тоже не дало эффекта.

Подробнее здесь: https://stackoverflow.com/questions/779 ... a-hash-map
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»