Stack栈详解 图解 引入到LinkedList和Array实现、均摊时间分析| Stack ADT details, intro to implementation and amortized time analysis with figures.

Stack ADT(abstract data type)

Introduction of Stack

Normally, mathematics is written using what we call in-fix notation:

[(3+4)\times 5-6 ]

Any operator is placed between two operands. The advantage is that it’s intuitive enough for human, the disadvantage is obvious. When the mathematics formula is too long, it’s full of parentheses and is difficult to find where to start calculation, both for people and computers.

Alternatively, we can place the operands first, followed by the operator.

[3\ \ 4\ \ +\ 5\ \ \times\ 6\ \ – ]

Parsing reads left-to-right and performs any operands on the last two operands.

[\begin{aligned} 3\ \ 4\ \ +\ 5\ \ \times\ 6&\ \ -\ 7\ \ \ \ \ \ \ \ \ \ 5\ \ \times\ 6&\ \ -\ 35\ \ \ \ 6&\ \ -\ 29& \end{aligned}]

This is called Reverse-Polish notation after the mathematician Jan Łukasiewicz.

Its advantage is that no ambiguity and no brackets are needed. And it’s the same process used by a computer to perform computations:

operands must be loaded into register before operations can be performed on them

The easiest way to parse reverse-Polish notation is to use an operand stack. So what is a stack?

What is a stack?

Stack is a last-in-first-out(LIFO) data structure. It’s like a pile of plates. Every time you take the plate, you take the top. After washing the plate, you also put the plate on the top.

Deal with Reverse-Polish Notation

Operands are proceeded by pushing them onto the stack.

When processing an operator:

  1. pop the last two items off the operand stack
  2. perform the operation, and
  3. push the result back onto the stack

Example: how do we evaluate 1 2 3 + 4 5 6 × - 7 × + - 8 9 × - using a stack:

Stack栈详解 图解 引入到LinkedList和Array实现、均摊时间分析| Stack ADT details, intro to implementation and amortized time analysis with figures.

The equivalent in-fix notation is: $$((1-((2+3)+((4-(5\times 6))\times 7)))+(8\times 9))$$ reduce the parentheses using order-of-operations: $$1-(2+3+(4-5\times 6)\times 7)+8\times 9$$

Implementation of Stack

We have 5 main operation of stack, they are:

  • Push: insert an object onto the top of stack
  • Pop: erase the object on the top of the stack
  • IsEmpty: determine if the stack is empty
  • IsFull: determine if a stack is full
  • CreateStack: generate an empty stack

We expect the optimal asymptotic run time of above operations is (\Theta(1)), which means that the run time of this algorithm is independent of the number of objects being stored in the container.

Operations at the front of a single linked list are all (\Theta(1)).

Stack栈详解 图解 引入到LinkedList和Array实现、均摊时间分析| Stack ADT details, intro to implementation and amortized time analysis with figures.

The desired behavior of an Abstract Stack may be reproduced by performing all operations at the front.

push_front(int)

void List::push_front(int n){
    list_head = new Node(n, list_head)
}

pop_front()

int List::pop_front(){
    if( empty() ){
        throw underflow();
    }
    int e = front();
    Node *ptr = list_head;
    list_head = list_head->next();
    delete ptr;
    return e;
}

Stack栈详解 图解 引入到LinkedList和Array实现、均摊时间分析| Stack ADT details, intro to implementation and amortized time analysis with figures.

Array Implementation

For one-ended arrays, all operations at the back are (\Theta(1)). But the insert at the front or pop at front takes (\Theta(n)) to move all element one place backwards.

top()

If there are (n) objects in the stack, the last is located at index (n-1).

template
T Stack::top() const{
    if( empty() ){
        throw underflow();
    }
    return array[stack_size-1];
}

pop()

Remove an object simply involves reducing the size. After decreasing the size, the previous top of the stack is now at the location stack_size.

template
T Stack::pop() const{
    if( empty() ){
        throw underflow();
    }
    stack_size--;
    return array[stack_size];
}

push(obj)

Pushing an object can only be performed if the array is not full

