您的位置:首页 > 其它

HashTable和HashMap

2015-12-20 22:19 176 查看
在平常的应用中,经常遇到一些需要查询某个元素的情况,一般来说就有3种不同复杂度的做法:

把元素简单放进线性表中,这样每次查询需要遍历一遍线性表,复杂度是O(n)的

把元素放进平衡树中,这样每次查询复杂度是O(logn)的

把元素放进hash表中,这样查询的均摊复杂度变为O(1)

实际应用中一般不采用1,而采用2和3。平衡树的优点是查询稳定,缺点是查询次数多时较慢;hash表的优点是查询的平均时间短,缺点是某几次查询可能比较慢。具体根据实际情况来选择。

3种方法的原理比较:

一般线性表,所有元素分布在一条链上,通过遍历这条链来查询元素

平衡树,二分搜索的基本思想以及维护平衡性质来限制深度保证O(logn)的复杂度

hash表,改进普通线性表的存储方式,使用某种分配机制使得元素尽量分布于不同的链上,从而只需遍历元素所在链即可。

HashTable的实现:

利用邻接表,然后设计一个散列函数,就可以得到HashTable的一个实现。散列函数的好坏决定了hash表的好坏。我这里选择对质数取模作为散列函数(选择非质数确实效率要下降不少)。

HashMap的实现:

有了HashTable,HashMap就不难了。HashMap相当于键的HashTable,再另外加上值的一个线性表,然后让地址对应起来即可,即可以由键来得到存对应值的地址。

实现得比较粗糙,将就着用吧~

template<typename T, int N, int SZ>
struct HashTable {
T table[SZ];
int nxt[SZ];
int last
;
int total;
HashTable(){ clear(); }
void clear() { mset(last, -1); total = 0; }
int add(T x) {
int pos = getMod(x);
table[total] = x;
nxt[total] = last[pos];
last[pos] = total ++;
return total - 1;
}
int find(T x) {
int pos = getMod(x), i = last[pos];
for (; ~i; i = nxt[i]) {
if (table[i] == x) break;
}
return i;
}
int getMod(string x) {
int n = x.length(), mm = 0;
up(i, n) {
mm = (mm * 128 + x[i]) % N;
}
return mm;
}
inline int getMod(ll x) {
return x % N;
}
};
template<typename T, typename T2, int N, int SZ>
struct HashMap {
HashTable<T, N, SZ> ht;
T2 b[SZ];
HashMap() { clear(); }
void clear() { ht.clear(); up(i, SZ) b[i]=T2(); }
void insert(pair<T, T2> p) {
b[ht.add(p.first)] = p.second;
}
int find(T key) {
return ht.find(key);
}
T2 get(T key) {
return b[ht.find(key)];
}
T2& operator[] (T key) {
int ac = find(key);
if (~ac) return b[ac];
else return b[ht.add(key)];
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: