1. 程式人生 > >從map到hash

從map到hash

存儲 減少 答案 class node 容易 自帶 span 相同

https://zybuluo.com/ysner/note/1175387

前言

這兩種技巧常用於記錄和去重量少而分散的狀態。
都體現了映射思想。

\(map\)

我一般是數組開不下時拿這玩意判重。
據說特別慢???

定義:

(註意一下比較規則必須顧及到所有變量,否則會重復

struct node
{
  int x,y;
  bool operator < (node const &o) const {return (x<o.x)||(x==o.x&&y<o.y);}
}
map<node,int>Map;

判定是否重復:

if(map[(node){x,y}]) ;

於是因太弱而被\(xzy\)教育了一番

排序

\(map\)還有一種排序功能(類比\(Tire\)樹)。如果用\(map\)存字符串,那麽用以下方式就能按字典序遍歷所有字符串。

map<node,int>::iterator iter;
for(iter=Map.begin();iter!=Map.end();iter++)
{
  string A=iter->first;
  int B=iter->second;
  ...
}

據說還有一種叫\(unorder\_map\)的玩意兒,存儲時不排序,省時間,但我並不想管。。。

\(hash\)

\(map\)雖然能有效區分、避免重復,但其自帶的\(O(logn\)

)復雜度飽受\(oier\)詬病。
我們可以棄置一定正確性,來換取時間復雜度降為\(O(1)\),這就是\(hash\)本質。
如何保證更高的正確性?這個問題沒有答案,因而很多\(hash\)方程都有其合理性。
一般在開始時,我們要選取一個\(Base\),原則是使\(Hash\)值分散,減少沖突

字符串\(hash\)

通常將字符串看成一個進制數,比如\(ABAF\)看成\(1216\)
那麽哈希值就是
\[Hash[x]=1*Base^3+2*Base^2+1*Base+6\]
\(Base\)值自定,如果態量有限,可以使用較小的\(base\)使得所有狀態不沖突,若狀態量較大且分散,可以采用多次取模(多\(hash\)

)的方式盡可能避免沖突。
狀態量少時狀態可逆。

\(hash\)

這玩意專為樹的同構而生。
怎樣的兩顆樹能稱為同構樹?
樹的深度相同、孩子、子樹大小相同,只有孩子順序不同
\[Hash[x]=\sum_{異或和}(Hash[son_{1..k}]+Base1)*(sz[x]+Base2)+deep[x]*Base3\]
如果用異或和而不是\({\sum}\),就能使\(Hash\)過程可逆。但\(Hash\)值密集時容易沖突,改成累乘就好了。

\(hash\)

用來處理狀態量大而分散的情況,沒有\(map\)保險。。。
方程自定。

從map到hash