一、概念
那什么是栈呢? 我们一起来看下定义:
堆栈(英语: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 进行 出栈, 直至程序执行完毕
-
<?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
ArrayStack.phpinterface Stack
{
public function getSize();
public function isEmpty();
public function push($element);
public function pop();
public function top();
}
<?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)