rabbit-slide-Piro-readable-code-workshop-2022-08-04-performance 2022.08.04
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rabbit +1 -0
- data/README.rd +32 -0
- data/Rakefile +17 -0
- data/config.yaml +22 -0
- data/images/graph-O1.png +0 -0
- data/images/graph-ON.png +0 -0
- data/images/graph-ON2.png +0 -0
- data/images/graph-ONfactorial.png +0 -0
- data/images/graph-OlogN.png +0 -0
- data/pdf/readable-code-workshop-2022-08-04-performance-summary.pdf +0 -0
- data/performance.rab +692 -0
- data/samples.pdf +0 -0
- data/try.pdf +0 -0
- metadata +85 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6d9a00a9415e33fd59505e098d1ab42b91c5ac23db295c039a9c76fa0fc1b0ad
|
4
|
+
data.tar.gz: 1342bd0c700bdbfbeb10929092cd8349e78e52404adb701aba8004b77f66cded
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 03fb94c05950f1aea0002b3b830ab3f5effd19bbceb848927b19119c2295fc19eb84f03780fcdc83e4fcb9605fed46f466330a54fade4ff9fa1c3a2b16c0753d
|
7
|
+
data.tar.gz: 56aef32470adc0118b66274e2f332c881f404b3d88c5c9538abc9c25791c175b9ba9107a73b57941ce62bc7b5892d562504e8f64037388fe28d038a3e954b101
|
data/.rabbit
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
performance.rab
|
data/README.rd
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
= プログラムの計算量と実行性能について
|
2
|
+
|
3
|
+
2022-08-04開催のリーダブルコード演習の予習としての、プログラムの実行性能の話。
|
4
|
+
|
5
|
+
== ライセンス
|
6
|
+
|
7
|
+
CC BY-SA 4.0
|
8
|
+
|
9
|
+
原著作者名は以下の通りです。
|
10
|
+
|
11
|
+
* 株式会社クリアコード
|
12
|
+
|
13
|
+
== 作者向け
|
14
|
+
|
15
|
+
=== 表示
|
16
|
+
|
17
|
+
rake
|
18
|
+
|
19
|
+
=== 公開
|
20
|
+
|
21
|
+
rake publish
|
22
|
+
|
23
|
+
== 閲覧者向け
|
24
|
+
|
25
|
+
=== インストール
|
26
|
+
|
27
|
+
gem install rabbit-slide-piroor-readable-code-workshop-2022-08-04-performance
|
28
|
+
|
29
|
+
=== 表示
|
30
|
+
|
31
|
+
rabbit rabbit-slide-piroor-readable-code-workshop-2022-08-04-performance.gem
|
32
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require "rabbit/task/slide"
|
2
|
+
|
3
|
+
# Edit ./config.yaml to customize meta data
|
4
|
+
|
5
|
+
spec = nil
|
6
|
+
Rabbit::Task::Slide.new do |task|
|
7
|
+
spec = task.spec
|
8
|
+
spec.files += Dir.glob("images/**/*.*")
|
9
|
+
# spec.files -= Dir.glob("private/**/*.*")
|
10
|
+
spec.add_runtime_dependency("rabbit-theme-clear-code")
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "Tag #{spec.version}"
|
14
|
+
task :tag do
|
15
|
+
sh("git", "tag", "-a", spec.version.to_s, "-m", "Publish #{spec.version}")
|
16
|
+
sh("git", "push", "--tags")
|
17
|
+
end
|
data/config.yaml
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
---
|
2
|
+
id: readable-code-workshop-2022-08-04-performance
|
3
|
+
base_name: summary
|
4
|
+
tags:
|
5
|
+
- rabbit
|
6
|
+
- readable-code
|
7
|
+
presentation_date: 2022-08-04
|
8
|
+
version: 2022.08.04
|
9
|
+
licenses:
|
10
|
+
- CC BY-SA 4.0
|
11
|
+
slideshare_id: readable-code-workshop-2022-08-04-performance
|
12
|
+
speaker_deck_id:
|
13
|
+
ustream_id:
|
14
|
+
vimeo_id:
|
15
|
+
youtube_id:
|
16
|
+
author:
|
17
|
+
markup_language: :rd
|
18
|
+
name: YUKI Hiroshi
|
19
|
+
email: yuki@clear-code.com
|
20
|
+
rubygems_user: Piro
|
21
|
+
slideshare_user: pirooutsiderreflex
|
22
|
+
speaker_deck_user: piroor
|
data/images/graph-O1.png
ADDED
Binary file
|
data/images/graph-ON.png
ADDED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/performance.rab
ADDED
@@ -0,0 +1,692 @@
|
|
1
|
+
= プログラムの計算量と実行性能について
|
2
|
+
|
3
|
+
: author
|
4
|
+
結城洋志
|
5
|
+
: institution
|
6
|
+
株式会社クリアコード
|
7
|
+
: content-source
|
8
|
+
リーダブルコード演習
|
9
|
+
: date
|
10
|
+
2022-08-04
|
11
|
+
: allotted-time
|
12
|
+
90m
|
13
|
+
: theme
|
14
|
+
clear-code
|
15
|
+
|
16
|
+
== ノート
|
17
|
+
|
18
|
+
TODO:次回やるのであれば、サンプルコードはPythonで書くようにする。
|
19
|
+
(学生さんはPythonはカリキュラムの中で学ばれているため、JSより浸透している)
|
20
|
+
|
21
|
+
= 講師紹介
|
22
|
+
|
23
|
+
(('tag:center'))(('tag:margin-bottom * 2'))
|
24
|
+
結城洋志(ゆうき ひろし)\n
|
25
|
+
aka Piro
|
26
|
+
|
27
|
+
* 株式会社クリアコード所属
|
28
|
+
* FirefoxやThunderbirdの\n
|
29
|
+
法人サポートに従事
|
30
|
+
* トラブルの原因や対策を探るため\n
|
31
|
+
ソースコードを調査することが多い
|
32
|
+
|
33
|
+
== ノート
|
34
|
+
|
35
|
+
Mozilla FirefoxはWebブラウザー。
|
36
|
+
Mozilla Thunderbirdはメールクライアント。
|
37
|
+
|
38
|
+
開発元のMozillaは、企業ユーザーからのトラブル問い合わせなどに回答するサービスは提供していない。
|
39
|
+
そのため、クリアコードのような事業者が、ある意味で勝手にサポートサービスを行っている。
|
40
|
+
|
41
|
+
Firefoxで特定のサービスの動作が遅い、といった問い合わせを受ける
|
42
|
+
|
43
|
+
|
44
|
+
= アジェンダ
|
45
|
+
|
46
|
+
* プログラムの実行性能に\n
|
47
|
+
影響する要素について
|
48
|
+
* 計算量について
|
49
|
+
* 実際に確かめてみる
|
50
|
+
|
51
|
+
|
52
|
+
= プログラムは「軽い」「速い」方がいい
|
53
|
+
|
54
|
+
= 「軽い」「速い」とは?
|
55
|
+
|
56
|
+
* ((*目的が素早く達成される*))\n
|
57
|
+
例:データ変換プログラム
|
58
|
+
* 同じ時間で多くの件数のデータを\n
|
59
|
+
変換できる
|
60
|
+
* データを1件変換する所要時間が短い
|
61
|
+
|
62
|
+
= 性能の指標と測定方法
|
63
|
+
|
64
|
+
* 他の方の講義で詳しく\n
|
65
|
+
扱われるそうなので\n
|
66
|
+
割愛
|
67
|
+
|
68
|
+
= 性能に影響する要素
|
69
|
+
|
70
|
+
* 外部要因
|
71
|
+
* 通信待ち
|
72
|
+
* ディスクアクセス待ち\n
|
73
|
+
(('note:など'))
|
74
|
+
* 内部要因
|
75
|
+
* ((*計算量*))
|
76
|
+
|
77
|
+
= 計算量
|
78
|
+
|
79
|
+
実行される処理の\n
|
80
|
+
((*回数の大小*))
|
81
|
+
|
82
|
+
= 例
|
83
|
+
|
84
|
+
「データを10件取得する」
|
85
|
+
|
86
|
+
= 1件ずつ取得する
|
87
|
+
|
88
|
+
SELECT * FROM table OFFSET 0 LIMIT 1;
|
89
|
+
SELECT * FROM table OFFSET 1 LIMIT 1;
|
90
|
+
...
|
91
|
+
SELECT * FROM table OFFSET 8 LIMIT 1;
|
92
|
+
SELECT * FROM table OFFSET 9 LIMIT 1;
|
93
|
+
|
94
|
+
→処理の実行回数は((*10回*))
|
95
|
+
|
96
|
+
== ノート
|
97
|
+
|
98
|
+
これは「計算量が10」と言える。
|
99
|
+
|
100
|
+
= 10件まとめて取得する
|
101
|
+
|
102
|
+
SELECT * FROM table OFFSET 0 LIMIT 10;
|
103
|
+
|
104
|
+
→処理の実行回数は((*1回*))
|
105
|
+
|
106
|
+
== ノート
|
107
|
+
|
108
|
+
これは「計算量が1」と言える。
|
109
|
+
|
110
|
+
= 計算量は少ない方がいい!
|
111
|
+
|
112
|
+
|
113
|
+
= アルゴリズム(1/3)
|
114
|
+
|
115
|
+
* 計算量は((*計算方法*))で決まる
|
116
|
+
* 計算(処理)方法=((*アルゴリズム*))
|
117
|
+
* ((*より少ない計算量*))で同じ結果を\n
|
118
|
+
得られる\n
|
119
|
+
=より優秀なアルゴリズム
|
120
|
+
|
121
|
+
= アルゴリズム(2/3)
|
122
|
+
|
123
|
+
* データ件数が増えれば\n
|
124
|
+
計算量も増える(('note:(ことが多い)'))
|
125
|
+
* データの件数の増加度合いに対して\n
|
126
|
+
((*計算量の増加度合いが小さい*))\n
|
127
|
+
=より優秀なアルゴリズム
|
128
|
+
|
129
|
+
= こういうのよりは
|
130
|
+
|
131
|
+
# image
|
132
|
+
# src = images/graph-ONfactorial.png
|
133
|
+
# relative_width = 90
|
134
|
+
|
135
|
+
== プロパティー
|
136
|
+
|
137
|
+
: enable-title-on-image
|
138
|
+
false
|
139
|
+
|
140
|
+
= こういうのの方が嬉しい
|
141
|
+
|
142
|
+
# image
|
143
|
+
# src = images/graph-ON2.png
|
144
|
+
# relative_width = 90
|
145
|
+
|
146
|
+
== プロパティー
|
147
|
+
|
148
|
+
: enable-title-on-image
|
149
|
+
false
|
150
|
+
|
151
|
+
= こうだとなお嬉しい
|
152
|
+
|
153
|
+
# image
|
154
|
+
# src = images/graph-O1.png
|
155
|
+
# relative_width = 90
|
156
|
+
|
157
|
+
== プロパティー
|
158
|
+
|
159
|
+
: enable-title-on-image
|
160
|
+
false
|
161
|
+
|
162
|
+
= アルゴリズム(3/3)
|
163
|
+
|
164
|
+
* 計算量は、((*実行しなくても*))\n
|
165
|
+
アルゴリズムから見積もれる
|
166
|
+
|
167
|
+
== ノート
|
168
|
+
|
169
|
+
これはとても大事な性質。
|
170
|
+
遅いアルゴリズムは、コードを見ただけで「これは遅い」と分かる。
|
171
|
+
1時間で終わると思ったら、実際動かしてみたら1日かかりました、といったことを避けられる。
|
172
|
+
|
173
|
+
= どうやって見積もる?
|
174
|
+
|
175
|
+
= 計算量の見積もり方・表し方
|
176
|
+
|
177
|
+
* Ο記法(オーダー)
|
178
|
+
* O(1)
|
179
|
+
* O(N)
|
180
|
+
* O(N^2)
|
181
|
+
* O(N!)
|
182
|
+
* O(logN)
|
183
|
+
|
184
|
+
= O(1):定数時間
|
185
|
+
|
186
|
+
// 色の名前とカラーコードのデータ(ハッシュ構造)
|
187
|
+
const COLOR_CODE_BY_NAME = {
|
188
|
+
blue: 0x0000FF,
|
189
|
+
green: 0x00FF00,
|
190
|
+
red: 0xFF0000,
|
191
|
+
yellow: 0xFFFF00,
|
192
|
+
};
|
193
|
+
// 色の名前でカラーコードを特定する
|
194
|
+
let color = COLOR_CODE_BY_NAME['red'];
|
195
|
+
console.log(color); // => 0xFF0000
|
196
|
+
|
197
|
+
== ノート
|
198
|
+
|
199
|
+
データ件数にかかわらず一定の速度で結果が出る。
|
200
|
+
最速のアルゴリズム。
|
201
|
+
|
202
|
+
= O(1):定数時間
|
203
|
+
|
204
|
+
# image
|
205
|
+
# src = images/graph-O1.png
|
206
|
+
# relative_width = 90
|
207
|
+
|
208
|
+
== プロパティー
|
209
|
+
|
210
|
+
: enable-title-on-image
|
211
|
+
false
|
212
|
+
|
213
|
+
= O(N):線形関数
|
214
|
+
|
215
|
+
// 色の名前とカラーコードのデータ(配列構造)
|
216
|
+
const COLOR_CODES = [
|
217
|
+
{ name: 'blue', code: 0x0000FF },
|
218
|
+
{ name: 'green', code: 0x00FF00 },
|
219
|
+
{ name: 'red', code: 0xFF0000 },
|
220
|
+
{ name: 'yellow', code: 0xFFFF00 },
|
221
|
+
];
|
222
|
+
// 色の名前でカラーコードを特定する
|
223
|
+
let color;
|
224
|
+
for (const item of COLOR_CODES) {
|
225
|
+
if (item.name == 'red') {
|
226
|
+
color = item.code;
|
227
|
+
break;
|
228
|
+
}
|
229
|
+
}
|
230
|
+
console.log(color); // => 0xFF0000
|
231
|
+
|
232
|
+
== ノート
|
233
|
+
|
234
|
+
計算量がデータ件数に正比例する。
|
235
|
+
(最悪の場合は全データを1回ずつ処理するため。)
|
236
|
+
|
237
|
+
= O(N):線形関数
|
238
|
+
|
239
|
+
# image
|
240
|
+
# src = images/graph-ON.png
|
241
|
+
# relative_width = 90
|
242
|
+
|
243
|
+
== プロパティー
|
244
|
+
|
245
|
+
: enable-title-on-image
|
246
|
+
false
|
247
|
+
|
248
|
+
= ループを使ってなくても安心できない
|
249
|
+
|
250
|
+
[a,b,c,d,e].indexOf(c) // => 2
|
251
|
+
|
252
|
+
[a,b,c,d,e].includes(c) // => true
|
253
|
+
|
254
|
+
= メソッドの中身が線形関数な場合がある(1/2)
|
255
|
+
|
256
|
+
function indexOf() {
|
257
|
+
const items = [a,b,c,d,e];
|
258
|
+
for (let i = 0; i < items.length; i++) {
|
259
|
+
if (item == c) {
|
260
|
+
return i; // => 2
|
261
|
+
}
|
262
|
+
}
|
263
|
+
return -1;
|
264
|
+
}
|
265
|
+
|
266
|
+
= メソッドの中身が線形関数な場合がある(2/2)
|
267
|
+
|
268
|
+
function includes() {
|
269
|
+
const items = [a,b,c,d,e];
|
270
|
+
for (let i = 0; i < items.length; i++) {
|
271
|
+
if (item == c) {
|
272
|
+
return true; // => 2
|
273
|
+
}
|
274
|
+
}
|
275
|
+
return false;
|
276
|
+
}
|
277
|
+
|
278
|
+
|
279
|
+
= O(N^2):二乗時間
|
280
|
+
|
281
|
+
// 重複を含む配列
|
282
|
+
const duplicated = [
|
283
|
+
0,1,2,3,2,1,4,3,4,5,6,7,5,6,4,8,9,5,3,2
|
284
|
+
];
|
285
|
+
// 重複を取り除いた配列
|
286
|
+
const unique = [];
|
287
|
+
for (const duplicatedItem of duplicated) {
|
288
|
+
let included = false;
|
289
|
+
for (const uniqueItem of unique) {
|
290
|
+
if (uniqueItem == duplicatedItem) {
|
291
|
+
included = true;
|
292
|
+
break;
|
293
|
+
}
|
294
|
+
}
|
295
|
+
if (!included)
|
296
|
+
unique.push(duplicatedItem);
|
297
|
+
}
|
298
|
+
console.log(unique); // => [0,1,2,3,4,5,6,7,8,9]
|
299
|
+
|
300
|
+
== ノート
|
301
|
+
|
302
|
+
データ件数の増加に対し、計算量の増加がいわゆる指数関数的な増加を見せる。
|
303
|
+
パスワードの総当たりの場合、O(n^文字数)となる。
|
304
|
+
|
305
|
+
= O(N^2):二乗時間
|
306
|
+
|
307
|
+
# image
|
308
|
+
# src = images/graph-ON2.png
|
309
|
+
# relative_width = 90
|
310
|
+
|
311
|
+
== プロパティー
|
312
|
+
|
313
|
+
: enable-title-on-image
|
314
|
+
false
|
315
|
+
|
316
|
+
= ループを使ってなくても安心できない
|
317
|
+
|
318
|
+
* メソッドの中身が(以下略)
|
319
|
+
|
320
|
+
= O(logN):対数
|
321
|
+
|
322
|
+
// 検索対象の配列(ソート済み)
|
323
|
+
const values = [0, 3, 6, 9, 12, 70, 102];
|
324
|
+
// 特定の値が何番目にあるかを二分探索で調べる
|
325
|
+
const target = 12;
|
326
|
+
let index = -1;
|
327
|
+
let minIndex = 0;
|
328
|
+
let maxIndex = values.length - 1;
|
329
|
+
while (minIndex <= maxIndex) {
|
330
|
+
let middleIndex = Math.floor((minIndex + maxIndex) / 2);
|
331
|
+
if (values[middleIndex] == target) {
|
332
|
+
index = middleIndex;
|
333
|
+
break;
|
334
|
+
}
|
335
|
+
else if (values[middleIndex] < target)
|
336
|
+
minIndex = middleIndex + 1;
|
337
|
+
else
|
338
|
+
maxIndex = middleIndex - 1;
|
339
|
+
}
|
340
|
+
console.log(index); // => 4
|
341
|
+
|
342
|
+
== ノート
|
343
|
+
|
344
|
+
コードは https://tech-blog.s-yoshiki.com/entry/195 の物を加工して掲載した。
|
345
|
+
データ件数の増加割合に対して計算量の増加割合が少ない。
|
346
|
+
データ件数の増加に対して、計算量の増加が緩やか。
|
347
|
+
|
348
|
+
= O(logN):対数
|
349
|
+
|
350
|
+
# image
|
351
|
+
# src = images/graph-OlogN.png
|
352
|
+
# relative_width = 90
|
353
|
+
|
354
|
+
== プロパティー
|
355
|
+
|
356
|
+
: enable-title-on-image
|
357
|
+
false
|
358
|
+
|
359
|
+
|
360
|
+
= O(N!):階乗関数(1/3)
|
361
|
+
|
362
|
+
巡回セールスマン問題
|
363
|
+
|
364
|
+
// ある都市から他の都市までの移動に要する時間のデータ
|
365
|
+
const cities = {
|
366
|
+
tokyo: { osaka: 2, hokkaido: 3, okinawa: 4, kagawa: 5 },
|
367
|
+
osaka: { tokyo: 2, hokkaido: 5, okinawa: 3, kagawa: 1 },
|
368
|
+
hokkaido: { tokyo: 3, osaka: 5, okinawa: 7, kagawa: 6 },
|
369
|
+
okinawa: { tokyo: 4, osaka: 3, hokkaido: 7, kagawa: 8 },
|
370
|
+
kagawa: { tokyo: 5, osaka: 1, okinawa: 8, hokkaido: 6 },
|
371
|
+
};
|
372
|
+
|
373
|
+
== ノート
|
374
|
+
|
375
|
+
各都市と、各都市間の移動に要する時間。
|
376
|
+
ここから、移動時間が最短になる巡回ルートを求めたい。
|
377
|
+
こういう計算を「巡回セールスマン問題」と呼ぶ。
|
378
|
+
|
379
|
+
= O(N!):階乗関数(2/3)
|
380
|
+
|
381
|
+
// 配列から順列組み合わせを作る処理
|
382
|
+
function getPermutations(array) {
|
383
|
+
const permutations = [];
|
384
|
+
const nextPermutation = [];
|
385
|
+
function permutate(array) {
|
386
|
+
if (array.length === 0)
|
387
|
+
permutations.push(nextPermutation.slice());
|
388
|
+
for (let i = 0; i < array.length; i++) {
|
389
|
+
array.push(array.shift());
|
390
|
+
nextPermutation.push(array[0]);
|
391
|
+
permutate(array.slice(1));
|
392
|
+
nextPermutation.pop();
|
393
|
+
}
|
394
|
+
}
|
395
|
+
permutate(array);
|
396
|
+
return permutations;
|
397
|
+
}
|
398
|
+
|
399
|
+
== ノート
|
400
|
+
|
401
|
+
組み合わせを列挙する関数。
|
402
|
+
Original version is: get-permutations npm module made by Jan Järfalk
|
403
|
+
Licensed: ISC
|
404
|
+
https://github.com/janjarfalk/get-permutations
|
405
|
+
|
406
|
+
= O(N!):階乗関数(3/3)
|
407
|
+
|
408
|
+
// 総当たりで移動時間を求めて、最短の移動パターンを見つける
|
409
|
+
const results = [];
|
410
|
+
for (const start of Object.keys(cities)) {
|
411
|
+
const patterns = getPermutations(
|
412
|
+
Object.keys(cities).filter(dest => dest != start)
|
413
|
+
);
|
414
|
+
for (const pattern of patterns) {
|
415
|
+
let last;
|
416
|
+
let total = 0;
|
417
|
+
const route = [start, ...pattern, start];
|
418
|
+
for (const current of route) {
|
419
|
+
if (last)
|
420
|
+
total += cities[last][current];
|
421
|
+
last = current;
|
422
|
+
}
|
423
|
+
results.push({ route: route.join('-'), total });
|
424
|
+
}
|
425
|
+
}
|
426
|
+
console.log(results.length);
|
427
|
+
// => 120
|
428
|
+
results.sort((a, b) => a.total - b.total);
|
429
|
+
console.log(results[0]);
|
430
|
+
// => { route: "tokyo-hokkaido-kagawa-osaka-okinawa-tokyo", total: 17 }
|
431
|
+
|
432
|
+
== ノート
|
433
|
+
|
434
|
+
愚直にやると、データ件数の階乗回の計算が必要になる。
|
435
|
+
ここでは、件数5で120回ループが回る。
|
436
|
+
|
437
|
+
= O(N!):階乗関数
|
438
|
+
|
439
|
+
# image
|
440
|
+
# src = images/graph-ONfactorial.png
|
441
|
+
# relative_width = 90
|
442
|
+
|
443
|
+
7件で5040回、8件で40320回
|
444
|
+
|
445
|
+
== プロパティー
|
446
|
+
|
447
|
+
: enable-title-on-image
|
448
|
+
false
|
449
|
+
|
450
|
+
== ノート
|
451
|
+
|
452
|
+
データ件数 計算量
|
453
|
+
1 1
|
454
|
+
2 2
|
455
|
+
3 6
|
456
|
+
4 24
|
457
|
+
5 120
|
458
|
+
6 720
|
459
|
+
7 5,040
|
460
|
+
8 40,320
|
461
|
+
|
462
|
+
=
|
463
|
+
|
464
|
+
= 計算量を減らしたい!
|
465
|
+
|
466
|
+
== ノート
|
467
|
+
|
468
|
+
同じ結果を得られるなら、計算量は小さいに越したことはない。
|
469
|
+
|
470
|
+
|
471
|
+
= 計算量
|
472
|
+
|
473
|
+
* どういう結果を
|
474
|
+
* どういうデータから
|
475
|
+
* どのように求めるか
|
476
|
+
|
477
|
+
によって、計算量は大きく変わる
|
478
|
+
|
479
|
+
= どうすれば計算量を減らせる?
|
480
|
+
|
481
|
+
= 計算量を減らすには(1/3)
|
482
|
+
|
483
|
+
* 計算方法を変える\n
|
484
|
+
=((*アルゴリズムを工夫する*))
|
485
|
+
|
486
|
+
= 元のアルゴリズム:O(N^2)
|
487
|
+
|
488
|
+
// 重複を含む配列
|
489
|
+
const duplicated = [
|
490
|
+
0,1,2,3,2,1,4,3,4,5,6,7,5,6,4,8,9,5,3,2
|
491
|
+
];
|
492
|
+
// 重複を取り除いた配列
|
493
|
+
const unique = [];
|
494
|
+
for (const duplicatedItem of duplicated) {
|
495
|
+
let included = false;
|
496
|
+
for (const uniqueItem of unique) {
|
497
|
+
if (uniqueItem == duplicatedItem) {
|
498
|
+
included = true;
|
499
|
+
break;
|
500
|
+
}
|
501
|
+
}
|
502
|
+
if (!included)
|
503
|
+
unique.push(duplicatedItem);
|
504
|
+
}
|
505
|
+
console.log(unique); // => [0,1,2,3,4,5,6,7,8,9]
|
506
|
+
|
507
|
+
|
508
|
+
= アルゴリズムを変えた:O(N)
|
509
|
+
|
510
|
+
// 重複を含む配列
|
511
|
+
const duplicated = [
|
512
|
+
0,1,2,3,2,1,4,3,4,5,6,7,5,6,4,8,9,5,3,2
|
513
|
+
];
|
514
|
+
// 既に見つかった項目の情報
|
515
|
+
const found = {};
|
516
|
+
// 重複を取り除いた配列
|
517
|
+
const unique = [];
|
518
|
+
for (const item of duplicated) {
|
519
|
+
if (found[item])
|
520
|
+
continue;
|
521
|
+
found[item] = true;
|
522
|
+
unique.push(item);
|
523
|
+
}
|
524
|
+
console.log(unique); // => [0,1,2,3,4,5,6,7,8,9]
|
525
|
+
|
526
|
+
= ループの実行回数を減らす!
|
527
|
+
|
528
|
+
* ループせず済ませるように\n
|
529
|
+
する(('note:(O(1)に寄せる)'))
|
530
|
+
* 直近の実行結果を使い回す\n
|
531
|
+
(キャッシュ)
|
532
|
+
|
533
|
+
= アルゴリズムは色々ある
|
534
|
+
|
535
|
+
= 例:並べ替え(ソート)
|
536
|
+
|
537
|
+
* クイックソート:O(NlogN)~O(N^2)
|
538
|
+
* 結果は不安定
|
539
|
+
* バブルソート:O(N^2)
|
540
|
+
* 結果は安定
|
541
|
+
* マージソート:O(NlogN)
|
542
|
+
* 結果は安定
|
543
|
+
|
544
|
+
= それぞれアルゴリズムには得手・不得手がある
|
545
|
+
|
546
|
+
例:
|
547
|
+
|
548
|
+
* ある程度揃ったデータだと速い
|
549
|
+
* データ件数が少ないと速い\n
|
550
|
+
(('note:など'))
|
551
|
+
|
552
|
+
先達の知見を活かそう
|
553
|
+
|
554
|
+
=
|
555
|
+
|
556
|
+
= 計算量を減らすには(2/3)
|
557
|
+
|
558
|
+
* データの構造の方を変える\n
|
559
|
+
=((*前加工する*))
|
560
|
+
|
561
|
+
= データ構造による制約:O(N)
|
562
|
+
|
563
|
+
// 色の名前とカラーコードのデータ(配列構造)
|
564
|
+
const COLOR_CODES = [
|
565
|
+
{ name: 'blue', code: 0x0000FF },
|
566
|
+
{ name: 'green', code: 0x00FF00 },
|
567
|
+
{ name: 'red', code: 0xFF0000 },
|
568
|
+
{ name: 'yellow', code: 0xFFFF00 },
|
569
|
+
];
|
570
|
+
// 色の名前でカラーコードを特定する
|
571
|
+
let color;
|
572
|
+
for (const item of COLOR_CODES) {
|
573
|
+
if (item.name == 'red') {
|
574
|
+
color = item.code;
|
575
|
+
break;
|
576
|
+
}
|
577
|
+
}
|
578
|
+
console.log(color); // => 0xFF0000
|
579
|
+
|
580
|
+
== ノート
|
581
|
+
|
582
|
+
配列構造でデータが与えられている場合、どう頑張ってもこれ以上は計算量を減らせない。
|
583
|
+
|
584
|
+
= データ構造による制約:O(1)
|
585
|
+
|
586
|
+
// 色の名前とカラーコードのデータ(ハッシュ構造)
|
587
|
+
const COLOR_CODE_BY_NAME = {
|
588
|
+
blue: 0x0000FF,
|
589
|
+
green: 0x00FF00,
|
590
|
+
red: 0xFF0000,
|
591
|
+
yellow: 0xFFFF00,
|
592
|
+
};
|
593
|
+
// 色の名前でカラーコードを特定する
|
594
|
+
let color = COLOR_CODE_BY_NAME['red'];
|
595
|
+
console.log(color); // => 0xFF0000
|
596
|
+
|
597
|
+
== ノート
|
598
|
+
|
599
|
+
同じ意味のデータでも、構造がハッシュテーブルになっていれば、O(1)でいける。
|
600
|
+
|
601
|
+
= データ構造を変える(1/2)
|
602
|
+
|
603
|
+
// 色の名前とカラーコードのデータ(配列構造)
|
604
|
+
const COLOR_CODES = [
|
605
|
+
{ name: 'blue', code: 0x0000FF },
|
606
|
+
{ name: 'green', code: 0x00FF00 },
|
607
|
+
{ name: 'red', code: 0xFF0000 },
|
608
|
+
{ name: 'yellow', code: 0xFFFF00 },
|
609
|
+
];
|
610
|
+
↓
|
611
|
+
// 色名をキーにしたハッシュ構造
|
612
|
+
const COLOR_CODE_BY_NAME = {
|
613
|
+
blue: 0x0000FF,
|
614
|
+
green: 0x00FF00,
|
615
|
+
red: 0xFF0000,
|
616
|
+
yellow: 0xFFFF00,
|
617
|
+
};
|
618
|
+
|
619
|
+
= データ構造を変える(2/2)
|
620
|
+
|
621
|
+
const COLOR_CODES = [
|
622
|
+
{ name: 'blue', code: 0x0000FF },
|
623
|
+
{ name: 'green', code: 0x00FF00 },
|
624
|
+
{ name: 'red', code: 0xFF0000 },
|
625
|
+
{ name: 'yellow', code: 0xFFFF00 },
|
626
|
+
];
|
627
|
+
|
628
|
+
const COLOR_CODE_BY_NAME = {};
|
629
|
+
for (const item of COLOR_CODES) {
|
630
|
+
COLOR_CODE_BY_NAME[item.name] = item.code;
|
631
|
+
}
|
632
|
+
|
633
|
+
= 変換のコスト
|
634
|
+
|
635
|
+
* 何回も使うなら割に合う
|
636
|
+
* 1回しか使わなくても、\n
|
637
|
+
応答性を挙げたいときにも\n
|
638
|
+
(('note:(初期化に時間をかけてよければ)'))
|
639
|
+
|
640
|
+
= 計算量を小さくしやすいデータ構造にしよう
|
641
|
+
|
642
|
+
* 配列の全走査は基本的に遅い
|
643
|
+
* 配列は((*よく検索するキー*))で\n
|
644
|
+
ハッシュテーブルにしておく\n
|
645
|
+
(インデックス)
|
646
|
+
* 読み込んだデータはとりあえず\n
|
647
|
+
ハッシュテーブルにしがち
|
648
|
+
|
649
|
+
=
|
650
|
+
|
651
|
+
= 計算量を減らすには(3/3)
|
652
|
+
|
653
|
+
「求めたい結果」を変えてしまう
|
654
|
+
|
655
|
+
* 厳密な結果でなく\n
|
656
|
+
((*近似値*))でいいことにする
|
657
|
+
* ((*制約条件*))を設ける
|
658
|
+
|
659
|
+
= 巡回セールスマン問題
|
660
|
+
|
661
|
+
* 各町を1回ずつ訪問したい
|
662
|
+
* すべての町を訪問したい
|
663
|
+
* なるべく短い時間で済ませたい
|
664
|
+
|
665
|
+
時間が最も短く済むのは\n
|
666
|
+
どのような巡回ルートか?
|
667
|
+
|
668
|
+
|
669
|
+
= 巡回セールスマン問題なら
|
670
|
+
|
671
|
+
* 最適解を求めることを諦めて、\n
|
672
|
+
((*現実的な計算時間の範囲で*))\n
|
673
|
+
((*ほどほどにいい結果*))を求める
|
674
|
+
* 巡回できる町の\n
|
675
|
+
((*最大数を制限する*))
|
676
|
+
|
677
|
+
|
678
|
+
=
|
679
|
+
|
680
|
+
= 練習してみよう
|
681
|
+
|
682
|
+
* https://github.com\n
|
683
|
+
/clear-code\n
|
684
|
+
/readable-code-workshop\n
|
685
|
+
/tree/master/20220804\n
|
686
|
+
/0performance\n
|
687
|
+
/try.docx または try.pdf
|
688
|
+
|
689
|
+
== ノート
|
690
|
+
|
691
|
+
|
692
|
+
|
data/samples.pdf
ADDED
Binary file
|
data/try.pdf
ADDED
Binary file
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rabbit-slide-Piro-readable-code-workshop-2022-08-04-performance
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2022.08.04
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- YUKI Hiroshi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-08-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rabbit
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.0.2
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.0.2
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rabbit-theme-clear-code
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: 2022-08-04開催のリーダブルコード演習の予習としての、プログラムの実行性能の話。
|
42
|
+
email:
|
43
|
+
- yuki@clear-code.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- ".rabbit"
|
49
|
+
- README.rd
|
50
|
+
- Rakefile
|
51
|
+
- config.yaml
|
52
|
+
- images/graph-O1.png
|
53
|
+
- images/graph-ON.png
|
54
|
+
- images/graph-ON2.png
|
55
|
+
- images/graph-ONfactorial.png
|
56
|
+
- images/graph-OlogN.png
|
57
|
+
- pdf/readable-code-workshop-2022-08-04-performance-summary.pdf
|
58
|
+
- performance.rab
|
59
|
+
- samples.pdf
|
60
|
+
- try.pdf
|
61
|
+
homepage: http://slide.rabbit-shocker.org/authors/Piro/readable-code-workshop-2022-08-04-performance/
|
62
|
+
licenses:
|
63
|
+
- CC BY-SA 4.0
|
64
|
+
metadata: {}
|
65
|
+
post_install_message:
|
66
|
+
rdoc_options: []
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
requirements: []
|
80
|
+
rubyforge_project:
|
81
|
+
rubygems_version: 2.7.6
|
82
|
+
signing_key:
|
83
|
+
specification_version: 4
|
84
|
+
summary: プログラムの計算量と実行性能について
|
85
|
+
test_files: []
|