template
void Stack::push(T const &obj) const{
    if( stack_size == array_capacity ){
        throw overflow();
    }
    array[stack_size] = obj;
    stack_size++;
}

Array Capacity

When the array is full, how to increase the array capacity?

So the question is:

How must space will be increased? By a constant or a multiple?

First, let see how an increase works.

Firstly, require a call to new memory: new T[N] where N is the new capacity.

Stack栈详解 图解 引入到LinkedList和Array实现、均摊时间分析| Stack ADT details, intro to implementation and amortized time analysis with figures.
Next, copy old data to new space:
Stack栈详解 图解 引入到LinkedList和Array实现、均摊时间分析| Stack ADT details, intro to implementation and amortized time analysis with figures.
The memory for original array must be deallocated:
Stack栈详解 图解 引入到LinkedList和Array实现、均摊时间分析| Stack ADT details, intro to implementation and amortized time analysis with figures.
Finally, the pointer should point to new memory address:
Stack栈详解 图解 引入到LinkedList和Array实现、均摊时间分析| Stack ADT details, intro to implementation and amortized time analysis with figures.

Now, back to the original question: How much do we change the capacity?

We recognize that any time we push onto a full stack, this requires (n) copies and the run time is (\Theta(n)). Therefore, push is usually (\Theta(1)) except when new memory is required.

To state the average run time, we introduce the concept of amortized time:

If n operations requires (\Theta(f(n))), we will say that an individual operation has an amortized run time of (\Theta(f(n)/n)).

Using this concept, if inserting n objects requires:

  • (\Theta(n^2)) copies, the amortized time is (\Theta(n))
  • (\Theta(n)) copies, the amortized time is (\Theta(1)), that is what we expect.
Capacity increase 1 analysis

If we increase the capacity by 1 each time the array is full. With each insertion when the array is full, its requires all entries to be copied.

Stack栈详解 图解 引入到LinkedList和Array实现、均摊时间分析| Stack ADT details, intro to implementation and amortized time analysis with figures.

Suppose we insert $k$ objects – The pushing of the $k^{\text{th}}$ object on the stack requires $k-1$ copies – The total number of copies is: $$\sum_{k=1}^{n}(k-1)=\left(\sum_{k=1}^{n} k\right)-n=\frac{n(n+1)}{2}-n=\frac{n(n-1)}{2}=\Theta\left(n^{2}\right)$$ – So the amortized number of copies is: $$\Theta\left(\frac{n^2}{n}\right)=\Theta(n)$$ – Therefore each push run in $\Theta(n)$ time – The wasted space, however is $\Theta(1)$

Capacity become double size analysis

Suppose we double the number of entries each time the array is full.

Now the copy time become significantly fewer.

Stack栈详解 图解 引入到LinkedList和Array实现、均摊时间分析| Stack ADT details, intro to implementation and amortized time analysis with figures.
  • Increase $n$ objects would require 1, 2, 4, 8, …, all the way up to the largest $2^k Increase Method Copies per Insertion Unused Memory Increase by 1
    (n-1)

0 Increase by
(m)(n/m)(m-1)

Increase by a factor of 2 1
(n)

Increase by a factor of
(r>1)

1/
((r-1))((r-1)n)

Example Applications

Most parsing uses stacks.

Examples includes:

  • Matching tags in XHTML
  • In C++, matching parentheses (\textbf{(…)}), brackets (\textbf{[…]}) and braces (\textbf{{…}})

Resources: ShanghaiTech 2020Fall CS101 Algorithm and Data Structure.

