はじめに
30代になってから転職活動を経験した人なら共感してもらえると思いますが、コーディング面接って意外とアルゴリズムの知識を問われるんですよね。
普段の業務ではフレームワークやライブラリに頼りきりで、基本的なアルゴリズムを自分で実装する機会ってほとんどない。でも面接では「二分探索木を実装してください」とか言われる。これ、結構焦ります。
そんな時に見つけたのが「JavaScript Algorithms and Data Structures」というGitHubリポジトリです。
GitHubで195,000以上のスターを獲得している超人気プロジェクトで、JavaScriptで実装されたアルゴリズムとデータ構造が網羅的に学べます。個人的には、これがアルゴリズム学習の決定版だと思っています。
読むより先に、実際に手を動かして二分探索やソートの挙動を見た方が理解が早いと思います。先にサンプルを触りたい方はこちらからどうぞ。
JavaScript Algorithms and Data Structuresとは
trekhleb氏が作成した、JavaScriptによるアルゴリズムとデータ構造の実装集です。単なるコードの羅列ではなく、各実装に丁寧な解説とさらに学習するためのリンクが付いています。
基本情報
| 項目 | 内容 |
|---|---|
| リポジトリ | trekhleb/javascript-algorithms |
| GitHubスター | 195,000以上 |
| コントリビューター | 213人以上 |
| コミット数 | 約1,130件 |
| ライセンス | MIT |
驚くべきはそのスター数です。JavaScriptのリポジトリとしてはトップクラスの人気を誇っています。
特徴・メリット
1. 難易度別に分類されている
各アルゴリズムには「B(Beginner)」と「A(Advanced)」の難易度ラベルが付いています。自分のレベルに合わせて段階的に学習できるのがありがたい。
初心者はまずBラベルのものから始めて、自信がついたらAに進むという流れで学習できます。
2. 解説が丁寧
コードだけでなく、各アルゴリズムの概念説明、計算量(Big O記法)、関連するYouTube動画やWikipediaへのリンクが付いています。
正直なところ、ただコードを写経するだけでは理解できないことも多いんですよね。この解説があるおかげで、「なぜこのアルゴリズムが効率的なのか」という本質的な理解ができます。
3. テストコードが充実
すべての実装にはテストコードが付属しています。自分で修正したり、別の言語に移植したりする際に、動作確認ができるのは地味に便利です。
npm install
npm test
これだけで全テストを実行できます。
4. 幅広いカテゴリーをカバー
基本的なソートやサーチだけでなく、機械学習や画像処理のアルゴリズムまでカバーしています。
収録されているデータ構造
まずはデータ構造から見ていきましょう。
基礎的なデータ構造
- リンクリスト(Linked List)
- 双方向リンクリスト(Doubly Linked List)
- キュー(Queue)
- スタック(Stack)
- ハッシュテーブル(Hash Table)
- ヒープ(Heap)- 最大ヒープ、最小ヒープ
- 優先度キュー(Priority Queue)
これらは基本中の基本ですが、意外と「自分で実装してみて」と言われると詰まる人が多いんですよね。
高度なデータ構造
- トライ木(Trie)
- 二分探索木(Binary Search Tree)
- AVL木
- 赤黒木(Red-Black Tree)
- セグメント木(Segment Tree)
- フェニック木(Fenwick Tree)
- グラフ(Graph)
- 素集合データ構造(Disjoint Set)
- ブルームフィルター(Bloom Filter)
- LRUキャッシュ(LRU Cache)
LRUキャッシュなんかは、実際の業務でも使う機会があります。どういう仕組みで動いているか知っておくと、パフォーマンスチューニングの際に役立ちます。
収録されているアルゴリズム
数学系
// 例:ユークリッドの互除法(最大公約数)
function euclideanAlgorithm(originalA, originalB) {
const a = Math.abs(originalA);
const b = Math.abs(originalB);
if (b === 0) {
return a;
}
return euclideanAlgorithm(b, a % b);
}
階乗、フィボナッチ数列、素数判定、パスカルの三角形など、数学的なアルゴリズムが揃っています。
ソートアルゴリズム
- バブルソート [B]
- 選択ソート [B]
- 挿入ソート [B]
- マージソート [B]
- クイックソート [B]
- ヒープソート [B]
- シェルソート [B]
- カウンティングソート [B]
- 基数ソート [B]
ソートは面接でもよく出題されます。各アルゴリズムの時間計算量と空間計算量を理解しておくと、「なぜクイックソートが実用的なのか」といった質問にも答えられるようになります。
探索アルゴリズム
- 線形探索 [B]
- 二分探索 [B]
- ジャンプサーチ [B]
- 補間探索 [B]
グラフアルゴリズム
- 深さ優先探索(DFS)[B]
- 幅優先探索(BFS)[B]
- ダイクストラ法 [A]
- ベルマンフォード法 [A]
- クラスカル法 [A]
- プリム法 [A]
- トポロジカルソート [A]
グラフ系は難易度が高いですが、経路探索やネットワーク分析など、実務でも使う場面があります。
その他の注目アルゴリズム
- 動的計画法(ナップサック問題、最長共通部分列など)
- 文字列探索(KMP法、ラビン-カープ法など)
- 暗号系(シーザー暗号、多項式ハッシュなど)
- 機械学習(k-NN、k-Meansなど)
インストールと使い方
リポジトリのクローン
git clone https://github.com/trekhleb/javascript-algorithms.git
cd javascript-algorithms
依存関係のインストール
npm install
テストの実行
# 全テスト実行
npm test
# 特定のアルゴリズムのみ
npm test -- --grep="BinarySearch"
個別ファイルの確認
各アルゴリズムはsrcディレクトリ内に整理されています。
src/
├── algorithms/
│ ├── math/
│ ├── sorting/
│ ├── search/
│ └── ...
└── data-structures/
├── linked-list/
├── stack/
├── queue/
└── ...
各フォルダには実装ファイルとテストファイル、そしてREADMEが含まれています。
JavaScript Algorithms and Data Structuresのサンプルを動かす
JavaScript Algorithms and Data Structuresはnpmパッケージとしては配布されていません(npm installするのはリポジトリ自身の開発用依存関係だけです)。そこで、収録アルゴリズムの中でも特に面接頻出の「二分探索(Binary Search)」を、リポジトリの実装を参考に外部ライブラリなしのプレーンなJavaScriptでその場で動かせるようにしました。
二分探索は、ソート済み配列の中央値と探索対象を比較し、範囲を半分ずつ絞り込んでいくアルゴリズムです。要点だけ抜き出すと次のようになります。
function binarySearch(arr, target) {
let low = 0
let high = arr.length - 1
while (low <= high) {
const mid = Math.floor((low + high) / 2)
if (arr[mid] === target) return mid
if (arr[mid] < target) low = mid + 1
else high = mid - 1
}
return -1 // 見つからなかった場合
}
下のサンプルでは、このbinarySearchを実際に動かせます。入力欄に探したい値を入れると、その場で二分探索が実行され、何回の比較で見つかった(あるいは見つからなかった)かがコンソールと画面の両方に表示されます。
入力欄の値を57(配列の最大値)や1(配列に存在しない値)に変えてみると、比較回数やヒットの有無が変わるのが分かるはずです。配列の要素数をlength: 20からlength: 1000に増やしても、二分探索なら比較回数はほとんど増えません(線形探索と比べての計算量の差がここに表れています)。
実践的なユースケース
ケース1:コーディング面接対策
これが一番多いユースケースだと思います。LeetCodeやHackerRankの問題を解く前に、このリポジトリで基礎を固めておくと効率が良いです。
特に以下のアルゴリズムは頻出なので、優先的に学習することをおすすめします。
1. 二分探索
2. DFS/BFS
3. 動的計画法の基本パターン
4. ソートアルゴリズム(特にクイックソート、マージソート)
5. ハッシュテーブルの操作
ケース2:計算機科学の基礎学習
独学でプログラミングを始めた人は、情報科学の基礎が抜けていることがあります。このリポジトリは、大学のアルゴリズム入門講座で学ぶような内容をカバーしています。
ケース3:他言語への移植練習
JavaScriptで書かれた実装を、自分の得意な言語(Python、Go、Rustなど)に移植してみるのも良い練習になります。テストコードがあるので、正しく動作しているか確認しやすいです。
ケース4:コードレビューの参考
「このアルゴリズム、もっと効率的に書けないかな」と思ったときに、このリポジトリを参照すると良い実装例が見つかることがあります。
ソートアルゴリズムを比較する(バブルソート vs クイックソート)
JavaScript Algorithms and Data Structuresにはバブルソート・クイックソートをはじめ9種類のソートアルゴリズムが収録されています。同じ配列を両方のアルゴリズムでソートし、比較回数を並べて見ると、計算量の違いが体感できます。
function quickSort(arr) {
if (arr.length <= 1) return arr
const [pivot, ...rest] = arr
const left = rest.filter((n) => n < pivot)
const right = rest.filter((n) => n >= pivot)
return [...quickSort(left), pivot, ...quickSort(right)]
}
以下のサンプルでは、入力欄の配列(カンマ区切り)をバブルソートとクイックソートの両方で処理し、結果と比較回数を表示します。
配列の要素数を増やしたり、すでにソート済みの配列(1,2,3,4,5,6,7)を入れたりすると、バブルソートの比較回数がクイックソートより大きく増える様子が確認できます。これが「なぜクイックソートが実用的なのか」の実感につながります。
リンクリスト(Linked List)の操作を試す
リンクリストは、配列のインデックスの代わりに「次のノードへの参照」で要素をつなぐデータ構造です。JavaScript Algorithms and Data StructuresのLinkedList実装では、prepend(先頭に追加)やdeleteHead(先頭を削除)といったメソッドで操作します。
class LinkedListNode {
constructor(value, next = null) {
this.value = value
this.next = next
}
}
class LinkedList {
constructor() {
this.head = null
}
prepend(value) {
this.head = new LinkedListNode(value, this.head)
return this
}
deleteHead() {
if (!this.head) return null
const deleted = this.head
this.head = this.head.next
return deleted
}
}
下のサンプルでは、ボタンでリンクリストの先頭にノードを追加・削除でき、現在のLinkedListの中身がその都度画面に表示されます。
「先頭に追加」を連打すると新しいノードが次々とheadに差し込まれ、「先頭を削除」を押すたびにheadが1つ後ろのノードに置き換わるのが分かります。配列のunshift/shiftと違い、リンクリストの先頭操作は常に一定時間(O(1))で終わる点がポイントです。
幅優先探索(BFS)でグラフの最短経路を探す
幅優先探索(Breadth-First Search)は、グラフの探索アルゴリズムの一つで、開始ノードから近い順にノードを訪問していくことで最短経路を求められます。JavaScript Algorithms and Data Structuresのグラフアルゴリズムの中でも基礎に位置づけられる手法です。
function bfsShortestPath(graph, start, goal) {
const queue = [[start]]
const visited = new Set([start])
while (queue.length > 0) {
const path = queue.shift()
const node = path[path.length - 1]
if (node === goal) return path
for (const neighbor of graph[node]) {
if (!visited.has(neighbor)) {
visited.add(neighbor)
queue.push([...path, neighbor])
}
}
}
return null
}
以下のサンプルでは、6つのノード(A〜F)からなるグラフに対して、開始ノードと終了ノードをプルダウンで選ぶとbfsShortestPathが最短経路を探索します。
graphオブジェクトに新しいノードや接続を書き足すと、探索結果もその通りに変わります。例えばEとAを直接つなぐ行を追加すると、EからAへの最短経路が2ステップ短縮されるはずです。深さ優先探索(DFS)と違い、BFSはキュー(先入れ先出し)で管理するため、最初に見つかった経路が必ず最短になります。
効果的な学習方法
1. まず手を動かす
READMEを読むだけでなく、実際にコードを書いて動かしてみることが重要です。
// 自分でリンクリストを実装してみる
class LinkedListNode {
constructor(value, next = null) {
this.value = value;
this.next = next;
}
}
2. 計算量を意識する
各アルゴリズムには時間計算量と空間計算量が明記されています。「なぜこの計算量になるのか」を考えながら学習すると理解が深まります。
3. 段階的に進める
いきなり赤黒木やダイクストラ法に挑戦するのではなく、基礎的なデータ構造から順番に学んでいくのがおすすめです。
Week 1: リンクリスト、スタック、キュー
Week 2: 二分探索木、ヒープ
Week 3: ソートアルゴリズム
Week 4: グラフの基礎(DFS、BFS)
リポジトリへのアクセス
GitHub: https://github.com/trekhleb/javascript-algorithms
日本語への翻訳も有志によって進められています。英語が苦手な方でも学習しやすい環境が整っています。
まとめ
JavaScript Algorithms and Data Structuresは、アルゴリズムとデータ構造を学ぶための最高のリソースの一つです。
特に良いと思った点は以下の通りです。
- 195,000スターという圧倒的な信頼性
- 難易度別の分類で段階的に学習できる
- 解説とテストコードが充実している
- 基礎から機械学習まで幅広くカバー
- MITライセンスで自由に利用できる
正直なところ、アルゴリズムの勉強は地味で大変です。でも、30代になって転職を考えたとき、この基礎力が差をつけるポイントになるんですよね。
毎日30分でもいいので、少しずつ進めていくことをおすすめします。一度理解すれば忘れにくい知識なので、投資する価値は十分にあります。
コーディング面接対策としてはもちろん、純粋にエンジニアとしてのスキルアップにも繋がるリポジトリです。ぜひ活用してみてください。