我正在学习哈希。我正在尝试填充大于等于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]);
}
}
有时我的程序进入循环或崩溃。我真的不知道为什么它不起作用。
答案 0 :(得分:0)
如果使用调试器逐步执行程序,则可能会发现resize_array
函数存在问题。
将旧表条目复制回新分配的数组时,它将使用insert
函数。这有一些问题:
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)
哈希表扩展是关于使更多的插槽可用。但是哈希函数使用表大小来计算哈希索引。如果扩大表的大小,这意味着计算将发生变化,而不仅仅是表的将来条目。以及过去条目。
所以扩展算法是
就是这样。就是说,您的扩展算法已被打破。
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
来转发字符串而不直接从旧数组中复制出来,从而大大提高效率,但是算法的基础是什么我们正在为这里拍摄,我希望能成功。