昨天看了数据结构中的散列的内容,将一些书上的代码敲了一下,加深记忆,当然,也对散列的大部分内容了解了一遍,知道它的原理大概是什么样的了。刚刚开始接触,看前几节的内容,还是很不理解这究竟是什么,散列函数用作什么用,后来,发觉,原来(只是个人理解)最大的作用是定位,找到相对应的位置,可以进行操作了,而,散列表也相当于是将一连串的类,用一个表放起来。
// 504 散列
/**
* 散列:是一种用于常数平均时间执行的插入、删除和查找的技术。
* 键(Key):查找一般是对项的某个部分(即数据成员)进行的。
* 散列函数:将每个键映射到0到TableSize - 1这个范围中的某个数,并将其放到适当的单元中。
* 冲突(collision):决定当两个键列到同一个值的时候。
* 分离链接法(separate chaining):将散列到同一个值的所有元素保留到第一个链表中。
* 可扩散列(extendible hashing):处理数据量太大以至于装不进主存的情况。
**/
// 分离链接法 -- 缺点:给新单元分配地址需要时间,导致算法的速度有点慢。
// ( 并非一个完整代码)
template <typename HashedObj>
class HashTable
{
public:
// 散列大小一般设为素数
explicit HashTable(int size = 101);
bool contains(const HashedObj & x) const;
void makeEmpty();
void insert(const HashedObj & x);
void remove(const HashedObj & x);
private:
vector < list<HashedObj> > theLists; // The array of Lists
int currentSize;
void rehash();
int myhash( const HashedObj & x) const;
};
int hash(const string & key);
int hash( int key);
/**
* A hash routine for string objects.
*/
int hash( const string & key, int tableSize)
{
int hashVal = 0;
for (int i = 0; i < key. length(); i++)
hasVal = 37 * hashVal + key[i];
hashVal %= tableSize;
if (hashVal < 0)
hashVal += tableSize;
return hashVal;
}
int myhash(const HashedObj & x) const
{
int hashVal = hash(x);
hashVal %= theLists.size();
if (hashVal < 0)
hashVal += theLists.size();
return hashVal;
}
void makeEmpty()
{
for (int i = 0; i < theLists.size(); i++)
theLists[i].clear();
}
bool contains(const HashedObj & x) const
{
const list<HashedObj> & whichList = theLists[myhash(x)];
return find(whichList.begin(), whichList.end(), x) != whichList.end();
}
bool remove(const HashedObj & x)
{
list <HashedObj> & whichList = theLists[myhash(x)];
list<HashedObj>:: iterator itr = find(whichList.begin(), whichList.end(), x);
if (itr == whichList.end())
return false;
whichList.erase(itr);
--currentSize;
return true;
}
bool insert (const HashedObj & x)
{
list<HashedObj> & whichList = theLists[myhash(x)];
if(find(whichList.begin(), whichList.end(), x) != whichList.end() )
return false;
whichList.push_back(x);
if (++currentSize > theLists.size() )
rehash();
return true;
}
void rehash()
{
vector<list<HashedObj> > oldLists = theLists;
// Create new double-sized, empty table
theLists.resize(nextPrime( 2 * theLists.size() ) );
for (int j = 0; j < theLists.size(); j++)
theLists[j].clear();
// copy table over
currentSize = 0;
for (int i = 0; i < oldLists.size(); ++i)
{
list<HashedObj>::iterator itr = oldLists[i].begin();
while( itr!= oldLists[i].end())
insert(*itr++);
}
return;
}
// 使用探测策略的散列表的类接口
template< typename HashedObj>
class HashTable
{
public:
explicit HashTable(int size = 101);
bool contains(const HashedObj & x) const;
void makeEmpty();
bool insert( const HashedObj & x);
bool remove(const HashedObj & x);
enum EntryType { ACTIVE, EMPTY, DELETED);
private:
struct HashEntry
{
HashedObj element;
EntryType info;
HashEntry(const HashedObj & e = HashedObj(), EntryType i = EMPTY)
: element(e), info(i){}
};
vector<HashEntry>array;
int currentSize;
bool isActive(int currentPos) const;
int findPos(const HashedObj & x)const;
void rehash();
int myhash(const HashedObj & x) const;
};
int hash( const string & key, int tableSize)
{
int hashVal = 0;
for (int i = 0; i < key.length(); i++)
hashVal = 37 * hashVal + key[i];
hashVal %= tableSize;
if (hashVal < 0)
hashVal += tableSize;
return hashVal;
}
explicit HashTable(int size = 101): array(nextPrime(size))
{ makeEmpty();}
void makeEmpty()
{
currentSize = 0;
for (int i = 0; i < array.size(); i++)
array[i].info = EMPTY;
}
bool contains(const HashedObj & x) const
{ return isActive(findPos(x) );}
int findPos( const HashedObj & x) const
{
int offset = 1;
int currentPos = myhash(x);
while(array[currentPos].info != EMPTY && array[currentPos].element != x)
{
currentPos += offset; // Compute ith probe
offset += 2;
if (currentPos >= array.size())
currentPos -= array.size();
}
return currentPos;
}
bool isActive( int currentPos) const
{ return array[currentPos].info == ACTIVE; }
bool insert(const HashedObj & x)
{
// Insert x as active
int currentPos = findPos(x);
if (isActive(currentPos) )
return false;
array[currentPos] = HashEntry(x, ACTIVE);
if ( ++currentSize > array.size() / 2)
rehash();
return true;
}
bool remove(const HashedObj & x)
{
int currentPos = findPos(x);
if (!is Active(currentPos) )
return false;
array[currentPos].info = DELETD;
return true;
}
void rehash()
{
vector < HashEntry> oldArray = array;
// create new double-sized, empty table
array.resize(nextPrime(2 * oldArray.size() ) );
for ( int i = 0; i < oldArray.size(); i++ )
if (oldArray[i].info == ACTIVE)
insert(oldArray[i].element);
}
本文介绍了散列表的基本概念,包括散列函数、冲突解决方法如分离链接法等,并提供了具体的代码实现示例。

971

被折叠的 条评论
为什么被折叠?



