實戰PHP資料結構基礎之棧

蕭瀟發表於2018-06-15

棧和佇列

棧和佇列和之前講到的實戰PHP資料結構基礎之雙連結串列 一樣都是線性結構。

棧有什麼特點

棧遵循後進先出的原則(LIFO)。這意味著棧只有一個出口用來壓入元素和彈出元素,當我們執行壓入或者彈出操作的時候要注意棧是否已滿或者棧是否是空的。

常見操作

還是廢話不多說,直接來看我們對棧執行的常用操作。

  • push
  • pop
  • top
  • isEmpty
  • ...

PHP實現

首先我們定義一個StackInterface。

interface StackInterface
{
    public function push(string $item);
    public function pop();
    public function top();
    public function isEmpty();
}
複製程式碼

來看基於陣列的棧實現

class ArrStack implements StackInterface
{
    private $stack;
    private $limit;

    public function __construct(int $limit = 20)
    {
        $this->limit = $limit;
        $this->stack = [];
    }

    public function __get($val)
    {
        return $this->$val;
    }

    public function push(string $data = null)
    {
        if (count($this->stack) < $this->limit) {
            array_push($this->stack, $data);
        } else {
            throw new \OverflowException('stack is overflow');
        }
    }

    public function pop()
    {
        if ($this->isEmpty()) {
            throw new \UnderflowException('stack is empty');
        } else {
            return array_pop($this->stack);
        }
    }

    public function isEmpty()
    {
        return empty($this->stack);
    }

    public function top()
    {
        return end($this->stack);
    }
複製程式碼

得益於PHP強大的array結構,我們輕而易舉的寫出來了棧的基本操作方法。果然世界上最好的語言名不虛傳。

那有同學說了,你說棧和之前的連結串列都是線性結構,那可不可以直接使用連結串列實現棧呢?這個問題非常犀利啊,答案是可以的。

可能機智的同學已經猜到了,我之前已經定義了一個棧介面,那棧的實現肯定不止只有上面一種哈。來看基於連結串列的實現。

class LinkedListStack implements StackInterface
{
    private $stack;
    private $limit;

    public function __construct(int $limit)
    {
        $this->limit = $limit;
        $this->stack = new LinkedList();
    }

    public function top()
    {
        return $this->stack->getNthNode($this->stack->getSize() - 1)->data;
    }

    public function isEmpty()
    {
        return $this->stack->getSize() === 0;
    }

    public function pop()
    {
        if ($this->isEmpty()) {
            throw new \UnderflowException('stack is empty');
        } else {
            $lastItem = $this->top();
            $this->stack->deleteLast();

            return $lastItem;
        }
    }

    public function push(string $item)
    {
        if ($this->stack->getSize() < $this->limit) {
            $this->stack->insert($item);
        } else {
            throw new \OverflowException('stack is overflow');
        }
    }
複製程式碼

裡面涉及到了之前的連結串列實現,不瞭解細節的同學可以去這裡看看。有同學又問,那棧到底有什麼用處?這個問題非常好,來看一個需求。

請實現一個數學表示式檢查類,輸入一個下面表示式,預期結果為true。

"8 * (9 -2) + { (4 * 5) / ( 2 * 2) }
複製程式碼

下面的為false。

"5 * 8 * 9 / ( 3 * 2 ) )"
複製程式碼

下面的也為false。

"[{ (2 * 7) + ( 15 - 3) ]"
複製程式碼

自己想一下,再往下看實現。

class ExpressionChecker
{
    //$expressions[] = "8 * (9 -2) + { (4 * 5) / ( 2 * 2) }";
    //$expressions[] = "5 * 8 * 9 / ( 3 * 2 ) )";
    //$expressions[] = "[{ (2 * 7) + ( 15 - 3) ]";

    public function check(string $expression): bool
    {
        $stack = new \SplStack();

        foreach (str_split($expression) as $item) {
            switch ($item) {
                case '{':
                case '[':
                case '(':
                    $stack->push($item);
                    break;

                case '}':
                case ']':
                case ')':
                    if ($stack->isEmpty()) return false;

                    $last = $stack->pop();

                    if (
                        $item == '{' && $last != '}' ||
                        $item == '(' && $last != ')' ||
                        $item == '[' && $last != ']'
                    )
                        return false;

                    break;
            }
        }

        if ($stack->isEmpty()) {
            return true;
        }

        return false;
    }
}
複製程式碼

專題系列

PHP基礎資料結構專題系列目錄地址:github.com/... 主要使用PHP語法總結基礎的資料結構和演算法。還有我們日常PHP開發中容易忽略的基礎知識和現代PHP開發中關於規範、部署、優化的一些實戰性建議,同時還有對Javascript語言特點的深入研究。

相關文章