数据结构之php实现栈_PHP

在上一次的文章中, 我们介绍了数组, 在讲解数组的过程中, 也提到了一点, 就是数组是线性结构。在今天的文章里,栈也是属于线性结构,我们先看下定义。
一、概念 

那什么是栈呢?  我们一起来看下定义:

堆栈(英语:stack)又称为栈或堆叠,是计算机科学中的一种抽象资料类型,只允许在有序的线性资料集合的一端(称为堆栈顶端,英语:top)进行加入数据(英语:push)和移除数据(英语:pop)的运算。因而按照后进先出(LIFO, Last In First Out)的原理运作。维基百科
栈是一种先进先出的线性数据结构(FIFO), 在计算机的世界里, 栈拥有着不可思议的作用。比如我们在编写文章时, 作图时, 写代码时 等等, 所使用的的 Undo (撤销) 操作, 就是使用这种数据结构进行实现的。先来看下栈在计算机中是什么“模样”.

数据结构之php实现栈_PHP_02

(栈的结构图)二、栈的应用
  • 无处不在的 Undo 操作

    • 比如 我现在输入 沉迷 学习 无法 自拔 这几个词, 我输入 学习, 这个动作 就会被编译机器中的栈给记录下来。这个时候我想输入,无法, 不小心打错了,输入了 “无非是”, 这个动作同样会被栈记录下来 -- 入栈,在你意识到自己打错了,想撤销这个操作的时候,这个时候,打错的这个“无非”就会被栈 "出栈"。我们看下流程图

 

数据结构之php实现栈_PHP_03

数据结构之php实现栈_PHP_04

数据结构之php实现栈_PHP_05

数据结构之php实现栈_PHP_06

数据结构之php实现栈_PHP_07

 

  • 程序调用的系统栈

    • 还有在我们写代码的时候,经常会遇到,当前方法,访问 另一个方法的情况,那程序是怎么知道跳转方法执行完了之后,该回到哪个方法呢?我们一起来看下流程图。

数据结构之php实现栈_PHP_08

    • 刚开始,进入 A 方法, 程序往下执行,开始访问B方法,这个时候 是在方法 A 的第二行执行B方法的,这是将 A2 压入 栈中,然后执行 B 方法, 在 B 方法中, 又执行了 C 方法, 这时候,将 B2 压入栈中。

      程序 C 执行完后,访问栈顶的元素,是 B2, 这时返回 B 方法 中的第二行继续执行,B2 进行 出栈, 直至程序执行完毕

       

 三、代码实现        ArrayStructure.php
<?php

class ArrayStructure
{

    // 数组实际元素

private $size = 0;

    // 用于存放数据

    private $data = [];

// 用于标记数组的容量大小

private $capacity = 10;

    /**
* 构造函数 定义数组容量
* ArrayStruct constructor.
* @param int $capacity
*/

    public function __construct(int $capacity = 10)
{

$this->capacity = $capacity;

 

    }

/**
     * 获取数组元素个数
     * @return int
     */
public function getSize(): int
{

return $this->size;

 

    }

/**
     * 获取数组的容量
     * @return int
     */
public function getCapacity(): int
{

return $this->capacity;

 

    }

/**
     * 判断数组是否为空
     * @return bool
     */
public function isEmpty(): bool
{

return $this->size == 0;

 

    }

/**
     * 向数组指定位置插入元素
     * @param int $index
     * @param $e
     * @throws Exception
     */
public function add(int $index, $e): void
{
if ($this->size == $this->capacity) {
$this->resize(2); //扩大到原来的2倍
        }

if ($index < 0 || $index > $this->size) {
echo "添加位置超出数组大小";
exit;

}

 

        //为了方便理解,[1,2,4,5,6],假设 $index = 3; $e = 100,插入之后[1,2,4,100,5,6]
for ($i = $this->size; $i >= $index; $i--) {
$this->data[$i] = $this->data[$i - 1];

}

 

        $this->data[$index] = $e;

$this->size++;

 

    }

/**
     * 向数组末尾添加元素
     * @param $e
     * @throws Exception
     */
public function addLast($e): void
{

$this->add($this->size, $e);

 

    }

/**
     * 向数组开头插入元素
     * @param $e
     * @throws Exception
     */
public function addFirst($e): void
{

$this->add(0, $e);

 

    }

/**
     * 获取 index 位置数组元素
     * @param int $index
     * @return mixed
     */
public function get(int $index)
{
if ($index < 0 || $index > $this->size) {
echo "index值超出元素的位置范围,";
exit;

}

 

return $this->data[$index];

 

    }

/**
     * 判断数组中是否存在某个元素
     * @param $e
     * @return bool
     */
public function contains($e): bool
{
for ($i = 1; $i < $this->size; $i++) {
if ($this->data[$i] == $e) {
return true;
            }
        }

return false;

 

    }

/**
     * 查某个元素在数组的位置索引值,若不存在则返回 -1
     * @param $e
     * @return int
     */
public function find($e): int
{
for ($i = 0; $i < $this->size; $i++) {
if ($this->data[$i] == $e) {
return $i;
            }
        }

return -1;

 

    }

/**
     * 删除数组指定位置元素,返回删除元素的值
     * @param $index
     * @return mixed
     */
public function remove($index)
{
if ($index < 0 || $index > $this->size) {
echo "index值超出元素的位置范围,";
exit;
        }
        $e = $this->data[$index];

for ($i = $index; $i < $this->size - 1; $i++) {
$this->data[$i] = $this->data[$i + 1];
        }
$this->size--;

$this->data[$this->size] = null;

/** 若当前数组大小,小于容量的一半,则重新分配一半的数组空间大小 **/
if ($this->size <= $this->capacity / 4 && $this->capacity % 2 == 0) {
$this->resize(0.5);

}

 

        return $e;
    }

/**
     * 删除数组首个元素,返回删除元素的值
     */
public function removeFirst()
{

return $this->remove(0);

 

    }

/**
     * 删除数组首个元素,返回删除元素的值
     */
public function removeLast()
{

return $this->remove($this->size);

 

    }

/**
     * 删除数组中特定元素
     * @param $e
     */
public function removeElement($e)
{
for ($i = 0; $i < $this->size; $i++) {
if ($this->data[$i] == $e) {
$this->remove($i);
$this->removeElement($e);
break;
            }

}

 

    }

/**
     * 数组扩容,若是其他语言,如JAVA这里需要重新开辟空间
     * @param $factor
     */
protected function resize($factor)
{

$this->capacity = $factor * $this->capacity;

 

    }

/**
     * 将数组转化为字符串
     * @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;

 

    }

}

 

      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)

  •  
ArrayStackpush(e)      O(1) // 如果是触发了扩容, 通过均摊复杂度来分析的话,依然是O(1)pop()        O(1) // 如果是触发了扩容, 通过均摊复杂度来分析的话,依然是O(1)top()        O(1)getSize()    O(1)isEmpty(1)   O(1)