Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【PHP8.x】SplMaxHeap::compare()メソッドの使い方

compareメソッドの使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

compareメソッドは、PHPのSplMaxHeapクラスにおいて、ヒープ内の要素間の順序を決定するための比較ロジックを実行するメソッドです。SplMaxHeapは、常に最大値を持つ要素を効率的に取り出せるように設計された「最大ヒープ」というデータ構造を表します。このヒープがどの要素を「最大」と見なすかを判断する際に、このcompareメソッドが利用されます。

具体的には、このメソッドは2つの要素($value1$value2)を引数として受け取り、それらを比較して整数値を返します。$value1$value2よりも大きいと判断される場合は正の整数を、$value1$value2よりも小さいと判断される場合は負の整数を、そして両者が等しいと判断される場合はゼロを返します。SplMaxHeapは、この戻り値に基づいて要素の相対的な位置を決定し、ヒープ構造を適切に維持します。

デフォルトでは、数値や文字列などの標準的な比較が行われますが、開発者がSplMaxHeapを継承して独自のヒープクラスを作成する際に、このcompareメソッドをオーバーライド(上書き)することができます。これにより、例えばカスタムオブジェクトの特定のプロパティを基準に比較したり、独自の複雑なルールに基づいて要素の大小を定義したりすることが可能になります。この柔軟性により、様々なデータ型や要件に合わせた最大ヒープを効率的に実装できます。

構文(syntax)

1<?php
2
3class MyCustomMaxHeap extends SplMaxHeap
4{
5    /**
6     * 2つの値を比較し、最大ヒープにおける要素の順序を決定します。
7     * $value1 が $value2 よりも大きい(優先される)場合に正の値を返します。
8     *
9     * @param mixed $value1 比較対象の最初の値
10     * @param mixed $value2 比較対象の2番目の値
11     * @return int $value1 が $value2 より大きい場合は正、小さい場合は負、等しい場合は0
12     */
13    protected function compare(mixed $value1, mixed $value2): int
14    {
15        // ここに独自の比較ロジックを実装します。
16        // 例: 数値を比較し、大きい方を優先する場合
17        return $value1 <=> $value2;
18    }
19}

引数(parameters)

mixed $value1, mixed $value2

PHP:

  • mixed $value1: 比較対象となる最初の値
  • mixed $value2: 比較対象となる2番目の値

戻り値(return)

int

SplMaxHeap::compare メソッドは、2つの要素の比較結果を整数で返します。 返り値は、最初の要素が2番目の要素より大きい場合は正の値、等しい場合は0、小さい場合は負の値となります。

サンプルコード

PHP SplMaxHeap で配列をスコア順に並べ替える

1<?php
2
3/**
4 * SplMaxHeap を継承したカスタムヒープクラスです。
5 * 配列を要素として扱い、配列内の 'score' キーの値に基づいて比較を行います。
6 * SplMaxHeap は最大ヒープであり、最もスコアの高い配列が常に先頭に配置されます。
7 */
8class CustomArrayHeap extends SplMaxHeap
9{
10    /**
11     * ヒープ内の2つの要素 (ここでは配列) を比較します。
12     * このメソッドをオーバーライドすることで、ヒープの比較ロジックをカスタマイズできます。
13     *
14     * @param mixed $value1 比較する最初の要素 (配列を想定)
15     * @param mixed $value2 比較する2番目の要素 (配列を想定)
16     * @return int 比較結果。
17     *             $value1 の方が大きい場合は正の数、
18     *             $value1 の方が小さい場合は負の数、
19     *             等しい場合は 0 を返します。
20     */
21    protected function compare(mixed $value1, mixed $value2): int
22    {
23        // 配列の 'score' キーの値で比較を行います。
24        // 配列に 'score' キーが存在しない場合は 0 をデフォルト値とします。
25        $score1 = $value1['score'] ?? 0;
26        $score2 = $value2['score'] ?? 0;
27
28        // PHP 7 以降の宇宙船演算子 (spaceship operator) を使用して比較します。
29        // $score1 が $score2 より大きい場合は 1、
30        // $score1 が $score2 より小さい場合は -1、
31        // 等しい場合は 0 を返します。
32        return $score1 <=> $score2;
33    }
34}
35
36/**
37 * カスタム配列ヒープの使用例をデモンストレーションする関数です。
38 */
39function demonstrateCustomArrayHeap(): void
40{
41    echo "--- カスタム配列ヒープのデモンストレーション ---\n";
42
43    // カスタムヒープのインスタンスを作成します。
44    $heap = new CustomArrayHeap();
45
46    // 複数の配列をヒープに追加します。
47    // 各配列は 'name' と 'score' の情報を持っています。
48    $heap->insert(['name' => 'Alice', 'score' => 85]);
49    $heap->insert(['name' => 'Bob', 'score' => 92]);
50    $heap->insert(['name' => 'Charlie', 'score' => 78]);
51    $heap->insert(['name' => 'David', 'score' => 95]);
52    $heap->insert(['name' => 'Eve', 'score' => 88]);
53
54    echo "ヒープに追加された要素数: " . $heap->count() . "\n";
55
56    // ヒープの先頭要素 (最もスコアが高い要素) を確認します。
57    echo "ヒープの先頭要素 (最もスコアが高い): \n";
58    print_r($heap->top());
59
60    echo "\nヒープから要素を順番に取り出します (スコアが高い順):\n";
61    // ヒープが空になるまで要素を取り出します。
62    // SplMaxHeap のため、extract() は常に現在の最大要素を返します。
63    while (!$heap->isEmpty()) {
64        $element = $heap->extract();
65        echo "  - " . $element['name'] . " (スコア: " . $element['score'] . ")\n";
66    }
67
68    echo "\nヒープが空になりました。\n";
69}
70
71// デモンストレーション関数を実行します。
72demonstrateCustomArrayHeap();
73
74?>

