1+ import Data.Hashable (Hashable , hash )
2+ import Data.Vector qualified as V
3+ import Debug.Trace (trace , traceShowId )
4+
5+ dbgId :: (Show a ) => a -> a
6+ dbgId x = trace (" bucketIndex is " ++ show x) x
7+
8+ -- チェイン法によるハッシュ
9+ -- NOTE: レコード構文を使い、buckets hsで値が取得できるようにしている
10+ -- ghci> import Data.Vector qualified as V
11+ -- ghci> data HashSet a = HashSet {buckets :: V.Vector [a]} deriving (Show)
12+ -- ghci> hs = HashSet {buckets=(V.replicate 3 [])}
13+ -- ghci> buckets hs
14+ -- [[],[],[]]
15+ data HashSet a = HashSet { buckets :: V. Vector [a ]}
16+ deriving (Show )
17+
18+ -- どのindexに保存するかを決める
19+ bucketIndex :: (Hashable a ) => HashSet a -> a -> Int
20+ bucketIndex hs x = abs (hash x) `mod` V. length (buckets hs)
21+
22+ -- ハッシュテーブルの初期化
23+ empty :: Int -> HashSet a
24+ empty size = HashSet (V. replicate size [] )
25+
26+ -- 値の存在確認
27+ member :: (Eq a , Hashable a ) => a -> HashSet a -> Bool
28+ member x hs = x `elem` bucket -- NOTE: チェイン法なので同じハッシュの値が含まれている可能性があるのでelemでチェックしている
29+ where
30+ i = bucketIndex hs x
31+ bucket = buckets hs V. ! i
32+
33+ insert :: (Eq a , Hashable a ) => a -> HashSet a -> HashSet a
34+ insert x hs
35+ | member x hs = hs -- 同じ要素は格納しない
36+ | otherwise = hs {buckets = buckets hs V. // [(i, x : bucket)]} -- index iの要素をx:bucketに置き換える(チェイン法なので同じハッシュの値は維持)
37+ where
38+ i = dbgId $ bucketIndex hs x
39+ bucket = buckets hs V. ! i
40+
41+ delete :: (Eq a , Hashable a ) => a -> HashSet a -> HashSet a
42+ delete x hs =
43+ hs {buckets = buckets hs V. // [(i, newBucket)]}
44+ where
45+ i = dbgId $ bucketIndex hs x
46+ bucket = buckets hs V. ! i
47+ newBucket = filter (/= x) bucket
48+
49+ main :: IO ()
50+ main = do
51+ let hs0 = empty 8 :: HashSet Int -- サイズ8
52+ print hs0
53+
54+ -- insert
55+ print " insert 1 4"
56+ let hs1 = insert 1 hs0
57+ hs2 = insert 4 hs1
58+ print hs2
59+
60+ -- check
61+ print " check 10 1 is store"
62+ print $ member 10 hs2 -- False
63+ print $ member 1 hs2 -- True
64+
65+ -- delete
66+ print " delete 1 and check 1 4 is store"
67+ let hs2' = delete 1 hs2
68+ print hs2'
69+ print $ member 1 hs2' -- False
70+ print $ member 4 hs2 -- True
71+
72+ -- 同じハッシュのときのチェック
73+ print " same hash"
74+ let hs3 = insert 16 hs2
75+ hs4 = insert 32 hs3
76+ print hs4
0 commit comments