1. 程式人生 > >基礎班:第三節

基礎班:第三節

一.用陣列結構實現雙端佇列

什麼是雙端佇列(或雙向佇列)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;