У меня есть хэш-таблица с использованием линейного зондирования. Мне дали задание написать erase(int key)
функционировать со следующими рекомендациями.
void erase(int key); Preconditions: key >= 0 Postconditions: If a record with the specified key exists in the table, then that record has been removed; otherwise the table is unchanged.
Мне также дали несколько советов для выполнения задачи
Важно понимать, что функция вставки позволит вам добавить новую запись в таблицу или обновить существующую запись в таблице.
Для версии с линейным зондированием обратите внимание, что код для вставки
пункт имеет два поиска. Функция insert () вызывает функцию
findIndex () для поиска в таблице, чтобы увидеть, если элемент уже находится в
Таблица. Если элемент отсутствует в таблице, выполняется второй поиск
найдите позицию в таблице, чтобы вставить предмет. Добавление способности
для удаления записи потребуется, чтобы процесс вставки
модифицирована. При поиске существующего элемента убедитесь, что
поиск не останавливается, когда дело доходит до места, которое было занято
но теперь пусто, потому что элемент был удален. При поиске
положение, чтобы вставить новый элемент, используйте первую пустую позицию — это делает
не имеет значения, была ли должность когда-либо занята или нет.
Итак, я начал писать erase (ключ) и, похоже, столкнулся с проблемой, на которую ссылаются подсказки, но я не уверен, что это значит. Я предоставлю код через секунду, но то, что я сделал для проверки своего кода, настроил хеш-таблицу так, чтобы она имела коллизию, а затем я стираю этот ключ и перефразирую таблицу, но она не входит в правильное местоположение.
Например, я добавляю несколько элементов в мою хеш-таблицу:
The hash table is:
Index Key Data
0 31 3100
1 1 100
2 2 200
3 -1
4 -1
5 -1
6 -1
7 -1
8 -1
9 -1
10 -1
11 -1
12 -1
13 -1
14 -1
15 -1
16 -1
17 -1
18 -1
19 -1
20 -1
21 -1
22 -1
23 -1
24 -1
25 -1
26 -1
27 -1
28 -1
29 -1
30 -1
Таким образом, все мои значения пусты, кроме первых 3 индексов. Очевидно, что ключ 31 должен входить в индекс 1. Но так как ключ 1 уже существует, он сталкивается и устанавливается для индекса 0. Затем я стираю ключ 1 и перефразирую таблицу, но ключ 31 остается с индексом 0.
Вот функции, на которые стоит обратить внимание:
void Table::insert( const RecordType& entry )
{
bool alreadyThere;
int index;
assert( entry.key >= 0 );
findIndex( entry.key, alreadyThere, index );
if( alreadyThere )
table[index] = entry;
else
{
assert( size( ) < CAPACITY );
index = hash( entry.key );
while ( table[index].key != -1 )
index = ( index + 1 ) % CAPACITY;
table[index] = entry;
used++;
}
}
Поскольку insert использует findIndex, я также включу это
void Table::findIndex( int key, bool& found, int& i ) const
{
int count = 0;
assert( key >=0 );
i = hash( key );
while ( count < CAPACITY && table[i].key != -1 && table[i].key != key )
{
count++;
i = (i + 1) % CAPACITY;
}
found = table[i].key == key;
}
И вот мой текущий старт на стирание
void Table::erase(int key)
{
assert(key >= 0);
bool found, rehashFound;
int index, rehashIndex;
//check if key is in table
findIndex(key, found, index);
//if key is found, remove it
if(found)
{
//remove key at position
table[index].key = -1;
table[index].data = NULL;
cout << "Found key and removed it" << endl;
//reduce the number of used keys
used--;
//rehash the table
for(int i = 0; i < CAPACITY; i++)
{
if(table[i].key != -1)
{
cout << "Rehashing key : " << table[i].key << endl;
findIndex(table[i].key, rehashFound, rehashIndex);
cout << "Rehashed to index : " << rehashIndex << endl;
table[rehashIndex].key = table[i].key;
table[rehashIndex].data = table[i].data;
}
}
}
}
Может кто-нибудь объяснить, что мне нужно сделать, чтобы перефразировать правильно? Я понимаю концепцию хеш-таблицы, но, похоже, я здесь что-то не так делаю.
РЕДАКТИРОВАТЬ
Согласно предложению пользователя:
void Table::erase(int key)
{
assert(key >= 0);
bool found;
int index;
findIndex(key, found, index);
if(found)
{
table[index].key = -2;
table[index].data = NULL;
used--;
}
}//modify insert(const RecordType & entry)
while(table[index].key != -1 || table[index].key != -2)//modify findIndex
while(count < CAPACITY && table[i].key != -1
&& table[i].key != -2 && table[i].key != key)
При удалении предмета из таблицы ничего не перемещайте. Просто вставьте туда «удаленный» маркер. При вставке обрабатывайте маркеры удаления как пустые и доступные для новых элементов. При поиске относитесь к ним как к занятым и продолжайте проверять, попали ли вы в них. При изменении размера таблицы игнорируйте маркеры.
Обратите внимание, что это может вызвать проблемы, если размер таблицы никогда не изменяется. Если размер таблицы никогда не будет изменен, через некоторое время в вашей таблице не будет записей, помеченных как никогда не используемые, и производительность поиска пойдет в ад. Поскольку в подсказках упоминается отслеживание того, использовалась ли когда-либо пустая позиция, и обращение с некогда использованными ячейками иначе, чем с никогда не использовавшимися, я считаю, что это и есть предполагаемое решение. Предположительно, изменение размера таблицы будет более поздним заданием.
Нет необходимости перефразировать всю таблицу каждый раз, когда выполняется удаление. Если вы хотите минимизировать снижение производительности, вы можете сжать таблицу, учитывая, был ли какой-либо из элементов после (с разрешенным переносом с конца на фронт) удаленного элемента, но до следующего хэша -1 в корзину в или перед удаленным element — если так, то их можно переместить в или хотя бы ближе к их хэш-корзине, затем вы можете повторить процесс сжатия для только что перемещенного элемента.
Уплотнение такого типа удалит самый большой недостаток в вашем текущем коде, который заключается в том, что после небольшого использования каждый сегмент будет помечен как используемый или использованный, а производительность, например, будет равна. поиск несуществующего значения будет ухудшаться до O (CAPACITY).
С головы до головы без компилятора / тестирования …
int Table::next(int index) const
{
return (index + 1) % CAPACITY;
}
int Table::distance(int from, int to) const
{
return from < to ? to - from : to + CAPACITY - from;
}
void Table::erase(int key)
{
assert(key >= 0);
bool found;
int index;
findIndex(key, found, index);
if (found)
{
// compaction...
int limit = CAPACITY - 1;
for (int compact_from = next(index);
limit-- && table[compact_from].key >= 0;
compact_from = next(compact_from))
{
int ideal = hash(table[compact_from].key);
if (distance(ideal, index) <
distance(ideal, compact_from))
{
table[index] = table[compact_from];
index = compact_from;
}
}
// deletion
table[index].key = -1;
delete table[index].data; // or your = NULL if not a leak? ;-.
--used;
}
}