[英]How do I implement an erase function for a hash table?
我有一個使用線性探測的哈希表。 我已經得到了按照以下准則編寫一個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()來搜索表以查看該項是否已在表中。 如果該項目不在表格中,則進行第二次搜索以找到表格中要插入該項目的位置。 添加刪除條目的功能將需要修改插入過程。 當搜索現有項目時,請確保當涉及到已被占用但由於已刪除該項目而現在為空的位置時,搜索不會停止。 搜索要插入新項目的職位時,請使用第一個空職位-職位是否曾被占用都沒有關系。
因此,我已經開始編寫“ ease(key)”,並且似乎遇到了提示所指的問題,但是我並不肯定這是什么意思。 我將在稍后提供代碼,但是我為測試代碼所做的工作是設置哈希表,以使其具有沖突,然后擦除該鍵並重新哈希表,但該表不會正確的位置。
例如,我在哈希表中添加了一些元素:
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
因此,除了前三個索引外,我所有的值都是空的。 顯然,鍵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哈希到存儲桶之前的任何元素來壓縮表元素-如果是這樣,則可以將其移至或至少靠近其哈希存儲桶,然后可以對剛剛移動的元素重復壓縮過程。
進行這種壓縮將消除當前代碼中的最大缺陷,即在少量使用后,每個存儲桶都將被標記為正在使用或已被使用,例如查找不存在的值的性能將降級為O(容量)。
沒有編譯器/測試的煩惱...
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;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.