9月7号下午写题(The Preliminary Contest for ICPC Asia Xuzhou 2019)遇到这个so easy ,我用了map写一直超时,想了底层map的查找没有hash_map快,然后就用了hash_map也超时了,后来看题解是用的unordered_map可以过。就让我疯狂测试了一波什么情况下超时。(????9月8号我又测试了一波,发现!!!!????我昨天比赛交的超时代码也能在oj上过了??我???????【小小的脸上大大的疑惑???】)
9月7号的测试结果让我以为:
!List.count(x) 和 !List[x] ,List[x]==0的效率不一样 。因为我测试了一下。后两者都超时了。
理一下吧测试结果:
unordered_map : !List.count(x) WA? !List[x] AC(3)/TLE(3) List[x]==0 AC(3)/TLE(4)
hash_map : !List.count(x) WA? !List[x] AC(4) List[x]==0 AC(4)
map: !List.count(x) WA? !List[x] TLE(1) List[x]==0 TLE(1)
使用的模板是下面一套:(也是我比赛时候交的写法!!!一毛一样 ,我测的时候改的只有hash_map 和unordered_map,然后条件改改) 今天测我超时的写法四次都过了,我比赛的时候是什么“好运气”,不过测过来还真的看运气。
#include<map>
#include<cstring>
#include<iostream>
#include<cstdio>
#include<unordered_map>
#include<ext/hash_map>
using namespace std;
using namespace __gnu_cxx;
namespace __gnu_cxx
{
template<> struct hash< std::string >
{
size_t operator()( const std::string& x ) const
{
return hash< const char* >()( x.c_str() );
}
};
template<> struct hash<long long>
{
size_t operator()(long long x) const
{
return x;
}
};
};
hash_map<int,int> List;
int find(int x){
return (!List[x])?x:List[x]=find(List[x]);
}
int main(){
int n,q,a,x;
scanf("%d%d",&n,&q);
while(q--){
scanf("%d%d",&a,&x);
if(a==1){
if(List[x]) continue;//已经不可用
else{
List[x]=find(x+1);
}
}
else{
if(!List[x]) printf("%d\n",x);
else printf("%d\n",find(x));
}
}
}
在看一下后来看群里发的解题写法,主函数逻辑这里不太一样,应该是影响了count。
unordered_map : !List.count(x) AC(3) !List[x] TLE(5)/AC(2) List[x]==0 TLE(2)/AC(2)
hash_map : !List.count(x) AC(2) !List[x] AC(2) List[x]==0 AC(3)
map: !List.count(x) TLE(2) !List[x] TLE(1) List[x]==0 TLE(1)
还是只有hash_map 和unordered_map,然后条件改改.
#include<map>
#include<cstring>
#include<iostream>
#include<cstdio>
#include<unordered_map>
#include<ext/hash_map>
using namespace std;
using namespace __gnu_cxx;
namespace __gnu_cxx
{
template<> struct hash< std::string >
{
size_t operator()( const std::string& x ) const
{
return hash< const char* >()( x.c_str() );
}
};
template<> struct hash<long long>
{
size_t operator()(long long x) const
{
return x;
}
};
};
unordered_map<int,int> List;
int find(int x){
return (!List.count(x))?x:List[x]=find(List[x]);
}
int main(){
int n,q,a,x;
scanf("%d%d",&n,&q);
while(q--){
scanf("%d%d",&a,&x);
if(a==1){
List[x]=find(x+1);
}
else{
printf("%d\n",find(x));
}
}
}
总之这个题目过的看几率,但是这些肯定要从他们的低层原理说起。
STL中,map
对应的数据结构是 红黑树。红黑树是一种近似于平衡的二叉查找树,里面的数据是有序的。在红黑树上做查找操作的时间复杂度为 O(logN)。而 unordered_map
对应 哈希表,哈希表的特点就是查找效率高,时间复杂度为常数级别 O(1), 而额外空间复杂度则要高出许多。所以对于需要高效率查询的情况,使用 unordered_map
容器。而如果对内存大小比较敏感或者数据存储要求有序的话,则可以用 map
容器。
所以只是用到查找功能用unordered_map 和 hash_map
关于hash_map 和 unordered_map:
由于在C++标准库中没有定义散列表hash_map,标准库的不同实现者将提供一个通常名为hash_map的非标准散列表。因为这些实现不是遵循标准编写的,所以它们在功能和性能保证上都有微妙的差别。
从C++11开始,哈希表实现已添加到C++标准库标准。决定对类使用备用名称,以防止与这些非标准实现的冲突,并防止在其代码中有hash_table的开发人员无意中使用新类。
所选择的备用名称是unordered_map,它更具描述性,因为它暗示了类的映射接口和其元素的无序性质。
可见hash_map , unordered_map本质是一样的,只不过 unordered_map被纳入了C++标准库标准。
参考链接
【2】https://www.sczyh30.com/posts/C-C/cpp-stl-hashmap/
【3】map hash_map unordered_map 性能测试
【4】c++ hash_map/unordered_map 使用