Original: https://www.cnblogs.com/liuzhch1/p/16246520.html
Author: liuzhch1
Title: Stack栈详解 图解 引入到LinkedList和Array实现、均摊时间分析| Stack ADT details, intro to implementation and amortized time analysis with figures.

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/607034/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 性能测试

    一.性能测试概述 性能测试概念: 性能测试是指通过特定方式,对被测系统按照一定策略施加压力,获取系响应时间、TPS、资源利用率等性能指标,以期保证生产系统的性能能够满足用户需求的过…

    Linux 2023年6月6日
    094
  • shell的入门

    命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。 中间不能有空格,可以使用下划线 不能使用标点符号 不能使用bash里面关键字 使用变量加上$就可使用 只读变量 rea…

    Linux 2023年6月8日
    091
  • Java使用Redis删除指定前缀Key

    Java使用Redis删除指定前缀Key // 获取Redis中特定前缀 Set keys = stringRedisTemplate.keys("BLOG_SORT_B…

    Linux 2023年5月28日
    0104
  • android系统中常见问题及分类

    版本: v0.2作者:河东希望日期:2022-7-6 对Android系统和应用来说,用户体验的基本目标是: 运行稳定 交互响应快 耗电少 启动快 所有违背这几个基本原则的问题,都…

    Linux 2023年6月7日
    098
  • 【VirtualBox】VirtualBox磁盘扩容

    我的VirtualBox里面运行着Ubuntu镜像,最初创建时设置的时20G,开发过程中就不够用了 查询磁盘使用情况 df-h 查询磁盘的使用空间确实已经到了极限 扩容步骤: 1….

    Linux 2023年6月13日
    099
  • 【异常】Jenkins构建任务控制台乱码,但是直接执行shell脚本却没有问题

    1 问题现象 构建各种问号 2 检查各种配置 查看Jenkins的文件编码为 ANSI_X3.4-1968 然后直接执行mvn -v命令显示的也不是UTF-8 3 解决方案,直接在…

    Linux 2023年5月28日
    0124
  • 解决 Docker Push Skipped foreign layer 的错误

    引言当Docker推送基于Windows镜像到私有仓库的时候会遇到 Skipped foreign layer的问题。 docker push 192.168.2.30:5000/…

    Linux 2023年6月14日
    0113
  • PHP代码审计_用==与===的区别

    背景介绍 如何审计 绕过案例1 绕过案例2 背景介绍 比较 ==与 ===的差别 == 是等于符号,=== 是恒等于符号,两个符号的功能都是用来比较两个变量是否相等的,只不过两个符…

    Linux 2023年6月6日
    0117
  • Redis内存满了怎么办

    Redis是基于内存的key-value数据库,因为系统的内存大小有限,所以我们在使用Redis的时候可以配置Redis能使用的最大的内存大小。 1、通过配置文件配置 通过在Red…

    Linux 2023年5月28日
    080
  • 使用Python的列表推导式计算笛卡儿积

    笛卡儿积:笛卡儿积是一个列表, 列表里的元素是由输入的可迭代类型的元素对构 成的元组,因此笛卡儿积列表的长度等于输入变量的长度的乘积, 如下图: 如果你需要一个列表,列表里是 3 …

    Linux 2023年6月6日
    091
  • Docker Manager for Kubernetes

    一、Kubernetes介绍 Kubernets是Google开源的容器集群系统,是基于Docker构建一个容器的调度服务,提供资源调度,均衡容灾,服务注册,动态伸缩等功能套件; …

    Linux 2023年6月14日
    088
  • 认识2020年的苹果设计奖获奖者

    苹果设计奖表彰那些在苹果平台上反映最佳设计、创新和技术的开发者的创造性艺术和技术成就。 塑钢3DShapr3D Zrt. 运行CAD软件通常需要一台具有相当处理能力的台式电脑。Sh…

    Linux 2023年6月7日
    081
  • QT编程中的char*,wchar_t*与QString之间的转换

    //QString to wchar_t:const wchar_t * encodedName = reinterpret_cast Original: https://www….

    Linux 2023年6月14日
    091
  • Jenkins

    Jenkins Jenkins jenkins简介 jenkins工作原理 jenkins特点 CI/CD是什么 使用tomcat容器安装jenkins jenkins流水线项目发…

    Linux 2023年6月6日
    0128
  • 实验4:开源控制器实践——OpenDaylight

    实验4:开源控制器实践——OpenDaylight 一、实验目的 能够独立完成OpenDaylight控制器的安装配置; 能够使用Postman工具调用OpenDaylight A…

    Linux 2023年6月7日
    0106
  • Linux常用命令总结

    Linux常用命令总结 关机 & 重启&注销 常用命令 作用 shutdown -h now 即刻关机 shutdown -h 5 5分钟后关机 shutdown …

    Linux 2023年6月7日
    0106
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球