基礎班:第三節
阿新 • • 發佈:2019-01-05
一.用陣列結構實現雙端佇列
什麼是雙端佇列(或雙向佇列)Deque,全名double-ended queue?
- 即元素可以在佇列的任意一段入隊或出隊,如果我們把這些方法叫做insertLeft()和insertRight(),以及removeLeft()和removeRight()。
- 如果嚴格禁止呼叫insertLeft()和removeLeft()方法(或禁用右段的操作),雙端佇列功能就和棧一樣。
- 禁止呼叫insertLeft()和removeRight()(或相反的另一對方法),它的功能就和佇列一樣了。
- 雙端佇列與棧或佇列相比,是一種多用途的資料結構。
<?php
class DoubleEndedQueue
{
public $queue = array();
/**(尾部)入隊 **/
public function addLast($value)
{
return array_push($this->queue,$value);
}
/**(尾部)出隊**/
public function removeLast()
{
return array_pop($this->queue);
}
/**(頭部)入隊**/
public function addFirst($value)
{
return array_unshift($this->queue,$value);
}
/**(頭部)出隊**/
public function removeFirst()
{
return array_shift($this->queue);
}
/**清空佇列**/
public function makeEmpty()
{
unset ($this->queue);
}
/**獲取列頭**/
public function getFirst()
{
return reset($this->queue);
}
/** 獲取列尾 **/
public function getLast()
{
return end($this->queue);
}
/** 獲取長度 **/
public function getLength()
{
return count($this->queue);
}
}
二.實現一個特殊的棧,在實現棧的基本功能的基礎上,再實現返回棧中最小元素的操作
要求:
- pop、push、getMin操作的時間複雜度都是O(1)
- 設計的棧型別可以使用現成的棧結構
class GetMinStackService
{
public function __construct(&$data, &$minArray)
{
$this->data = &$data; // 棧
$this->minArray = &$minArray; // 最小值棧
}
// 出棧操作
public function pop()
{
// 彈出最小值棧
array_pop($this->minArray);
// 彈出棧
array_pop($this->data);
}
// 入棧操作
public function push($number)
{
// 壓入最小值棧
if (count($this->minArray) == 0) {
array_push($this->minArray, $number);
} else {
$min = end($this->minArray) > $number ? $number : end($this->minArray);
array_push($this->minArray, $min);
}
// 壓入棧
array_push($this->data, $number);
}
// 獲取最小值
public function getMin()
{
return end($this->minArray);
}
}
三.如何僅用佇列結構實現棧結構?如何僅用棧結構實現佇列結構?
3.1 如何僅用佇列結構實現棧結構
class TwoQueuesStack {
public function __construct(&$data, &$help)
{
$this->data = &$data;
$this->help = &$help;
}
// 出棧
public function pop()
{
// data佇列 倒入 到help佇列
while (count($this->data) > 1) {
array_push($this->help, array_shift($this->data));
}
array_shift($this->data);
$this->swap();
}
// 入棧
public function push($number)
{
array_push($this->data, $number);
}
public function swap()
{
// help佇列 倒入 data佇列
while (count($this->help) > 0 ) {
array_push($this->data, array_shift($this->help));
}
}
}
3.2 如何僅用棧結構實現佇列結構
class TwoStacksQueue {
public function __construct(&$data, &$help)
{
$this->data = &$data;
$this->help = &$help;
}
// 入隊
public function push($number)
{
array_push($this->data, $number);
}
// 出隊
public function shift()
{
// data棧 倒入 到 help 棧
while (count($this->data) > 1) {
array_push($this->help, array_pop($this->data));
}
// 彈出最後一個
array_pop($this->data);
// help 棧 倒入 到data棧
while (count($this->help) > 0) {
array_push($this->data, array_pop($this->help));
}
}
}
四.貓狗佇列
【題目】 寵物、狗和貓的類如下:
public class Pet {
private String type;
public Pet(String type) {
this.type = type;
}
public String getPetType() {
return this.type;
}
}
public class Dog extends Pet {
public Dog() {
super("dog");
}
}
public class Cat extends Pet {
public Cat() {
super("cat");
}
}
實現一種狗貓佇列的結構,要求如下:
- 使用者可以呼叫add方法將cat類或dog類的例項放入佇列中;
- 使用者可以呼叫pollAll方法,將佇列中所有的例項按照進佇列
的先後順序依次彈出; - 使用者可以呼叫pollDog方法,將佇列中dog類的例項按照
進佇列的先後順序依次彈出; - 使用者可以呼叫pollCat方法,將佇列中cat類的實
例按照進佇列的先後順序依次彈出; - 使用者可以呼叫isEmpty方法,檢查佇列中是
否還有dog或cat的例項; - 使用者可以呼叫isDogEmpty方法,檢查佇列中是否有dog
類的例項; - 使用者可以呼叫isCatEmpty方法,檢查佇列中是否有cat類的例項。
父類Pet
namespace App\Services;
class Pet
{
private $type;
public function __construct(string $type)
{
$this->type = $type;
}
public function getPetType() : string {
return $this->type;
}
public function __toString()
{
return json_encode([
'type' => $this->type
]);
}
}
繼承父類Pet的Cat類和Dog類
namespace App\Services;
use App\Services\Pet;
class Dog extends Pet
{
public function __construct()
{
parent::__construct('dog');
}
}
namespace App\Services;
use App\Services\Pet;
class Cat extends Pet
{
public function __construct()
{
parent::__construct('cat');
}
}
Pet包裝類 PetWrapper, $id 記錄入隊的先後順序
namespace App\Services;
class PetWrapper
{
protected $pet;
protected $id;
public function __construct(Pet $pet, int $id)
{
$this->pet = $pet;
if (is_null($id)) {
$id = time();
}
$this->id = $id;
}
// 出隊時返回物件
public function getPet() : Pet
{
return $this->pet;
}
public function getId() : int
{
return $this->id;
}
public function getEnterPetType() : String
{
return $this->pet->getPetType();
}
public function __toString()
{
return json_encode([
'id' => $this->id,
'type' => $this->pet->getPetType()
]);
}
}
貓狗佇列
上面的類Pet、Cat、Dog、PetWrapper都是準備。
use App\Services\Cat;
use App\Services\Dog;
use App\Services\Pet;
use App\Services\PetWrapper;
class DogCatQueue
{
protected $dogQ;
protected $catQ;
protected $count;
public function __construct()
{
$this->dogQ = new \SplQueue();
$this->catQ = new \SplQueue();
$this->count = 0;
}
// 使用者可以呼叫add方法將cat類或dog類的例項放入佇列中
public function add(Pet $pet)
{
if (strcmp($pet->getPetType(), 'dog') === 0) {
$this->dogQ->enqueue(new PetWrapper($pet, $this->count++));
} else if (strcmp($pet->getPetType(), 'cat') === 0) {
$this->catQ->enqueue(new PetWrapper($pet, $this->count++));
} else {
throw new \Exception("Error, neither dog or cat");
}
}
// 使用者可以呼叫pollAll方法,
// 將佇列中所有的例項按照進佇列的先後順序依次彈出
public function pollAll() : Pet
{
// 一.狗佇列不為空 且 貓佇列也不為空
if (! $this->isDogEmpty() && ! $this->isCatEmpty()) {
$minIdOfDogQ = $this->front($this->dogQ)->getId();
$minIdOfCatQ = $this->front($this->catQ)->getId();
// 比較貓佇列隊頭的屬性id 與 狗佇列隊頭的屬性id 大小
// 誰小誰被彈出佇列
if ($minIdOfCatQ < $minIdOfDogQ) {
return $this->pollCat();
} else {
return $this->pollDog();
}
// 二.狗佇列為空 且 貓佇列不為空
} else if ($this->isDogEmpty() && ! $this->isCatEmpty()) {
return $this->pollCat();
// 三.狗佇列不為空 且 貓佇列為空
} else if (! $this->isDogEmpty() && $this->isCatEmpty()) {
return $this->pollDog();
}
// 四.貓狗總佇列為空
throw new \Exception('貓狗佇列為空');
}
// 使用者可以呼叫pollDog方法,將佇列中dog類的例項按照
// 進佇列的先後順序依次彈出;
public function pollDog() : Dog
{
if (! $this->isDogEmpty()) {
$this->count--; // 佇列數量-1
return $this->dogQ->dequeue()->getPet();
}
throw new \Exception('dog queue is empty');
}
// 使用者可以呼叫pollCat方法,將佇列中cat類的實
// 例按照進佇列的先後順序依次彈出;
public function pollCat() : Cat
{
if (! $this->isCatEmpty()) {
$this->count--; // 佇列數量-1
return $this->catQ->dequeue()->getPet();
}
throw new \Exception('cat queue is empty');
}
// 使用者可以呼叫isEmpty方法,
// 檢查佇列中是否還有dog或cat的例項;
public function isEmpty() : bool
{
return $this->isDogEmpty() && $this->isCatEmpty();
}
// 使用者可以呼叫isDogEmpty方法,
// 檢查佇列中是否有dog類的例項;
public function isDogEmpty() : bool
{
return $this->dogQ->isEmpty();
}
// 使用者可以呼叫isCatEmpty方法,
// 檢查佇列中是否有cat類的例項
public function isCatEmpty() : bool
{
return $this->catQ->isEmpty();
}
public function __toString() : String
{
// 列印貓佇列
$stringCat = "[cat queue]: " . PHP_EOL;
foreach ($this->catQ as $petWrapper) {
$stringCat .= $petWrapper . PHP_EOL;