【Algorithms公开课学习笔记3】 栈与队列
Stack and Queue 栈和队列
0.前言
本文是对数据类型的学习笔记,将会从接口(interface),实现(implement), 客户(client)等三个角度分模块来组织文章。
接口:对数据类型、基本操作的描述(API)
实现:实现API的基本操作的实际代码
客户:在程序里调用API所定义的基本操作
1.Stack 栈
栈最基本的特点就是后进先出(LIFO, last in first out)
- 栈的API
//栈的APIpublic class Stack<Item>{//<Item>表示将数据类型泛化,此栈元素可接受任意数据类型public Stack();public void push(Item item);public Item pop();public boolean isEmpty();public int size;//其他
}
- 栈的实现
栈的实现有两个(基本)方式,分别是链表(linked-list)和可调整数组(resizing array)
链表
入栈和出栈表示
入栈
出栈
代码实现
public class Stack<Item>{private Node first = null;//因为构造时不做任何操作,所以不写构造方法//内部类定义链表节点,注意访问修饰符privateprivate class Node{Item item;Node next;}public boolean isEmpty(){return first == null;}public void push(Item item){Node oldfirst = first;first = new Node();first.item = item;first.next = oldfirst;}public Item pop(){Item item = first.item;first = first.next;return item;}
}
时间性能
出栈和入栈的操作都是顺序语句,常数级(constant)
空间复杂度
在针对String字符串时分析:Node节点对象占用40字节,故所有空间~40N字节,如图
可调整数组
入栈和出栈表示
push: 往数组的的末尾添加item
pop: 在数组的末尾删除item
难处:由于无法提前知道栈的容量,导致在定义数组时无法确定其大小。初始的数组容量过大会浪费空间,容量过小会导致运行过程中溢出。因此,使用可调整的数组来将解决可以难题。
关键:当数组容量满(full)的时候,将数组大小翻倍(double size),当数据容量为大小的四分之一(one-quarter full)的时候,将数组大小减半(halve size)。
代码实现
public class Stack<Item>{private Item[] s;private int N;public Stack(){//由于java不支持泛型数组,所以这里需要强转s = (Item[])new Object[1];N = 0;}public boolean isEmpty(){return N > 0;}public void push(Item item){if (N == s.length) resize(2 * s.length);s[N++] = item;}public Item pop(){Item item = s[--N];s[N] = null;if (N > 0 && N == s.length/4) resize(s.length/2);return item;}private void resize(int capacity){Item[] copy = (Item[])new Object[capacity];for (int i = 0; i < N; i++)copy[i] = s[i];s = copy;}
}
时间性能
由于在入栈和出栈的过程中需要调整数组大小(此过程需要复制完整数组),若调整过于频繁,必定会耗时严重。因此时间性能分析存在最好、最坏和平摊情况。
*平摊分析:在最坏情况下,每次操作所需的平均时间。
空间复杂度
在针对String字符串时分析:在full的时候需要~8N,在1/4 full的时候需要~32N(暂时未能解释)
对比
链表每一个操作的耗时都是常数级,但比较占用空间(存字符串要~40N)
可调整数组的每一个操作的摊分时间也是常数级,但可能会遇到最坏情况而影响性能,其空间占用较小
2.Queue队列
队列最基本的特点就是先进先出(FIFO, first in first out)
- 队列的API
//队列的APIpublic class Queue<Item>{//Item表示将数据类型泛化,此队列元素可接受任意数据类型public Queue();public void enqueue(Item item);public Item dequeue();public boolean isEmpty();public int size;//其他
}
- 队列的实现
栈的实现同样有两个(基本)方式,分别是链表(linked-list)和可调整数组(resizing array)
链表
入队和出队表示
入队
出队
代码实现
public class Queue<Item>{private Node first = null;private Node last = null;//因为构造时不做任何操作,所以不写构造方法//内部类定义链表节点,注意访问修饰符privateprivate class Node{Item item;Node next;}public boolean isEmpty(){return first == null;}public void enqueue(Item item){Node oldlast = last;last = new Node();first.item = item;first.next = null;if (isEmpty()) first = last;else oldlast.next = last;}public Item pop(){Item item = first.item;first = first.next;if (isEmpty()) last = null;return item;}
}
时间性能
出队和入队的操作都是顺序语句,常数级(constant)
空间复杂度
在针对String字符串时分析:Node节点对象占用40字节,故所有空间~40N字节
可调整数组
入队和出队表示
push: 往数组的的末尾(tail)添加item
pop: 在数组的首部(head)删除item
关键:调整首部和末尾的指针,以及调整数组的容量
代码实现
public class Queue<Item>{//这里使用循环队列来实现,必须固定长度。//这里暂时没有实现调整数组容量的操作private final static int N =10 ;private Item[] s;private int tail;private int head;public Stack(){//由于java不支持泛型数组,所以这里需要强转s = (Item[])new Object[1];tail = 0;head = 0;}public boolean isEmpty(){return head == tail;}public void enqueue(Item item){if ((tail + 1) % N == head ){//溢出,不允许入队return ;}s[tail] = item;tail = (tail + 1) % N;}public Item dequeue(){if(isEmpty()){//空队列,不允许出队return;}Item item = s[head];head = (head + 1) % N;return item;}}
时间性能
循环队列由于不涉及调整数组容量的操作,所以入队和出队操作都是顺序语句,常数级(constant)
空间复杂度
空间占用就是数组的容量,拿String字符串来分析,就是~8N
3.泛型
前面的代码已经涉及泛型,使用泛型的目的就是为了能够适配所有的数据类型。
在使用可调整数组实现栈的时候提到:由于java不支持定义泛型数组(其他程序语言也不支持),所以在定义泛型数组的时候使用强制转型
//强转Item[] copy = (Item[])new Object[capacity];
虽然使用强转是一种糟糕的编程习惯,但是此场景下只能通过该方法解决。
另外,学习泛型还需要学习java数据类型的包装类(wrapper type)和自动装箱子机制(autoboxing)。
//int类型的包装类是Integer
//push操作中会将int自动转成Integer,称为自动装箱Stack<Integer> s = new Stack<Integer>();
s.push(17);
4.迭代器
使用迭代器的好处就是可以方便地遍历栈(或者队列)的元素,例如使用foreach方法来遍历。
类实现迭代器的基本方法如下:
public class Stack<Item> implements Iterable<Item>{//省略了其他属性和方法//重写iterator()方法,返回自定义的iterator对象public Iterator<Item> iterator() {return new ListIterator();}//自定义iterator类private class ListIterator implements Iterator<Item>{private Node current = first;//必须重写next()he hasnext()方法public boolean hasNext() {return current != null;}public void remove() { /* not supported */ }public Item next(){Item item = current.item;current = current.next;return item;}}
}
5.应用
java本身就提供了非常丰富的集合类(如List、Stack等),但是其提供的操作都是非常冗余且低性能的。如果对性能有追求的最好自己封装集合类。
函数的调用就是对栈的而一种应用。由于函数的调用,程序流程进入函数内部,其当前环境和变量将全部推入栈,直到调用完毕返回结果时,才出栈。注意多级调用和递归调用。
对于表达式的运算(如下图),使用双栈来完成:1)遇到左括号不操;2)遇到数字push到value satck;3)遇到操作符push到operator stack;4)遇到有括号从value satck pop两个数字,再从operator stack pop一个操作符,最后将计算结果push 到value stack。
第2周作业的答案
Queues
【Algorithms公开课学习笔记3】 栈与队列相关推荐
- 英宝通Unity4.0公开课学习笔记Vol.0
英宝通Unity4.0公开课学习笔记 公开课地址 学习笔记目录 公开课地址 公开课地址:游戏蛮牛网. 源码素材:游戏蛮牛网. 公开课在官网上刷新不出来,只能去B站上找资源了.视频链接:哔哩哔哩. Un ...
- MIT Artificial Intelligence —— Patrick H. Winston 麻省理工人工智能公开课学习笔记(一)
本系列文章是博主对网易公开课中麻省理工人工智能课程的学习笔记,在此方便学习和分享. Lecture 1: Introduction and Scope 本节课程大概从这三方面讲述: 一.什 ...
- 斯坦福机器学习公开课学习笔记(1)—机器学习的动机与应用
(转载请注明出处:http://blog.csdn.net/buptgshengod) 1.背景 斯坦福机器学习公开课差不多是网上能找到的最好的机器学习入门课程了.现在一共有20节课放 ...
- 编程方法学 - 公开课学习笔记(一)
好像一直并没有专门学习过某种语言,C也罢,C++也罢,VC也罢,都是在实践中学习.但是Java看过<Thinking in Java>,在实际开发中,优秀的编程风格是很重要的,在我们看so ...
- 公开课学习笔记-[哈佛]计算机科学CS50(一)
看公开课"哈佛-计算机科学CS50",看来一下课程目录,哦,学得真快,一个学期完成这么多,很有效率.和之前看完的斯坦福的课程比起来,录像的效果好,可能是时间不同吧. 第1课:开始 ...
- 【Mechine Learning】斯坦福公开课学习笔记1
很早开始接触机器学习的概念,在一些比赛中调用过OpenCV的级联分类器函数做图像识别,但是一直以来都没有去了解其基本算法,因此在Coursera里参加斯坦福大学Professor Andrew Ng的 ...
- 斯坦福机器学习公开课学习笔记(2)—监督学习 梯度下降
(转载请注明出处:http://blog.csdn.net/buptgshengod) 1.感受 这一节课Andrew讲的是监督学习应用中的梯度下降方法(Supervised-Lear ...
- 机器学习斯坦福公开课学习笔记
第1课 机器学习的动机与应用 无监督学习适用于即使是人也不知道正确答案,但是要进行分类的数据,即对无标签数据进行分类 强化学习可用于机器人领域,实现一些很复杂的.人很难写出每个细节的控制程序,如机器人 ...
- 有道精品公开课-学习笔记
逻辑英语-钟平 中英文翻译语法公式 eg1 介词的核心意思 on-接触 about-画圈圈 及物和不及物(及宾和不及宾) i see you(宾语),see在此处是及物/及宾 she died (后面 ...
最新文章
- 问题集合---《平时遇到的问题 + 参考解决方式》
- vs2015 QT5.6 兼容xp系统
- 数据库的那些事(全是干货)
- 工作177:表单重置项目处理
- ecshop每个商品添加去淘宝购买链接
- 华为MatePad 11配置曝光:骁龙865+2K/120Hz高刷屏
- SQL Server索引视图以(物化视图)及索引视图与查询重写
- Boost.Asio基础(五) 异步编程初探
- Vmware虚机机挂起后无法远程连接
- DPDK初始化分析(五)
- 《Spring实战,【吐血整理】
- Hadoop FS 常用命令详解
- 酷炫小程序相册源码,制作属于自己的相册,免费下载
- 交换机配置软件具有的作用
- Vmware上安装openstack(Queens版)
- java如何jasper_java – 如何以编程方式打印Jasper报告
- 十个著名的思想实验-黑客帝国思想原来是(Brain in a Vat)
- Arduino IDE无法打开问题解决
- win10修复tcp驱动服务器,高手亲自解决win10系统tcpip.sys蓝屏的详尽解决教程
- uni-app获取短信验证码