哈希表 - 找重复数字、字符(不限制内存)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| #include<iostream> #include<vector> #include<ctime> #include<unordered_set> #include<unordered_map> using namespace std; int main() { vector<int> vec; srand(time(NULL)); for(int i = 0; i < 1000; ++i) { vec.push_back(rand() % 100); } unordered_set<int> set1; int count = 0; for(const auto & key : vec) { const auto it = set1.find(key); if (it == set1.end()) { set1.insert(key); } else { cout << "重复的数字是" << key << endl; ++count; } } std::cout << "总共重复了" << count << "个数" << endl; unordered_map<int, int> map1; for(const auto & key : vec) { const auto it = map1.find(key); if (it == map1.end()) { map1.emplace(key, 1); } else { ++it->second; } } for(const auto & pair : map1) { if(pair.second > 1) { cout << "数字" << pair.first << "重复" << pair.second << "次" << endl; } } unordered_set<int> set2; for(const auto & key : vec) { set2.emplace(key); } bool haveDuplicate = false; string str = "fgodgnffinogiofdngps"; unordered_map<char, int> map2; for(const auto & key : str) { ++map2[key]; } for(const auto & key : str) { if (map2[key] == 1) { haveDuplicate = true; cout << "第一个不重复的字符为" << key << endl; break; } } if (!haveDuplicate) { cout << "所有字符都重复" << endl; } }
|
哈希表分桶 - 两个大文件,找重复内容(适当限制内存)
有两个文件分别是a和b,各自存放了1亿条IP地址,限制内存100MB,找出两个文件中重复的ip地址。
总体思路是,把一个文件的内容输入到哈希表中,遍历另一个文件中的每一条IP地址,与哈希表中的key比对。因此只需要提供1个文件的内存占用即可。
IPv4地址的大小是4个字节。1亿是100M,则1亿条IP地址就是400MB。如果再加上unordered_map结构的地址域,那就要再翻倍,把一个文件输入到哈希表中就要占800MB内存。这显然是超出了100MB的要求。
可以这样:文件a的IP地址依次读取,取模(或者称之为哈希函数),比如%11
,这样把他们都分散到11个“桶”里。
把文件b也像这样,挨个IP地址取模,在a的相应的“桶”号下,去寻找。因为如果IP地址一样,用了相同的取模运算(哈希运算),所以是在同一个桶号里。
这样,就把1亿个IP地址分成了11波。内存压力减少到了80MB。
位数组 - (小内存)
如果数据集中的最大值很大,那么中间有好多无效的空位被浪费。总体上还是浪费内存的。
Bloom Filter 布隆过滤器 - (极限内存)
结合了哈希+位数组的优势。内存使用效率高。