PHP 8のSplMaxHeapクラスは、要素を効率的に管理し、常に最大の要素を先頭に保つデータ構造です。この「最大」が何であるかを定義するのが、compareメソッドの役割です。

提供されたサンプルコードでは、SplMaxHeapを継承したCustomArrayHeapクラスが作成され、配列を要素として扱います。特に、protected function compare(mixed $value1, mixed $value2): intがオーバーライドされており、このメソッドは比較対象となる二つの要素$value1$value2(ここでは配列)を受け取ります。そして、それぞれの配列が持つ'score'キーの値に基づいて比較を行い、その大小関係を示す整数(int)を返します。具体的には、$value1のスコアが$value2より大きい場合は正の数、小さい場合は負の数、等しい場合は0を返します。ここではPHP 7以降で導入された宇宙船演算子<=>が利用され、この比較ロジックが簡潔に記述されています。

これにより、CustomArrayHeapは、scoreの値が最も高い配列を最大の要素として認識します。そのため、insertメソッドで複数の配列要素を追加した後、topメソッドで常に最もスコアの高い配列を確認でき、extractメソッドを繰り返し実行することで、スコアの高い配列から順に要素を取り出すことが可能になります。この例は、compareメソッドをカスタマイズすることで、配列のような複雑なデータ構造も独自の基準でソート(並べ替え)できることを示しています。

このcompareメソッドは、ヒープ内の要素の順序を決定する非常に重要な部分です。戻り値のルール(正の数、負の数、ゼロ)を正しく守らないと、ヒープが意図しない並び順になります。サンプルコードは配列の'score'キーで比較していますが、compareメソッドはあらゆる型の比較ロジックを自由に定義できます。ただし、比較対象が想定する形式(ここでは'score'キーを持つ配列)であることを前提としているため、異なるデータが混入すると予期せぬエラーや挙動の原因となります。?? 0でキーがない場合に対応していますが、データ形式が厳密な場合は、型チェックや例外処理を追加して堅牢性を高めることもご検討ください。SplMaxHeapは常に最大の要素を取り出します。

PHP SplMaxHeap でオブジェクトを比較する

