Algorithms 普林斯顿知识点熟记 - Stacks and Queues

逆流柯里化
• 阅读 2010

Stacks and Queue

一、基本概念

Algorithms 普林斯顿知识点熟记 - Stacks and  Queues

  • 堆栈:检测最后加入的对象。后进先出,插入元素又叫入栈(push),去掉最近加入的元素又叫出栈(pop)。
  • 队列:检测最先加入的对象。先进先出,插入元素又叫入队(enqueue),去掉最近加入的元素又叫出队(dequeue)。

二、stacks:基于链表实现

指针始终指向链表的第一个节点,在最前方进行插入和删除操作
Algorithms 普林斯顿知识点熟记 - Stacks and  Queues

以字符串为存储对象的 stacks 举例

stack 需要实现的API
Algorithms 普林斯顿知识点熟记 - Stacks and  Queues

内部类

private class Node 
{ 
    String item;
    Node next;
}

pop出栈操作
1、 保存头节点中存储的对象

String item = first.item;

2、改变指针指向下一个节点(原本的头结点会被垃圾回收器回收)
Algorithms 普林斯顿知识点熟记 - Stacks and  Queues

first = first.next;

3、 返回1中保存下来的对象

return item;

push 入栈操作

1、创建一个新指针指向当前的头结点
Algorithms 普林斯顿知识点熟记 - Stacks and  Queues

Node oldfirst = first

2、创建一个新的头节点,并将first指针指向该节点
Algorithms 普林斯顿知识点熟记 - Stacks and  Queues

first = new Node();

3、给新节点设置实例变量
Algorithms 普林斯顿知识点熟记 - Stacks and  Queues

first.item = "not"
first.next = oldfirst

三、stacks:基于链表实现的性能表现

  1. 时间: 由于没有for循环,每个方法都只有个别指令,因此是常数项的复杂度
  2. 空间:节点数为N,则内存占用 ~40N 字节:

Algorithms 普林斯顿知识点熟记 - Stacks and  Queues

内存占用项占用空间(bytes)
对象头部16
内部对象额外的开销8
指向字符串的指针8
指向下一个节点的指针8

四、stacks:基于数组实现

基于数组实现的缺陷
数组是有容量的,存储的数量可能超过容量,需要对其进行处理。

public class FixedCapacityStackOfStrings 
{
    private String[] s;
    private int N = 0;
    //这里假设提前设置好数组大小,之后会解决这个问题
    public FixedCapacityStackOfStrings(int capacity) 
    { s = new String[capacity]; }
    public boolean isEmpty() 
    { return N == 0; } 
    public void push(String item) 
    // 使用当前索引插入数组,然后递增N
    { s[N++] = item; } 
    public String pop() 
    // 递减N,然后使用索引访问数组元素
    { return s[--N]; } }

五、对于stacks数组实现更多的思考

如何处理数组的上溢和下溢
下溢(Underflow):从空堆栈中进行pop操作会抛出异常
上溢(Overflow):扩容数组容量(resizing array)

空值: 允许空值插入

对象游离(loitering)
Algorithms 普林斯顿知识点熟记 - Stacks and  Queues

六、重置数组容量的实现

每次push数组容量递增,pop数组容量递减(<span style="color:red">×</span>)
如果采取每次push增大数组1个容量,pop减少数组1个容量的方式,每次resize都需要拷贝数组中的对象到新的数组中,那么插入N个元素花费的时间正比于 1+2+3+...+N ~ N^2/2,在数据量大的时候无法接受。

push —— 反复翻倍(<span style="color:green">√</span>)
每当数组达到容量上限,创建一个两倍大小的数组,然后将旧数组的元素拷贝到新数组

public ResizingArrayStackOfStrings() {
    s = new String[1];
}
public void push(String item) {
    if (N == s.length) resize(2 * s.length);
    s[N++] = item;
}
private void resize(int capacity) {
    String[] copy = new String[capacity];
    for (int i = 0; i < N; i++) 
        copy[i] = s[i];
    s = copy;
}

此时插入N个元素花费的时间上正比于 <font color="green">N</font> + <font color="red">(2 + 4 + 8 + ... + N)</font> ~ 3N
其中 <font color="green">N</font> 是 N 个元素在进行 push 操作时数组的访问次数,而 <font color="red">2 + 4 + 8 + ... + N</font> 是达到数组上限后,拷贝数组过程中对旧数组的访问次数

下图可以看到每遇到2的幂,需要进行多次数组的访问(数组扩容,拷贝原数组容量数量的对象到新数组),其余时间数组的访问次数仅为常数次(具体数组访问次数取决于push中的代码)。
Algorithms 普林斯顿知识点熟记 - Stacks and  Queues
虽然有些push操作会进行多次数组的运算,但从宏观上来看,总的开销是正比于3N的访问次数,这叫做平摊分析(amortized analysis)

  1. pop —— 对象为容量的 1/4 大小时容量减半 (<span style="color:green">√</span>)

不在 1/2 大小减半的原因是会出现抖动(shrashing),push元素时数组满了翻倍,随即pop时数组又少于容量的1/2于是减半,随即push翻倍、pop减半、push翻倍、pop减半...于是每次操作都需要花费正比于数据量 N 的时间。

public String pop() {
    String item = s[--N];
    s[N] = null;
    if (N > 0 && N == s.length/4) resize(s.length/2);
    return item;
}
点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
4年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
4年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
4年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Wesley13 Wesley13
4年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Wesley13 Wesley13
4年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
4年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Python进阶者 Python进阶者
2年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这