(2011.08.18)散列表

本文介绍了散列表的基本概念,包括散列函数、冲突解决方法如分离链接法等,并提供了具体的代码实现示例。

    昨天看了数据结构中的散列的内容,将一些书上的代码敲了一下,加深记忆,当然,也对散列的大部分内容了解了一遍,知道它的原理大概是什么样的了。刚刚开始接触,看前几节的内容,还是很不理解这究竟是什么,散列函数用作什么用,后来,发觉,原来(只是个人理解)最大的作用是定位,找到相对应的位置,可以进行操作了,而,散列表也相当于是将一连串的类,用一个表放起来。

// 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);
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值