1<?php
2
3/**
4 * 比較対象となるタスクのクラス。
5 * タスク名と優先度を持つシンプルなオブジェクトです。
6 */
7class Task
8{
9    /**
10     * コンストラクタでタスク名と優先度を初期化します。
11     *
12     * @param string $name タスクの名前
13     * @param int $priority タスクの優先度 (数値が大きいほど優先度が高い)
14     */
15    public function __construct(
16        public string $name,
17        public int $priority
18    ) {}
19
20    /**
21     * オブジェクトを文字列に変換する際に使用されます。デバッグ出力などに便利です。
22     *
23     * @return string タスクの情報を表す文字列
24     */
25    public function __toString(): string
26    {
27        return "Task: {$this->name}, Priority: {$this->priority}";
28    }
29}
30
31/**
32 * SplMaxHeapを継承し、Taskオブジェクトのpriorityプロパティに基づいて比較するカスタムヒープです。
33 * SplMaxHeapは「最大ヒープ」であるため、compareメソッドで「大きい」と判断された要素が
34 * ヒープの最上位(つまり、extractメソッドで最初に取り出される要素)になります。
35 * このクラスでは、Taskオブジェクトのpriorityがより高い(数値が大きい)ものを「大きい」と判断します。
36 */
37class TaskPriorityMaxHeap extends SplMaxHeap
38{
39    /**
40     * 2つの値(この場合はTaskオブジェクト)を比較し、その相対的な順序を決定します。
41     * このメソッドはSplMaxHeapの内部で使用され、ヒープ内の要素の順序付けに利用されます。
42     *
43     * @param mixed $value1 比較対象の最初の値 (Taskオブジェクトを想定)
44     * @param mixed $value2 比較対象の2番目の値 (Taskオブジェクトを想定)
45     * @return int `$value1`が`$value2`より大きい場合は正の整数、小さい場合は負の整数、
46     *             等しい場合は0を返します。
47     */
48    protected function compare(mixed $value1, mixed $value2): int
49    {
50        // PHP 8では$value1と$value2はmixed型として渡されますが、
51        // このヒープはTaskオブジェクトを扱うことを前提としています。
52        // @varアノテーションはIDEが型ヒントを認識するために役立ちます。
53        /** @var Task $task1 */
54        $task1 = $value1;
55        /** @var Task $task2 */
56        $task2 = $value2;
57
58        // Taskオブジェクトのpriorityプロパティを比較します。
59        // priorityの値が大きいほど、そのタスクは「大きい」とみなされます。
60        // 例: $task1->priority = 5, $task2->priority = 3 の場合、5 - 3 = 2 (正の数)
61        //     -> $task1 が $task2 より大きいと判断され、SplMaxHeapでは $task1 が優先されます。
62        // 例: $task1->priority = 2, $task2->priority = 4 の場合、2 - 4 = -2 (負の数)
63        //     -> $task1 が $task2 より小さいと判断されます。
64        return $task1->priority - $task2->priority;
65    }
66}
67
68// -----------------------------------------------------------------------------
69// サンプルコードの実行部分
70// -----------------------------------------------------------------------------
71
72// カスタムヒープのインスタンスを作成します。
73$taskHeap = new TaskPriorityMaxHeap();
74
75echo "ヒープにタスクオブジェクトを追加:\n";
76// いくつかのTaskオブジェクトを作成し、ヒープに追加します。
77// SplMaxHeapは自動的にcompareメソッドを使用して、要素を優先度順に並べ替えます。
78$taskHeap->insert(new Task('ドキュメント作成', 2));
79echo "  - " . (new Task('ドキュメント作成', 2)) . "\n";
80$taskHeap->insert(new Task('緊急バグ修正', 5));
81echo "  - " . (new Task('緊急バグ修正', 5)) . "\n";
82$taskHeap->insert(new Task('新機能実装', 3));
83echo "  - " . (new Task('新機能実装', 3)) . "\n";
84$taskHeap->insert(new Task('コードリファクタリング', 1));
85echo "  - " . (new Task('コードリファクタリング', 1)) . "\n";
86$taskHeap->insert(new Task('アップデート展開', 4));
87echo "  - " . (new Task('アップデート展開', 4)) . "\n";
88echo "\n";
89
90echo "ヒープからタスクを抽出 (priorityが高いものから順に取り出されます):\n";
91// ヒープが空になるまで、要素を一つずつ抽出します。
92// SplMaxHeapは常に最も「大きい」要素(この場合はpriorityが最も高いTask)を返します。
93while (!$taskHeap->isEmpty()) {
94    /** @var Task $task */
95    $task = $taskHeap->extract(); // ヒープから最大の要素を取り除き、返します
96    echo "  - 抽出されたタスク: {$task->name} (Priority: {$task->priority})\n";
97}
98
99?>

このPHPサンプルコードは、PHP標準ライブラリの SplMaxHeap クラスで要素の順序をカスタマイズする方法を、compare メソッドを通じて示しています。SplMaxHeap は、追加された要素の中から常に「最大」と判断される要素を効率的に取り出す「最大ヒープ」というデータ構造を提供します。

compare メソッドは、ヒープ内で2つの要素の相対的な大小関係を決定するために内部的に呼び出されるprotectedメソッドです。引数 $value1$value2 には比較対象となる2つの値(この例では Task オブジェクト)が渡されます。このメソッドは int を戻り値として返し、$value1$value2 より大きい場合は正の整数、小さい場合は負の整数、等しい場合はゼロを返します。SplMaxHeap はこの戻り値に基づいて要素をヒープ内に適切に配置します。

サンプルコードでは、タスク名と優先度を持つ Task クラスを定義し、それを扱うために SplMaxHeap を継承した TaskPriorityMaxHeap クラスを作成しています。このカスタムヒープクラスでは、compare メソッドをオーバーライドし、Task オブジェクトの priority プロパティの差を比較結果として返すように実装しています。これにより、priority の値が大きいタスクほど「最大」と判断され、ヒープの最上位に配置されるようになります。実際にタスクをヒープに追加し、extract メソッドで取り出すと、優先度の高いタスクから順に取り出される動作を確認できます。このように compare メソッドをカスタムすることで、任意のオブジェクトの特定のプロパティに基づいた優先度処理を柔軟に実現できるのです。

このサンプルコードでは、SplMaxHeapを継承し、compareメソッドをオーバーライドすることで、カスタムオブジェクトを優先度順に扱う方法を示しています。compareメソッドは、$value1$value2より大きい場合は正の整数、小さい場合は負の整数、等しい場合はゼロを返さなければなりません。SplMaxHeapは、この比較結果で「大きい」と判断された要素を最も優先して取り出すため、この戻り値の意味を誤ると期待と逆の順序になってしまいます。

また、compareメソッドの引数はmixed型ですが、この実装ではTaskオブジェクトが渡される前提です。もし異なる型の値が渡される可能性がある場合は、予期せぬエラーを防ぐために、メソッド内で明示的な型チェックやバリデーションを追加することが安全なコード作りに繋がります。オブジェクトの複数のプロパティを組み合わせて比較するなど、より複雑なロジックを実装することも可能です。

関連コンテンツ