在哈希表中调整字符串数组的大小

时间:2019-05-21 04:56:01

标签: c++ hashtable

我正在学习哈希。我正在尝试填充大于等于80%的哈希表时调整其大小。但是每次我尝试调整大小时,都会出现不确定的行为,否则就会崩溃。

我试图用更多的字段创建一个新的String数组,然后删除了旧的数组,但这没用。

hashtable.h


class hashtable
{
    public:
        hashtable();
        void insert(string);
        void resize_array();
        int hashfunction(string str);
        string* getArray();

    private:
         int elemts_in_array;
         int table_size;
         string* T;
};

hashtable.cpp

hashtable::hashtable()
{
    // your code (start with a capacity of 10)
    table_size = 10;
    elemts_in_array = 0;
    string *array = new string[table_size];
    T = array;
}


void hashtable::insert(string key)
{
    string* array = getArray();
    int hkey=hashfunction(key);

    float filled = float(elemts_in_array)/float(table_size);
// When the array is more than 80% filled resize it and double the table_size
    if(filled >= 0.8)
    {
        cout << "Resizing Array.." << endl;
        resize_array();
    }
    for(int i=0; i<table_size;i++)
    {
// if the field is empty insert it, else go +1
        if(array[(hkey+i)%table_size] == "")
        {
            array[(hkey+i)%table_size] = key;
            elemts_in_array++;
            break;
        }
        if(array[(hkey+i)%table_size] == key)
        {
          // it is the same element
            break;
        }
    }
}


void hashtable::resize_array()
{
    int old_table_size =table_size;
    table_size*=2; // double the size of the hashtable
    string* old_array= new string[table_size]; // save the old array entries
    old_array = T;

// Apply the old entries in old_array
    for(int i=0; i<table_size;i++)
    {
        old_array[i]= T[i];
    }

//create a new array with double size
    string *new_array = new string[table_size];
//delete the old T
    delete[] T;
    T = new_array;

//re-hash the old entries into the new array with double size (HERE I GOT THE ISSUES)
    for(int i=0; i<table_size/2; i++)
    {
        insert(old_array[i]);
    }
}

有时我的程序进入循环或崩溃。我真的不知道为什么它不起作用。

2 个答案:

答案 0 :(得分:0)

如果使用调试器逐步执行程序,则可能会发现resize_array函数存在问题。

将旧表条目复制回新分配的数组时,它将使用insert函数。这有一些问题:

  1. 由于冲突解决,您可能无法获得与原始值相同的顺序;
  2. insert函数会增加表的大小,因此最终它会认为它的条目是最初插入的两倍。

现在,由于insert将再次达到表增加限制,因此可能发生崩溃。重复该循环,直到堆栈溢出或内存不足。

复制回字符串的正确方法是:

for(int i = 0; i < table_size / 2; i++)
{
    T[i] = old_array[i];
}

但是,还有另一个问题可能会在发生任何此类问题之前崩溃。您首先要像这样保存您的值:

for(int i=0; i<table_size;i++)
{
    old_array[i]= T[i];
}

请注意,table_size已被加倍,因此您将访问T末尾。您应该改为在old_table_size上循环。

您还可以进行一些不必要的复制。如果您要重新分配T,请执行以下操作:

void hashtable::resize_array()
{
    int old_table_size = table_size;
    table_size *= 2;

    string* old_T = T;
    T = new string[table_size];
    for (int i = 0; i < old_table_size; i++)
    {
        std::swap(T[i], old_T[i]);   // or in C++11 assign with std::move
    }
    delete[] old_T;
}

答案 1 :(得分:0)

哈希表扩展是关于使更多的插槽可用。但是哈希函数使用表大小来计算哈希索引。如果扩大表的大小,这意味着计算将发生变化,而不仅仅是表的将来条目。以及过去条目。

所以扩展算法是

  1. 确定新大小并创建该表(空)
  2. 使用新大小重新哈希所有条目,并将其从旧表移至新表。
  3. 删除旧表(现在(从概念上来说,现在是空的)。
  4. 新表成为 the 表。

就是这样。就是说,您的扩展算法已被打破。

int old_table_size =table_size;
table_size*=2; // double the size of the hashtable
string* old_array = new string[table_size]; // ???? This isn't needed
old_array = T; // ???? the memory allocated above was just leaked. 

然后再...

//create a new array with double size
string *new_array = new string[table_size];

//delete the old T
delete[] T;       // ??? old table destroyed, now old_array is pointing to ether
T = new_array;    // Finally some sanity returns, but old_array is still broken

最后...

for(int i=0; i<table_size/2; i++)
{
    insert(old_array[i]); // ???? old_array isn't valid anymore. BAD
}

这充满了问题。

适当调整大小

按照上面的任务列表,尝试以下操作:

void hashtable::resize_array()
{
    // remember the old table
    int old_table_size = table_size;
    std::string *old_array = T;

    // build the new table and reset counter
    table_size *= 2;
    T = new std::string[table_size];
    elemts_in_array = 0;

    // now bring the elements over
    for (int i=0; i<old_table_size; ++i)
    {
        if (old_array[i].empty())
            insert(old_array[i]);
    }

    // finally, throw out old array
    delete[] old_array;
}

就是这样。您可以通过使用一个insert方法来获取一个rvalue-reference并使用std::move来转发字符串而不直接从旧数组中复制出来,从而大大提高效率,但是算法的基础是什么我们正在为这里拍摄,我希望能成功。