Skip to content
This repository was archived by the owner on May 22, 2026. It is now read-only.

Commit a51f356

Browse files
Merge pull request #8 from RyosukeDTomita/feature/binary_search
feature/binary search
2 parents fc413ea + a9e21c1 commit a51f356

8 files changed

Lines changed: 103 additions & 12 deletions

File tree

.vscode/settings.json

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,31 @@
11
{
2-
"C_Cpp.errorSquiggles": "disabled"
2+
"[markdown]": {
3+
"editor.defaultFormatter": "DavidAnson.vscode-markdownlint",
4+
"editor.formatOnSave": true,
5+
},
6+
// 抑止設定
7+
"markdownlint.config": {
8+
"MD010": false, // タブ
9+
"MD013": false // 長い行
10+
},
11+
"[haskell]": {
12+
"editor.defaultFormatter": "haskell.haskell",
13+
"editor.formatOnSave": true
14+
},
15+
"haskell.manageHLS": "GHCup",
16+
"haskell.formattingProvider": "ormolu",
17+
"haskell.ghcupExecutablePath": "~/.ghcup/bin/ghcup",
18+
"github.copilot.enable": {
19+
"haskell": false
20+
},
21+
"cSpell.words": [
22+
"foldl",
23+
"foldr",
24+
"scanl",
25+
"zipWith",
26+
"unwords",
27+
"unlines",
28+
"zipWith",
29+
"elems"
30+
]
331
}

search/README.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,18 @@
1414

1515
---
1616

17-
## 2 分探索(Binary search)
17+
## 二分探索(Binary search)
1818

19-
- 配列を半分にわけて,ピボットを基準にターゲットとなる値が左右のどちらにあるか探索する。
20-
- 配列がソート済みであることが必要。
19+
### 値の探索
2120

21+
- 配列がソート済みであることが必要。
22+
- 配列を半分にわけて,ピボットを基準にターゲットとなる値が左右のどちらにあるか探索する。
2223
- 計算効率は、1 ステップごとに探索対象が半分になっていく。これは 2 進数においては 1 桁減ることを表しているので計算量は O(log2 n)と表せる。
2324

25+
### 関数を満たす最大/最小の値の探索
26+
27+
- 二分探索を使い、関数f(x)がピボットに対してTrueかFalseかを判定することで、関数f(x)を満たす最大/最小のxの範囲を探索できる。
28+
2429
---
2530

2631
## bit 全探索(bit search)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import Data.List (sort)
2+
3+
-- targetを二分探索で探す
4+
binarySearch :: [Int] -> Int -> Int -> Int -> Bool
5+
binarySearch xs target left right
6+
| left > right = False -- 要素が見つからない
7+
| xs !! mid == target = True -- インデックスで要素にアクセス
8+
| xs !! mid < target = binarySearch xs target (mid + 1) right
9+
| otherwise = binarySearch xs target left (mid - 1)
10+
where
11+
mid = (left + right) `div` 2
12+
13+
main :: IO ()
14+
main = do
15+
let randomList = [30, 75, 69, 16, 47, 77, 60, 80, 74, 8, 77, 1, 60, 33, 70, 29, 24, 91, 60, 69]
16+
let sortedList = sort randomList -- 配列がsort済みである必要がある
17+
print sortedList
18+
print $ binarySearch sortedList 47 0 (length sortedList - 1) -- 発見
19+
print $ binarySearch sortedList 100 0 (length sortedList - 1) -- 発見できず
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
-- 二分探索を使って関数の条件を満たす最大の値を求める。
2+
binarySearch :: Int -> Int -> (Int -> Bool) -> Int
3+
binarySearch ok ng f
4+
| abs (ok - ng) <= 1 = ok -- これが最大の値
5+
| f mid = binarySearch mid ng f
6+
| otherwise = binarySearch ok mid f
7+
where
8+
mid = (ok + ng) `div` 2
9+
10+
main :: IO ()
11+
main = do
12+
print $ binarySearch 0 100 (\x -> x ^ 2 <= 30) -- x^2 <= 30 を満たす最大の値xを0から100の範囲で求める

sort/README.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,13 @@
1515

1616
- ある程度整列済みのデータに関して実行すると速い。
1717
- すべての値を順に調べ,各値をあるべき位置に挿入するソート方法。
18-
- 平均計算量は配列の i 番目の要素に対して右隣と比較を行うので 1 + 2 + 3 ... n-1 = (n-1)(n)/2
19-
- よって計算量は O(n^2)
18+
- 最良ケース(既に整列済みの場合)は n-1 回の比較で済むため O(n)
19+
- 平均ケース(挿入位置が一様に分布する)はO(n^2)
20+
- 各挿入で平均して i/2 回の比較が必要になるため、1/2(1 + 2 + ... + (n-1)) = n(n-1)/4 回の比較が必要になる。
21+
- 最悪ケース(逆順に整列されている場合)はO(n^2)
22+
- i番目の挿入で毎回右端まで移動するので、1 + 2 + 3 ... + (n-1) = n(n-1)/2 回の比較が必要になる。
23+
24+
---
2025

2126
## 選択ソート(Selection Sort)
2227

sort/insert_sort/insert_sort.hs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
-- 要素を正しい位置に挿入する関数
2-
insert :: Ord a => a -> [a] -> [a]
2+
insert :: (Ord a) => a -> [a] -> [a]
33
insert e [] = [e] -- 空リストへの挿入
4-
insert e (x:xs)
5-
| e <= x = e:x:xs -- eをxの左へ
6-
| otherwise = x:insert e xs -- eをxsの適切な位置へ挿入
4+
insert e (x : xs)
5+
| e <= x = e : x : xs -- eをxの左へ
6+
| otherwise = x : insert e xs -- eをxsの適切な位置へ挿入
77

88
-- 挿入ソート関数
9-
insertSort :: Ord a => [a] -> [a]
9+
insertSort :: (Ord a) => [a] -> [a]
1010
insertSort [] = []
11-
insertSort (x:xs) = insert x (insertSort xs)
11+
insertSort (x : xs) = insert x (insertSort xs)
1212

1313
main :: IO ()
1414
main = do
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
insertSort :: (Ord a) => [a] -> [a]
2+
insertSort xs = foldr insert [] xs
3+
where
4+
insert x [] = [x]
5+
insert x (y : ys) -- xをyとysの間に入れられるか調べる
6+
| x <= y = x : y : ys -- yの前にxを入れる
7+
| otherwise = y : insert x ys -- yとysの間にxは入れられることがわかったので、再帰してxを入れる適切な位置を探す。
8+
9+
insertSort' :: (Ord a) => [a] -> [a]
10+
insertSort' xs = foldl (flip insert) [] xs -- flipは関数につけて引数の順序を逆にする
11+
where
12+
insert x [] = [x]
13+
insert x (y : ys) -- xをyとysの間に入れられるか調べる
14+
| x <= y = x : y : ys -- yの前にxを入れる
15+
| otherwise = y : insert x ys -- yとysの間にxは入れられることがわかったので、再帰してxを入れる適切な位置を探す。
16+
17+
main :: IO ()
18+
main = do
19+
let randomList = [30, 75, 69, 16, 47, 77, 60, 80, 74, 8, 77, 1, 60, 33, 70, 29, 24, 91, 60, 69]
20+
print randomList
21+
print $ insertSort randomList
22+
print $ insertSort' randomList

sort/insert_sort/insert_sort_foldr.hs

Whitespace-only changes.

0 commit comments

Comments
 (0)