簡體   English   中英

如何為哈希表實現擦除功能?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM