1+ {-# LANGUAGE CPP #-}
2+ {-# LANGUAGE OverloadedStrings #-}
3+
4+ -- {-# OPTIONS_GHC -DATCODER #-}
5+ import Debug.Trace (traceShowId )
6+
7+ #ifdef ATCODER
8+ debug :: Bool ; debug = False
9+ #else
10+ debug :: Bool ; debug = True
11+ #endif
12+
13+ dbgId :: (Show a ) => a -> a
14+ dbgId x
15+ | debug = traceShowId x
16+ | otherwise = x
17+
18+ data BST a
19+ = Empty
20+ | Node a (BST a ) (BST a )
21+ deriving (Show )
22+
23+ search :: (Ord a ) => a -> BST a -> Bool
24+ search _ Empty = False
25+ search target (Node v left right)
26+ | target == v = True
27+ | target < v = search target left -- 自分より小さい値は左側の枝に
28+ | otherwise = search target right
29+
30+ insert :: (Ord a ) => a -> BST a -> BST a
31+ insert x Empty = Node x Empty Empty
32+ insert x (Node v left right)
33+ | x == v = Node v left right
34+ | x < v = Node v (insert x left) right
35+ | otherwise = Node v left (insert x right)
36+
37+ -- 削除対象の位置にその位置からみた右部分木の最小値に置き換える。
38+ -- これにより、左部分技よりは小さく、右部分技のどの値よりも小さな値がトップにくるため二分木が破綻しない。
39+ delete :: (Ord a ) => a -> BST a -> BST a
40+ delete _ Empty = Empty
41+ delete x (Node v left right)
42+ | x < v = Node v (delete x left) right
43+ | x > v = Node v left (delete x right)
44+ | otherwise = removeNode (Node v left right)
45+
46+ -- ノード削除ロジック
47+ removeNode :: (Ord a ) => BST a -> BST a
48+ removeNode (Node _ Empty right) = right
49+ removeNode (Node _ left Empty ) = left
50+ removeNode (Node _ left right) =
51+ -- 右部分木の最小値を取り出し、そのノードを除いた木も返す
52+ let (m, right') = detachMin right
53+ in Node m left right'
54+ removeNode Empty = Empty
55+
56+ detachMin :: BST a -> (a , BST a )
57+ detachMin Empty = error " detachMin: empty tree"
58+ detachMin (Node x Empty right) = (x, right)
59+ detachMin (Node x left right) =
60+ let (m, left') = detachMin left
61+ in (m, Node x left' right)
62+
63+ -- 木を整形して表示(枝を使って階層構造を明確化)
64+ prettyPrint :: (Show a ) => BST a -> String
65+ prettyPrint tree = go " " " " tree
66+ where
67+ go _ _ Empty = " "
68+ go prefix childPrefix (Node x left right) =
69+ prefix
70+ ++ show x
71+ ++ " \n "
72+ ++ drawChildren childPrefix left right
73+
74+ drawChildren prefix Empty Empty = " "
75+ drawChildren prefix left Empty =
76+ go (prefix ++ " └── " ) (prefix ++ " " ) left
77+ drawChildren prefix Empty right =
78+ go (prefix ++ " └── " ) (prefix ++ " " ) right
79+ drawChildren prefix left right =
80+ go (prefix ++ " ├── " ) (prefix ++ " │ " ) left
81+ ++ go (prefix ++ " └── " ) (prefix ++ " " ) right
82+
83+ main :: IO ()
84+ main = do
85+ let bTree =
86+ Node
87+ 5
88+ ( Node
89+ 3
90+ ( Node
91+ 1
92+ Empty
93+ Empty
94+ )
95+ ( Node
96+ 4
97+ Empty
98+ Empty
99+ )
100+ )
101+ ( Node
102+ 7
103+ ( Node
104+ 6
105+ Empty
106+ Empty
107+ )
108+ ( Node
109+ 8
110+ Empty
111+ Empty
112+ )
113+ )
114+ putStrLn " =====INITIAl====="
115+ putStrLn $ prettyPrint bTree
116+ print $ search 3 bTree -- 存在する
117+ print $ search 10 bTree -- 存在しない
118+
119+ -- 追加
120+ putStrLn " =====ADD 10====="
121+ let bTree' = insert 10 bTree
122+ putStrLn $ prettyPrint bTree'
123+ print $ search 10 bTree'
124+
125+ -- 存在する要素を追加
126+ putStrLn " =====ADD 3(already exists)====="
127+ let bTree'' = insert 3 bTree
128+ putStrLn $ prettyPrint bTree''
129+ print $ search 3 bTree''
130+
131+ -- 削除
132+ putStrLn " =====DELETE 5====="
133+ let bTree''' = delete 5 bTree
134+ putStrLn $ prettyPrint bTree'''
135+ print $ search 5 bTree'''
136+
137+ -- 存在しない要素を削除する
138+ putStrLn " =====DELETE 8(not exist)====="
139+ let bTree'''' = delete 8 bTree
140+ putStrLn $ prettyPrint bTree''''
141+ print $ search 8 bTree''''
0 commit comments