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

Commit c492f15

Browse files
update readme
1 parent aa57e58 commit c492f15

4 files changed

Lines changed: 88 additions & 1 deletion

File tree

sort/README.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
### マージソートの計算量
6161

6262
- 配列の要素数を n とする。ただし,n>=2 とする。
63-
- 再帰的に呼び出されるマージソートは,左右対象な 2 分木を使って表現できる。この木の高さは log2 n である。
63+
- 再帰的に呼び出されるマージソートは,左右対象な 2 分木を使って表現できる。この木の高さは log2 n である。 --> 何回で1つずつの要素に分解できるか。
6464

6565
```
6666
# 2分木の高さlog2 8 = 4の例
@@ -123,6 +123,9 @@
123123
- 挿入ソートがある程度整列済みのデータに関して高速であることを利用して予め整列度を高めるための前処理を行う。
124124
- h-ソート: 前処理として一定の距離(h)離れた要素を比較し,ソートする。
125125
- この例ではKnuthの間隔列を用いる。
126+
- 計算量は最良ケースで O(n log2 n)
127+
- 平均ケースで O(n^(3/2))
128+
- 最悪ケースで O(n^2)
126129

127130
### 実装例
128131

@@ -146,3 +149,16 @@
146149
---
147150

148151
## 計数ソート(Counting Sort)
152+
153+
- まず、ソート対象のデータの中で最小値と最大値を調べる。
154+
- 次に、最小値から最大値までの範囲で各数値が出現する回数をマッピングする。
155+
- 展開するとソート済みの配列になる。
156+
- 計算量は O(n + k) である。ただし n はソート対象の要素数、k は最大値と最小値の差。
157+
- カウント配列の作成にO(k)、入力を1回走査するのにO(n)、出力配列の作成にO(k+n)かかるため。
158+
- カウント配列から復元時にはk個のカウント配列に対して合計n個の要素を出力するため、O(k+n)になる。
159+
160+
### 実装例
161+
162+
- [] C
163+
- [] Python
164+
- [x] Haskell
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import Data.Array (accumArray, assocs)
2+
3+
-- accumArray
4+
-- :: GHC.Ix.Ix i =>
5+
-- (e -> a -> e) -> e -> (i, i) -> [(i, a)] -> GHC.Arr.Array i e
6+
-- ghci> accumArray (+) 0 (0,5) [(x, 1) | x <- [1,1,2,3,5]]
7+
-- array (0,5) [(0,0),(1,2),(2,1),(3,1),(4,0),(5,1)]
8+
countingSort :: [Int] -> [Int]
9+
countingSort [] = []
10+
countingSort xs =
11+
let maxX = maximum xs
12+
minX = minimum xs
13+
range = (minX, maxX)
14+
-- 各値の出現回数をカウント(配列を使用してO(n))
15+
counts = accumArray (+) 0 range [(x, 1) | x <- xs]
16+
-- カウント配列から元のリストを再構築
17+
expand (i, count) = replicate count i
18+
in concatMap expand (assocs counts)
19+
20+
main :: IO ()
21+
main = do
22+
let randomList = [30, 75, 69, 16, 47, 77, 60, 80, 74, 8, 77, 1, 60, 33, 70, 29, 24, 91, 60, 69]
23+
print randomList
24+
print $ countingSort randomList
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
countingSort :: [Int] -> [Int]
2+
countingSort [] = []
3+
countingSort xs =
4+
let maxX = maximum xs
5+
minX = minimum xs
6+
range = maxX - minX + 1
7+
-- 初期化:すべて0のリストを作成
8+
initCounts = replicate range 0
9+
-- 各値の出現回数をカウント(リストの更新はO(n)なので全体でO(n²))
10+
updateCount :: [Int] -> Int -> [Int]
11+
updateCount counts x =
12+
let idx = x - minX
13+
(before, current : after) = splitAt idx counts
14+
in before ++ (current + 1) : after
15+
counts = foldl updateCount initCounts xs
16+
-- カウント配列から元のリストを再構築
17+
expand (i, count) = replicate count (i + minX)
18+
in concatMap expand (zip [0 ..] counts)
19+
20+
main :: IO ()
21+
main = do
22+
let randomList = [30, 75, 69, 16, 47, 77, 60, 80, 74, 8, 77, 1, 60, 33, 70, 29, 24, 91, 60, 69]
23+
print randomList
24+
print $ countingSort randomList
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
countingSort :: [Int] -> [Int]
2+
countingSort [] = []
3+
countingSort xs =
4+
let updateCounts :: [(Int, Int)] -> Int -> [(Int, Int)]
5+
-- 第一引数: 操作前のcounts。各数値が何個見つかったか記録する
6+
-- x
7+
-- return xを適用したcounts
8+
-- 1回の更新はO(k)なので全体の最悪ケースはO(n^2)
9+
updateCounts [] x = [(x, 1)]
10+
updateCounts ((v, c) : rest) x
11+
| v == x = (v, c + 1) : rest
12+
| v < x = (v, c) : updateCounts rest x
13+
| otherwise = (x, 1) : (v, c) : rest
14+
counts = foldl updateCounts [] xs
15+
-- タプルから元のリストを再構築
16+
expand (value, count) = replicate count value
17+
in concatMap expand counts
18+
19+
main :: IO ()
20+
main = do
21+
let randomList = [30, 75, 69, 16, 47, 77, 60, 80, 74, 8, 77, 1, 60, 33, 70, 29, 24, 91, 60, 69]
22+
print randomList
23+
print $ countingSort randomList

0 commit comments

Comments
 (0)