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 使用​