Skip to content

Commit

Permalink
Merge pull request #6 from KaririCode-Framework/develop
Browse files Browse the repository at this point in the history
feat: Refactor ArrayQueue, Create CircularArrayQueue, Refactor ArrayD…
  • Loading branch information
walmir-silva authored Jun 29, 2024
2 parents 0f45efa + edce0d7 commit 54c81cf
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 140 deletions.
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

0 comments on commit 54c81cf

Please sign in to comment.