Skip to content

feat: Refactor ArrayQueue, Create CircularArrayQueue, Refactor ArrayD… #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

68 changes: 3 additions & 65 deletions src/Queue/ArrayDeque.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace KaririCode\DataStructure\Queue;

use KaririCode\Contract\DataStructure\Deque;
use KaririCode\Contract\DataStructure\Queue;

/**
Expand All @@ -16,45 +17,9 @@
*
* @implements Queue<mixed>
*/
class ArrayDeque implements Queue
{
private array $elements;
private int $front = 0;
private int $size = 0;
private int $capacity;

public function __construct(int $initialCapacity = 16)
{
$this->capacity = $initialCapacity;
$this->elements = array_fill(0, $this->capacity, null);
}

public function enqueue(mixed $element): void
{
$this->ensureCapacity();
$index = ($this->front + $this->size) % $this->capacity;
$this->elements[$index] = $element;
++$this->size;
}

public function dequeue(): mixed
{
if ($this->isEmpty()) {
return null;
}
$element = $this->elements[$this->front];
$this->elements[$this->front] = null;
$this->front = ($this->front + 1) % $this->capacity;
--$this->size;

return $element;
}

public function peek(): mixed
{
return $this->isEmpty() ? null : $this->elements[$this->front];
}

class ArrayDeque extends CircularArrayQueue implements Deque
{
public function addFirst(mixed $element): void
{
$this->ensureCapacity();
Expand Down Expand Up @@ -85,31 +50,4 @@ public function peekLast(): mixed

return $this->elements[$index];
}

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

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

/**
* Ensures that the deque has enough capacity to add a new element.
*/
private function ensureCapacity(): void
{
if ($this->size === $this->capacity) {
$newCapacity = $this->capacity * 2;
$newElements = array_fill(0, $newCapacity, null);
for ($i = 0; $i < $this->size; ++$i) {
$newElements[$i] = $this->elements[($this->front + $i) % $this->capacity];
}
$this->elements = $newElements;
$this->front = 0;
$this->capacity = $newCapacity;
}
}
}
67 changes: 3 additions & 64 deletions src/Queue/ArrayQueue.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,69 +19,8 @@
*
* @see https://kariricode.org/
*/
class ArrayQueue implements Queue
{
private array $elements;
private int $front = 0;
private int $size = 0;
private int $capacity;

public function __construct(int $initialCapacity = 16)
{
$this->capacity = $initialCapacity;
$this->elements = array_fill(0, $this->capacity, null);
}

public function enqueue(mixed $element): void
{
$this->ensureCapacity();
$index = ($this->front + $this->size) % $this->capacity;
$this->elements[$index] = $element;
++$this->size;
}

public function dequeue(): mixed
{
if ($this->isEmpty()) {
return null;
}
$element = $this->elements[$this->front];
$this->elements[$this->front] = null;
$this->front = ($this->front + 1) % $this->capacity;
--$this->size;

return $element;
}

public function peek(): mixed
{
return $this->isEmpty() ? null : $this->elements[$this->front];
}

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

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

/**
* Ensures that the queue has enough capacity to add a new element.
*/
private function ensureCapacity(): void
{
if ($this->size === $this->capacity) {
$newCapacity = $this->capacity * 2;
$newElements = array_fill(0, $newCapacity, null);
for ($i = 0; $i < $this->size; ++$i) {
$newElements[$i] = $this->elements[($this->front + $i) % $this->capacity];
}
$this->elements = $newElements;
$this->front = 0;
$this->capacity = $newCapacity;
}
}
class ArrayQueue extends CircularArrayQueue implements Queue
{
// No additional methods required, uses methods from CircularArrayQueue
}
99 changes: 99 additions & 0 deletions src/Queue/CircularArrayQueue.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php

declare(strict_types=1);

namespace KaririCode\DataStructure\Queue;

use KaririCode\Contract\DataStructure\Queue;

/**
* CircularArrayQueue implementation.
*
* This class provides the common functionality for array-based queues using a circular array.
*
* @category Queues
*
* @author Walmir Silva <walmir.silva@kariricode.org>
* @license MIT
*
* @see https://kariricode.org/
*/
abstract class CircularArrayQueue implements Queue
{
protected array $elements;
protected int $front = 0;
protected int $size = 0;
protected int $capacity;

public function __construct(int $initialCapacity = 16)
{
$this->capacity = $initialCapacity;
$this->elements = array_fill(0, $this->capacity, null);
}

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

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

public function clear(): void
{
$this->elements = array_fill(0, $this->capacity, null);
$this->front = 0;
$this->size = 0;
}

protected function ensureCapacity(): void
{
if ($this->size === $this->capacity) {
$newCapacity = $this->capacity * 2;
$newElements = array_fill(0, $newCapacity, null);
for ($i = 0; $i < $this->size; ++$i) {
$newElements[$i] = $this->elements[($this->front + $i) % $this->capacity];
}
$this->elements = $newElements;
$this->front = 0;
$this->capacity = $newCapacity;
}
}

public function peek(): mixed
{
return $this->isEmpty() ? null : $this->elements[$this->front];
}

public function dequeue(): mixed
{
if ($this->isEmpty()) {
return null;
}
$element = $this->elements[$this->front];
$this->elements[$this->front] = null;
$this->front = ($this->front + 1) % $this->capacity;
--$this->size;

return $element;
}

public function enqueue(mixed $element): void
{
$this->ensureCapacity();
$index = ($this->front + $this->size) % $this->capacity;
$this->elements[$index] = $element;
++$this->size;
}

public function getItems(): array
{
$items = [];
for ($i = 0; $i < $this->size; ++$i) {
$items[] = $this->elements[($this->front + $i) % $this->capacity];
}
return $items;
}
}
65 changes: 65 additions & 0 deletions tests/Queue/ArrayDequeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,69 @@ public function testDequeBehaviorAfterMixedOperations(): void
$this->assertSame(1, $deque->dequeue());
$this->assertSame(3, $deque->peekLast());
}

// Test capacity expansion during addFirst operations
public function testEnsureCapacityExpandsDuringAddFirstOperations(): void
{
$deque = new ArrayDeque(2);
$deque->addFirst(1);
$deque->addFirst(2);
$deque->addFirst(3); // Should trigger capacity increase
$this->assertSame(3, $deque->size());
$this->assertSame(3, $deque->peek());
$this->assertSame(1, $deque->peekLast());
}

// Test capacity expansion during removeLast operations
public function testEnsureCapacityExpandsDuringRemoveLastOperations(): void
{
$deque = new ArrayDeque(2);
$deque->enqueue(1);
$deque->enqueue(2);
$deque->enqueue(3); // Should trigger capacity increase
$deque->removeLast();
$deque->removeLast();
$this->assertSame(1, $deque->size());
$this->assertSame(1, $deque->peek());
}

// Test mixed operations of addFirst, addLast, removeFirst, and removeLast
public function testMixedOperations(): void
{
$deque = new ArrayDeque();
$deque->addFirst(1);
$deque->enqueue(2);
$deque->addFirst(0);
$this->assertSame(0, $deque->dequeue());
$this->assertSame(1, $deque->dequeue());
$this->assertSame(2, $deque->removeLast());
$deque->enqueue(3);
$deque->addFirst(4);
$this->assertSame(4, $deque->peek());
$this->assertSame(3, $deque->peekLast());
}

// Test clearing the deque
public function testClearEmptiesTheDeque(): void
{
$deque = new ArrayDeque();
$deque->enqueue(1);
$deque->enqueue(2);
$deque->clear();
$this->assertTrue($deque->isEmpty());
$this->assertNull($deque->peek());
$this->assertNull($deque->peekLast());
$this->assertNull($deque->dequeue());
$this->assertNull($deque->removeLast());
}

// Test getting all items
public function testGetItemsReturnsAllElementsInCorrectOrder(): void
{
$deque = new ArrayDeque();
$deque->enqueue(1);
$deque->enqueue(2);
$deque->enqueue(3);
$this->assertSame([1, 2, 3], $deque->getItems());
}
}
Loading
Loading