アルアカ - Arcadia Academia

Arcadia Academiaは「エンジニアリングを楽しむ」を合言葉に日本のデジタル競争力を高めることをミッションとするテックコミュニティです。

TypeScriptでのグラフ理論の学習ガイド

Featured image of the post

TypeScriptを活用してグラフ理論を学ぶことは、理論の理解を深めるだけでなく、プログラミングスキルの向上にもつながります。本記事では、TypeScriptを使用したグラフの基本的な実装からアルゴリズムの適用例までを解説します。

グラフ理論ってなに?というところからおさらいしたい方は以下の記事を参照してください。

📄Arrow icon of a page linkグラフ理論における「グラフ」とは?


[目次を開く]

1. TypeScriptでグラフを実装する

隣接リストの実装

隣接リストは、メモリ効率が高く、スパースグラフに適しています。TypeScriptで隣接リストを実装する方法を以下に示します。

class Graph {
    private adjacencyList: Map<string, string[]>;

    constructor() {
        this.adjacencyList = new Map();
    }

    addVertex(vertex: string): void {
        if (!this.adjacencyList.has(vertex)) {
            this.adjacencyList.set(vertex, []);
        }
    }

    addEdge(vertex1: string, vertex2: string): void {
        this.adjacencyList.get(vertex1)?.push(vertex2);
        this.adjacencyList.get(vertex2)?.push(vertex1); // 無向グラフの場合
    }

    displayGraph(): void {
        for (const [vertex, edges] of this.adjacencyList) {
            console.log(`${vertex} -> ${edges.join(", ")}`);
        }
    }
}

// 使用例
const graph = new Graph();
graph.addVertex("A");
graph.addVertex("B");
graph.addVertex("C");
graph.addEdge("A", "B");
graph.addEdge("A", "C");
graph.displayGraph();

上記のコードでは、頂点を追加し、それらを結ぶ辺を作成しています。グラフ全体を隣接リストの形式で出力可能です。

上記のコードのイメージ

Image in a image block

グラフ理論におけるノードは、ドットや丸で表します。ノード間の接続はエッジと呼ばれる線で表現されます。


2. 基本アルゴリズムの実装

深さ優先探索(DFS)

深さ優先探索は、再帰を用いることで簡潔に実装できます。

class DFSGraph extends Graph {
    dfs(start: string): void {
        const visited = new Set<string>();

        const dfsHelper = (vertex: string) => {
            if (!vertex || visited.has(vertex)) return;
            visited.add(vertex);
            console.log(vertex);

            for (const neighbor of this.adjacencyList.get(vertex) || []) {
                dfsHelper(neighbor);
            }
        };

        dfsHelper(start);
    }
}

// 使用例
const dfsGraph = new DFSGraph();
dfsGraph.addVertex("A");
dfsGraph.addVertex("B");
dfsGraph.addVertex("C");
dfsGraph.addEdge("A", "B");
dfsGraph.addEdge("A", "C");
dfsGraph.dfs("A");

幅優先探索(BFS)

BFSはキューを使用して、各層ごとに探索を進めます。

class BFSGraph extends Graph {
    bfs(start: string): void {
        const visited = new Set<string>();
        const queue: string[] = [start];

        while (queue.length > 0) {
            const vertex = queue.shift()!;
            if (!visited.has(vertex)) {
                visited.add(vertex);
                console.log(vertex);

                for (const neighbor of this.adjacencyList.get(vertex) || []) {
                    if (!visited.has(neighbor)) {
                        queue.push(neighbor);
                    }
                }
            }
        }
    }
}

// 使用例
const bfsGraph = new BFSGraph();
bfsGraph.addVertex("A");
bfsGraph.addVertex("B");
bfsGraph.addVertex("C");
bfsGraph.addEdge("A", "B");
bfsGraph.addEdge("A", "C");
bfsGraph.bfs("A");


3. 応用アルゴリズムの実装

ダイクストラ法(最短経路探索)

重み付きグラフを用いた最短経路アルゴリズムです。

class WeightedGraph {
    private adjacencyList: Map<string, [string, number][]>;

    constructor() {
        this.adjacencyList = new Map();
    }

    addVertex(vertex: string): void {
        if (!this.adjacencyList.has(vertex)) {
            this.adjacencyList.set(vertex, []);
        }
    }

    addEdge(vertex1: string, vertex2: string, weight: number): void {
        this.adjacencyList.get(vertex1)?.push([vertex2, weight]);
        this.adjacencyList.get(vertex2)?.push([vertex1, weight]);
    }

    dijkstra(start: string, finish: string): void {
        const distances: { [key: string]: number } = {};
        const previous: { [key: string]: string | null } = {};
        const queue: [string, number][] = [];

        for (const vertex of this.adjacencyList.keys()) {
            if (vertex === start) {
                distances[vertex] = 0;
                queue.push([vertex, 0]);
            } else {
                distances[vertex] = Infinity;
            }
            previous[vertex] = null;
        }

        while (queue.length) {
            const [currentVertex] = queue.shift()!;
            if (currentVertex === finish) break;

            for (const [neighbor, weight] of this.adjacencyList.get(currentVertex) || []) {
                const distance = distances[currentVertex] + weight;
                if (distance < distances[neighbor]) {
                    distances[neighbor] = distance;
                    previous[neighbor] = currentVertex;
                    queue.push([neighbor, distance]);
                }
            }
        }

        console.log("最短経路の距離:", distances[finish]);
    }
}

// 使用例
const weightedGraph = new WeightedGraph();
weightedGraph.addVertex("A");
weightedGraph.addVertex("B");
weightedGraph.addVertex("C");
weightedGraph.addVertex("D");
weightedGraph.addVertex("E");
weightedGraph.addVertex("F");
weightedGraph.addEdge("A", "B", 4);
weightedGraph.addEdge("A", "C", 2);
weightedGraph.addEdge("C", "D", 3);
weightedGraph.addEdge("C", "D", 3);
weightedGraph.addEdge("D", "E", 1);
weightedGraph.addEdge("B", "F", 2);
weightedGraph.addEdge("E", "F", 3);
weightedGraph.dijkstra("A", "F");

上記のコードのイメージ

Image in a image block

weightedGraph.dijkstra("A", "F"); で頂点Aから頂点Fまでの最短経路を出力します。


4. 学習の次のステップ

TypeScriptを使用してグラフ理論を学ぶ際は、以下の点にも取り組むと良いでしょう:

  1. 実践課題
    • 実際の交通ネットワークやソーシャルグラフをモデリングして、アルゴリズムを試します。
  2. ライブラリを活用
    • D3.jsやGraphlibなどのグラフライブラリを組み合わせて視覚化に挑戦します。
  3. 応用アルゴリズム
    • クラスカル法やフロイド・ワーシャル法など、高度なアルゴリズムを実装します。

まとめ

TypeScriptを使用したグラフ理論の学習は、実際にコードを書きながら理論を深く理解できるため、非常に効果的です。データ構造とアルゴリズムの知識を実践に活用し、問題解決能力を向上させましょう。

プログラミング学習でお悩みですか?

現役エンジニアがあなたの学習をマンツーマンでサポートします。

  • 学習の進め方がわからない
  • ポートフォリオの作り方を知りたい
  • 現場で使える技術を学びたい
まずは30分の無料相談

相談は完全無料・オンラインで気軽に

あなたを爆速で成長させるメンタリングプログラムはこちら

メンタープログラムバナー

プログラミングを学ぶならテックアカデミー

テックアカデミー
無料相談はこちら