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)

大家都在看

  • Guava中的封装的Map操作

    引入依赖 <dependency> <groupId>com.google.guavagroupId> <artifactId>guava…

    Linux 2023年6月7日
    0108
  • 分布式运算中,高精度校时器的畅想

    这是我写的,带有一定的娱乐性质的文章。你可以把它理解为神经病的yy。昨天,我看了个帖子《Facebook工程师开发开源自计时设备 仅需一个PCIe插槽即可工作》,有感而发写了此文。…

    Linux 2023年6月14日
    090
  • 错误域控降级导致解析问题

    近两天在给分部安装辅助域控的时候,总是安装不成功,或者安装时成功了但是无法复制主域或者其他域控的信息,同步失败,还有就是它一直没有网。 解决方案 经过排查发现域名dns解析不对,经…

    Linux 2023年6月8日
    0111
  • Docker 容器虚拟化

    Docker 容器虚拟化 1、虚拟化网络 Network Namespace 是 Linux 内核提供的功能,是实现网络虚拟化的重要功能,它能创建多个隔离的网络空间,它们有独自网络…

    Linux 2023年6月7日
    0126
  • centos安装torch==1.4.0与相关细节

    对于某些直接安装torch==1.4.0报错的情况(没错,就是我遇到了) 在网上查找了,大概的解决方法是先安装一个低版本的torch和torchvision, torchvisio…

    Linux 2023年6月7日
    096
  • 高通MSM8998 ABL的调试

    高通在MSM8998上引入了UEFI,用来代替LK(Little Kernel)。高通UEFI由XBL和ABL两部分组成。XBL负责芯片驱动及充电等核心应用功能。ABL包括芯片无关…

    Linux 2023年6月7日
    081
  • 普通 Docker 与 Kubernetes 对比

    Docker提供基本容器管理 API 和容器镜像文件格式Kubernetes 管理运行容器的(物理或虚拟)主机群集,如果 Docker 是 OCP 的”内核&#8221…

    Linux 2023年6月6日
    091
  • 让滚动条自动滚动到最底部(可用)

    代码: <body> </body> 需求: main高度不断增加,保持页面滚动条始终在底部 解决方案: $(function(){ ….//main&…

    Linux 2023年6月13日
    0115
  • Linux下PAM模块学习总结

    Linux下PAM模块学习总结 转载自 https://www.cnblogs.com/kevingrace/p/8671964.html Original: https://ww…

    Linux 2023年6月7日
    099
  • jdk8 时间

    package p2022; import java.text.SimpleDateFormat; import java.util.Date; /** * @descriptio…

    Linux 2023年6月8日
    097
  • pymysql模块的使用

    pymysql模块的使用 import pymysql 1、连接数据库 conn = pymysql.connect( user=’root’, # The first four …

    Linux 2023年6月14日
    090
  • 自动化集成:Kubernetes容器引擎详解

    前言:该系列文章,围绕持续集成:Jenkins+Docker+K8S相关组件,实现自动化管理源码编译、打包、镜像构建、部署等操作; 本篇文章主要描述Kubernetes引擎用法。 …

    Linux 2023年5月27日
    0111
  • 文件相关命令

    pwd指令 基本语法:pwd功能:显示当前工作的绝对目录 ls指令 基本语法:ls [选项][目录或者文件]常用选项 -a 显示所有文件及目录 (. 开头的隐藏文件也会列出) -l…

    Linux 2023年6月6日
    078
  • Linux系统中断处理框架(3)【转】

    //init/main.casmlinkage void __init start_kernel(void){…… trap_init(); //空函数…… ear…

    Linux 2023年6月8日
    099
  • Docker Compose

    https://m.runoob.com/docker/docker-compose.html https://www.cnblogs.com/minseo/p/11548177….

    Linux 2023年6月13日
    095
  • 主机存活探测程序

    一、ICMP协议原理 什么是icmp协议 因特网控制报文协议ICMP(Internet Control Message Protocol)是一个差错报告机制,是TCP/IP协议簇中…

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