PHPで実装するキューとスタック:配列と連結リストによるデータ構造の基礎

キュー(Queue)の基本概念

キューは先入先出(FIFO: First In, First Out)の原則に従う線形データ構造です。データの追加(エンキュー)は末尾でのみ行われ、データの削除(デキュー)は先頭でのみ行われます。PHPの組み込み関数を使用する場合、array_push() または配列の代入で末尾に要素を追加し、array_shift() で先頭の要素を削除することでキューの動作を再現できます。

配列を用いたキューの実装

PHPの配列は動的にサイズが変更されるため、キューの実装に非常に適しています。以下のコードは、配列を利用したキューのクラス実装です。型宣言と例外処理を用いて、より堅牢な設計にしています。

<?php

class ArrayQueue {
    private array $items = [];

    public function size(): int {
        return count($this->items);
    }

    public function isEmpty(): bool {
        return $this->size() === 0;
    }

    public function enqueue(mixed $value): void {
        $this->items[] = $value;
    }

    public function dequeue(): mixed {
        if ($this->isEmpty()) {
            throw new UnderflowException("キューが空です");
        }
        return array_shift($this->items);
    }
    
    public function peek(): mixed {
        if ($this->isEmpty()) {
            throw new UnderflowException("キューが空です");
        }
        return $this->items[0];
    }
}

連結リストを用いたキューの実装

連結リストを用いることで、メモリを動的に確保するキューを構築できます。効率的な操作のため、先頭(ヘッド)と末尾(テール)の両方のポインタを維持し、エンキューとデキューをO(1)の計算量で実行できるように設計します。

<?php

class QueueNode {
    public function __construct(
        public mixed $value,
        public ?QueueNode $next = null
    ) {}
}

class LinkedQueue {
    private ?QueueNode $head = null;
    private ?QueueNode $tail = null;
    private int $count = 0;

    public function isEmpty(): bool {
        return $this->count === 0;
    }

    public function enqueue(mixed $value): void {
        $newNode = new QueueNode($value);
        if ($this->tail === null) {
            $this->head = $this->tail = $newNode;
        } else {
            $this->tail->next = $newNode;
            $this->tail = $newNode;
        }
        $this->count++;
    }

    public function dequeue(): mixed {
        if ($this->isEmpty()) {
            throw new UnderflowException("キューが空です");
        }
        $value = $this->head->value;
        $this->head = $this->head->next;
        if ($this->head === null) {
            $this->tail = null;
        }
        $this->count--;
        return $value;
    }
}

スタック(Stack)の基本概念

スタックは後入先出(LIFO: Last In, First Out)の原則に従うデータ構造です。データの追加(プッシュ)と削除(ポップ)は、常に同じ端(スタックのトップ)で行われます。PHPでは、array_push() で要素を追加し、array_pop() で末尾の要素を削除することでスタックを実現できます。

配列を用いたスタックの実装

配列を用いたスタックは、PHPの動的配列の特性を活かしてシンプルかつ効率的に実装できます。

<?php

class ArrayStack {
    private array $elements = [];

    public function size(): int {
        return count($this->elements);
    }

    public function isEmpty(): bool {
        return $this->size() === 0;
    }

    public function push(mixed $value): void {
        $this->elements[] = $value;
    }

    public function pop(): mixed {
        if ($this->isEmpty()) {
            throw new UnderflowException("スタックが空です");
        }
        return array_pop($this->elements);
    }

    public function peek(): mixed {
        if ($this->isEmpty()) {
            throw new UnderflowException("スタックが空です");
        }
        return $this->elements[$this->size() - 1];
    }
}

連結リストを用いたスタックの実装

連結リストでスタックを実装する場合、リストの先頭をスタックのトップとして扱います。これにより、ノードの走査を不要にし、プッシュとポップの操作をO(1)の計算量で完了させることができます。

<?php

class StackNode {
    public function __construct(
        public mixed $value,
        public ?StackNode $next = null
    ) {}
}

class LinkedStack {
    private ?StackNode $top = null;
    private int $count = 0;

    public function isEmpty(): bool {
        return $this->count === 0;
    }

    public function push(mixed $value): void {
        $newNode = new StackNode($value, $this->top);
        $this->top = $newNode;
        $this->count++;
    }

    public function pop(): mixed {
        if ($this->isEmpty()) {
            throw new UnderflowException("スタックが空です");
        }
        $value = $this->top->value;
        $this->top = $this->top->next;
        $this->count--;
        return $value;
    }
}

タグ: PHP データ構造 アルゴリズム キュー スタック

9月14日 11:19 投稿