705. Design HashSet

仅供自己学习

 

思路:

主要还是去重和冲突的解决。

可以直接开个很大的数组直接存放即可,用下标代表为什么数,该位置的值用0和1来判断是否存放了。

还有一种的散列表,如果这个位置存放了那就+1,+2这样找到下一个没有冲突的位置

还有一个就是每个数组的位置都有一个链表。

 

如果使用链表,对于数组的大小我们使用一个固定长度,且为质数,原因是:

查了下质数取模,其实是利用了同余的感念:当元素是个有规律的等差数列时,并且和基数(数组大小)最大公约数不为1时,就会造成哈希映射时冲突变高(数组某些位置永远不会有值)。比如数列0,6,12,18,24...,

  • base为10,取模放入哈希表中位置将只能在0,2,4,6,8这几个数组位置上
  • 但我们如果把base取7(数组大小甚至比10小),同样数列可以分布在哈希表中的0,1,2,3,4,5,6

可以使得哈希表中每个位置都“有用武之地”

 

然后其他功能每个都要用key值mod数组的固定长度后得到的数就是存放数组的哪个位置,然后遍历该位置的链表,对于add,如果没有相同的元素,那么就直接加载后面,对于remove如果发现有就erase,对于contain如果有就返回true

代码:

 1 class MyHashSet {
 2 private:
 3     vector<list<int>> data;
 4     static const int base=769;
 5     static int hash(int key){
 6         return key%base;
 7     }
 8 public:
 9     /** Initialize your data structure here. */
10     MyHashSet(): data(base){}
11     
12     void add(int key) {
13         int h=hash(key);
14         for(auto a=data[h].begin();a!=data[h].end();++a){
15             if(*a==key)
16                 return;
17         }
18         data[h].push_back(key);
19     }
20     
21     void remove(int key) {
22         int h=hash(key);
23         for(auto a=data[h].begin();a!=data[h].end();++a){
24             if(*a==key){
25                 data[h].erase(a);
26                 return;
27             }
28         }
29     }
30     
31     /** Returns true if this set contains the specified element */
32     bool contains(int key) {
33         int h=hash(key);
34         for(auto a=data[h].begin();a!=data[h].end();++a){
35             if(*a==key)
36                 return true;
37         }
38         return false;
39     }
40 };
41 
42 /**
43  * Your MyHashSet object will be instantiated and called as such:
44  * MyHashSet* obj = new MyHashSet();
45  * obj->add(key);
46  * obj->remove(key);
47  * bool param_3 = obj->contains(key);
48  */

 

posted @ 2021-03-13 13:36  Mrsdwang  阅读(75)  评论(0)    收藏  举报