在上一次的文章中, 我們介紹了陣列, 在講解陣列的過程中, 也提到了一點, 就是陣列是線性結構。在今天的文章裡,棧也是屬於線性結構,我們先看下定義。
一、概念
那什麼是棧呢? 我們一起來看下定義:
堆疊(英語:stack)又稱為棧或堆疊,是電腦科學中的一種抽象資料型別,只允許在有序的線性資料集合的一端(稱為堆疊頂端,英語:top)進行加入資料(英語:push)和移除資料(英語:pop)的運算。因而按照後進先出(LIFO, Last In First Out)的原理運作。
維基百科
棧是一種先進先出的線性資料結構(FIFO), 在計算機的世界裡, 棧擁有著不可思議的作用。比如我們在編寫文章時, 作圖時, 寫程式碼時 等等, 所使用的的 Undo (撤銷) 操作, 就是使用這種資料結構進行實現的。先來看下棧在計算機中是什麼“模樣”.
(棧的結構圖)
二、棧的應用
無處不在的 Undo 操作
比如 我現在輸入 沉迷 學習 無法 自拔 這幾個詞, 我輸入 學習, 這個動作 就會被編譯機器中的棧給記錄下來。這個時候我想輸入,無法, 不小心打錯了,輸入了 “無非是”, 這個動作同樣會被棧記錄下來 – 入棧,在你意識到自己打錯了,想撤銷這個操作的時候,這個時候,打錯的這個“無非是”就會被棧 “出棧”。我們看下流程圖
程式呼叫的系統棧
還有在我們寫程式碼的時候,經常會遇到,當前方法,訪問 另一個方法的情況,那程式是怎麼知道跳轉方法執行完了之後,該回到哪個方法呢?我們一起來看下流程圖。
剛開始,進入 A 方法, 程式往下執行,開始訪問B方法,這個時候 是在方法 A 的第二行執行B方法的,這是將 A2 壓入 棧中,然後執行 B 方法, 在 B 方法中, 又執行了 C 方法, 這時候,將 B2 壓入棧中。
程式 C 執行完後,訪問棧頂的元素,是 B2, 這時返回 B 方法 中的第二行繼續執行,B2 進行 出棧, 直至程式執行完畢
三、程式碼實現
ArrayStructure.php
<?php
class ArrayStructure
{
// 陣列實際元素
private $size = 0;
// 陣列的容量大小
private $capacity = 0;
// 用於存放資料
private $data = [];
/**
* ArrayStruct constructor.
*
* @param int $capacity 陣列容量大小
*/
public function __construct($capacity = 10)
{
$this->capacity = $capacity;
}
/**
* Notes: 獲取陣列實際元素個數
* Author: PhpStorm
* Date: 2021/1/8 0008
* Time: 15:12
*
* @return int
*/
public function getSize(): int
{
return $this->size;
}
/**
* Notes: 擴容
* User: think abel
* Date: 2021/1/10 0010
* Time: 17:08
*
* @param $factor
*/
protected function resize($factor)
{
$this->capacity = $factor * $this->capacity;
}
/**
* Notes: 獲取陣列的容量
* Author: PhpStorm
* Date: 2021/1/8 0008
* Time: 15:14
*
* @return int
*/
public function getCapacity(): int
{
return $this->capacity;
}
/**
* Notes: 陣列是否為空
* Author: PhpStorm
* Date: 2021/1/8 0008
* Time: 15:16
*
* @return bool
*/
public function isEmpty(): bool
{
return $this->size === 0;
}
/**
* Notes: 往陣列指定位置插入資料
* Author: PhpStorm
* Date: 2021/1/8 0008
* Time: 15:27
*
* @param int $index 需要插入的下標/索引
* @param int $ele 需要插入的元素
*/
public function add(int $index, $ele): void
{
// 如果當前的實際大小 等於 當前容量, 則不可以進行插入
try {
if ($this->size === $this->capacity) {
throw new Exception("新增失敗, Array 已經到達最大容量");
}
if ($index < 0 || $index > $this->size) {
throw new Exception("新增失敗, index require >= 0 and <= " . $this->size);
}
/**
* 從最後一個元素開始進行遍歷, 直到下標 為 當前輸入的 下標, 終止
* 每次將當前遍歷的數值 往後 移動一位
*/
for ($i = $this->size - 1; $i >= $index; $i --) {
$this->data[$i + 1] = $this->data[$i];
}
// 目前當前下標還是存在之前的元素, 因為當前元素已經移動到後面一位, 所以直接覆蓋就好
$this->data[$index] = $ele;
// 維護當前實際大小
$this->size ++;
}
catch (Exception $e) {
echo $e->getMessage();
}
}
/**
* Notes: 向所有元素後新增一個元素
* Author: PhpStorm
* Date: 2021/1/8 0008
* Time: 15:19
*/
public function addLast($element): void
{
$this->add($this->size, $element);
}
/**
* Notes: 向第一位新增一個元素
* Author: PhpStorm
* Date: 2021/1/8 0008
* Time: 15:19
*/
public function addFirst(int $element): void
{
$this->add(0, $element);
}
/**
* Notes: 陣列轉字串
* Author: PhpStorm
* Date: 2021/1/8 0008
* Time: 15:50
*
* @return string
*/
public function toString(): string
{
$str = 'Array: size = ' . $this->size . ',' . 'capacity = ' . $this->capacity . PHP_EOL;
$str .= '[';
for ($i = 0; $i < $this->size; $i ++) {
$str .= $this->data[$i];
if ($i != $this->size - 1) {
$str .= ',';
}
}
$str .= ']';
return $str . PHP_EOL;
}
/**
* Notes: 獲取指定下標位置的元素
* Author: PhpStorm
* Date: 2021/1/8 0008
* Time: 16:13
*
* @param int $index
*
* @return int
*/
public function get($index)
{
try {
if ($index < 0 || $index >= $this->size) {
throw new Exception("獲取失敗, index require >= 0 and < " . $this->size);
}
return $this->data[$index];
}
catch (Exception $e) {
return $e->getMessage();
}
}
/**
* Notes: 獲取最後一個
* User: think abel
* Date: 2021/1/10 0010
* Time: 15:48
*
* @return int
*/
public function getLast()
{
return $this->get($this->size - 1);
}
/**
* Notes: 獲取第一個
* User: think abel
* Date: 2021/1/10 0010
* Time: 15:48
*
* @return int
*/
public function getFirst()
{
return $this->get(0);
}
/**
* Notes: 修改指定下標位置的元素為 ele
* User: think abel
* Date: 2021/1/9 0009
* Time: 12:04
*
* @param int $index
* @param int $ele
*
* @return string
*/
public function set(int $index, int $ele)
{
try {
if ($index < 0 || $index >= $this->size) {
throw new Exception("獲取失敗, index require >= 0 and < " . $this->size);
}
$this->data[$index] = $ele;
}
catch (Exception $e) {
return $e->getMessage();
}
}
/**
* Notes: 刪除指定位置上的元素
* Author: PhpStorm
* Date: 2021/1/8 0008
* Time: 16:19
*
* @param int $index
*
* @return int|string
*/
public function remove(int $index): int
{
try {
if ($index < 0 || $index >= $this->size) {
throw new Exception("移除失敗, index require >= 0 and < " . $this->size);
}
$return = $this->data[$index];
for ($i = $index + 1; $i < $this->size; $i ++) {
$this->data[$i - 1] = $this->data[$i];
}
$this->size --;
return $return;
}
catch (Exception $e) {
return $e->getMessage();
}
}
/**
* Notes: 刪除第一個
* Author: PhpStorm
* Date: 2021/1/8 0008
* Time: 16:39
*
* @return int
*/
public function removeFirst(): int
{
try {
return $this->remove(0);
}
catch (Exception $e) {
return $e->getMessage();
}
}
/**
* Notes: 刪除最後一個
* Author: PhpStorm
* Date: 2021/1/8 0008
* Time: 16:39
*
* @return int
*/
public function removeLast()
{
try {
return $this->remove($this->size - 1);
}
catch (Exception $e) {
return $e->getMessage();
}
}
/**
* Notes: 如果有元素, 就刪除
* Author: PhpStorm
* Date: 2021/1/8 0008
* Time: 16:44
*
* @param int $ele
*
* @return bool
*/
public function removeElement(int $ele): bool
{
$index = $this->find($ele);
if ($index != - 1) {
$this->remove($index);
}
}
/**
* Notes: 是否包含元素
* Author: PhpStorm
* Date: 2021/1/8 0008
* Time: 16:22
*
* @param int $ele
*
* @return bool
*/
public function contains(int $ele): bool
{
for ($i = 0; $i < $this->size; $i ++) {
if ($this->data[$i] == $ele) {
return true;
}
}
return false;
}
/**
* Notes: 獲取當前元素的索引
* Author: PhpStorm
* Date: 2021/1/8 0008
* Time: 16:22
*
* @param int $ele
*
* @return int
*/
public function find(int $ele): int
{
for ($i = 0; $i < $this->size; $i ++) {
if ($this->data[$i] == $ele) {
return $i;
}
}
return - 1;
}
}
Stack.php
interface Stack
{
public function getSize();
public function isEmpty();
public function push($element);
public function pop();
public function top();
}
ArrayStack.php
<?php
/**
* Created by : PhpStorm
* User: think abel
* Date: 2021/1/10 0010
* Time: 15:33
*/
include 'Stack.php';
include 'ArrayStructure.php';
class ArrayStack implements Stack
{
private $array;
public function __construct(int $capacity = 10)
{
$this->array = new ArrayStructure($capacity);
}
public function getSize()
{
return $this->array->getSize();
}
public function isEmpty()
{
return $this->array->isEmpty();
}
public function getCapacity()
{
return $this->array->getCapacity();
}
public function push($element)
{
$this->array->addLast($element);
}
public function pop()
{
return $this->array->removeLast();
}
public function top()
{
return $this->array->getLast();
}
public function toString(): string
{
$str = "Stack: [";
for ($i = 0; $i < $this->array->getSize(); $i ++) {
$str .= $this->array->get($i);
if ($i != $this->array->getSize() - 1) {
$str .= ", ";
}
}
$str .= "] top";
return $str;
}
}
四、簡單複雜度分析
O: 描述是演算法的執行時間 和 輸入資料之間的關係 — 程式執行時間 和 數資料 成線性關係 O(n)
ArrayStack
push(e) O(1) // 如果是觸發了擴容, 通過均攤複雜度來分析的話,依然是O(1)
pop() O(1) // 如果是觸發了擴容, 通過均攤複雜度來分析的話,依然是O(1)
top() O(1)
getSize() O(1)
isEmpty(1) O(1)
倉庫地址
倉庫地址: gitee.com/thinkAbel/data-structure
最後祝大家 工作開心, 永不加班
本作品採用《CC 協議》,轉載必須註明作者和本文連結