删除,插入,查找是对数据的最基本且最常用的操作,这几种操作的效率往往极大的影响着我们的程序的效率,当然,有很多数据结构都对这些操作提供了基本的支持,不过效率却大不相同,如向量表的查找效率是O(1),但插入与删除为O(n)的,链表相反,查找效率是O(n),但插入与删除为O(1)的,而二叉查找树对三种操作都为O(lgn)。
但却有一种数据结构很神奇,他对三种操作的效率都是O(1)的,这种结构就是散列,散列可以认为是对输入空间的一个压缩形成一个散列表!但遗憾的是要做好一个散列表我们往往要找到一个散列函数,而寻找好的散列函数往往只能称作一种艺术,很难有什么好的理论支撑。尽管如此,散列在我们的生活中的应用还是极其的广泛!
例如,我们知道,基于比较的排序最好的效率是O(nlogn)的,平常我们用的快排,堆排就是如此。但如果我们是对一定范围内的数据进行排序,例如1000以内,这是我们就用散列的思想就能达到O(n)的效率!
虽然寻找散列函数十分的困难,但直接取余是比较通用的办法,通常是对一个素数进行取余,不过还是无法避免冲突的情况,这时一般用分离链接法来解决,下面就是我写的一个利用分离链接法来实现的散列:
//hash.h
#ifndef HASH_H
#define HASH_H
#include<iostream>
using namespace std;
#include<vector>
#include<list>
class Hashtable
{
private:
vector<list<int> > hs;
int size;
public:
Hashtable(int thesize=101){ hs.resize(thesize) ;size=0;}
void insert(int &x)
{
if(size==hs.size())
{
return;
}
list<int> &L=hs[hash(x)];
list<int>::iterator it;
for(it=L.begin();it!=L.end();it++)
if(*it==x)
break;
if(it==L.end())
{
if(L.empty())
size++;
L.push_back(x);
}
}
void remove(int &x)
{
list<int> &L=hs[hash(x)];
list<int>::iterator it;
for(it=L.begin();it!=L.end();it++)
if(*it==x)
break;
if(it!=L.end())
{
L.erase(it);
if(L.empty())
size--;
}
}
bool contains(int &x)
{
list<int> &L=hs[hash(x)];
list<int>::iterator it;
for(it=L.begin();it!=L.end();it++)
if(*it==x)
break;
if(it!=L.end())
return true;
return false;
}
int hash(int x)
{
int hashvalue=x%hs.size();
return hashvalue;
}
};
#endif