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

Commit 5657735

Browse files
feat: shell sort
1 parent 446385d commit 5657735

2 files changed

Lines changed: 57 additions & 3 deletions

File tree

sort/README.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,16 +119,16 @@
119119
## シェルソート(Shell Sort)
120120

121121
- 挿入ソートの改良版。
122-
- クイックソートが発見されるまでは最も高速なソートアルゴリズムだった
122+
- クイックソートが発見されるまでは最も高速なソートアルゴリズムだったらしい
123123
- 挿入ソートがある程度整列済みのデータに関して高速であることを利用して予め整列度を高めるための前処理を行う。
124124
- h-ソート: 前処理として一定の距離(h)離れた要素を比較し,ソートする。
125-
- この例では h を 3n+1 としてループを回す毎に h を 3 で割る(切り捨て)しつつ,挿入ソートと同様に 2 つの値を比較して並べることを繰り返す
125+
- この例ではKnuthの間隔列を用いる
126126

127127
### 実装例
128128

129129
- [x] C
130130
- [x] Python
131-
- [] Haskell
131+
- [x] Haskell
132132

133133
---
134134

@@ -137,4 +137,12 @@
137137
- 木構造の一種であるヒープというデータ構造を用いて,データを並び替えるソート方法。
138138
- ヒープとは: 木のデータ構造のうち,どの親子も親>=子,あるいは親<=子の関係にあること。
139139

140+
### 実装例
141+
142+
- [x] C
143+
- [x] Python
144+
- [] Haskell
145+
140146
---
147+
148+
## 計数ソート(Counting Sort)

sort/shell_sort/shellSort.hs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
shellSort :: (Ord a) => [a] -> [a]
2+
shellSort xs = foldl sortGap xs gaps -- gapは大きい順で処理される
3+
where
4+
n = length xs
5+
6+
-- Knuth gapを使用。元のリストサイズ以下の範囲で生成し、降順ソート
7+
gaps =
8+
reverse $
9+
takeWhile
10+
(< n)
11+
[ (3 ^ k + 1) `div` 2
12+
| k <- [1 ..]
13+
]
14+
-- リストをgap個のグループに分けて挿入ソートを実施する。 [0 .. gap -1]は挿入ソートの開始位置を表す
15+
sortGap arr gap = foldl (sortGroup gap) arr [0 .. gap - 1]
16+
17+
-- 挿入ソートを実施する。
18+
-- [start + gap, start + 2 * gap .. n -1]は[最初の値, 2番目の値, 上限]という形になっていて、2番目の値から類推して生成される
19+
-- ghci> start = 0
20+
-- ghci> gap = 5
21+
-- ghci> [start + gap, start + 2 * gap .. 100]
22+
-- [5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100]
23+
sortGroup gap arr start = foldl (insertGap gap start) arr [start + gap, start + 2 * gap .. n - 1]
24+
25+
-- 挿入処理を行う。
26+
insertGap gap start arr i =
27+
let x = arr !! i -- 挿入対象
28+
-- xの元のindex(i)からgap間隔で左側に走査していき、条件を満たさなくなる場所までこれを続ける。
29+
j = until (\j -> j - gap < start || arr !! (j - gap) <= x) (subtract gap) i
30+
in insertAt j x (deleteAt i arr) -- NOTE: 関数の引数であるdeleteAtが先に評価されることに注意
31+
-- リストのi番目を削除する
32+
deleteAt i arr =
33+
let (left, _ : right) =
34+
splitAt i arr
35+
in left ++ right
36+
-- リストのi番目にxを挿入する
37+
insertAt i x arr =
38+
let (left, right) =
39+
splitAt i arr
40+
in left ++ (x : right)
41+
42+
main :: IO ()
43+
main = do
44+
let randomList = [30, 75, 69, 16, 47, 77, 60, 80, 74, 8, 77, 1, 60, 33, 70, 29, 24, 91, 60, 69]
45+
print randomList
46+
print $ shellSort randomList

0 commit comments

Comments
 (0)