java栈和队列
栈
可变长数组实现
链表实现
数组与链表的对比
队列
链表实现
栈
下压栈(简称栈)是一种基于后进后出(LIFO)策略的集合类型。这里学习分别用数组和链表这两种基础数据结构来实现栈。
栈支持的基本操作有push,pop。
可变长数组实现
要用数组实现栈,可以声明一个int型的标记,这个标记指向的位置即为栈顶,push操作时,将值放在数据中标记的位置,同时将标记+1,pop时,返回数组在标记位置的值,同时标记-1。
但java中的数组在声明的时候其长度就已经固定了,所以栈使用的空间只能是这个数组最大容量的一部分。为了能容纳更多的数据而声明一个特别大的数组会非常浪费空间,那如何解决这个问题,达到既不会浪费数组空间也不会超出数组范围呢?
可以采用动态调整数组大小的方式,在push操作导致栈已满时,重新创建一个数组,其容量为原数组的两倍。同理在pop操作使数组的闲置空间达到一定程度时,重新创建一个容量更小的数组。但闲置的判断标准不能为一半1/2,否则会造成在1/2的临界点处push和pop操作时发生“抖动”,即频繁地进行数组扩容、缩容操作,这会极大地降低栈的性能。所以通常的做法是在减少到数组容量的1/4时缩容为1/2。
实现可变长数组的代码如下:
public class StackResizeArray<Item> {
private Item[] a; // array of items
private int n; // number of elements on stack
public StackResizeArray() {
a = (Item[]) new Object[2];
n = 0;
}
public boolean isEmpty() {
return n == 0;
}
public int size() {
return n;
}
private void resize(int capacity) {
assert capacity >= n;
Item[] temp = (Item[]) new Object[capacity];
for (int i = 0; i < n; i++) {
temp[i] = a[i];
}
a = temp;
}
public void push(Item item) {
if (n == a.length)
resize(2 * a.length); // double size of array if necessary
a[n++] = item; // add item
}
public Item pop() {
if (isEmpty())
throw new NoSuchElementException("Stack underflow");
Item item = a[n - 1];
a[n - 1] = null; // to avoid loitering
n--;
// shrink size of array if necessary
if (n > 0 && n == a.length / 4)
resize(a.length / 2);
return item;
}
}
pop方法中,a[n - 1] = null将数组中已经出栈的位置设为null,是为了避免对象游离,否则这个位置的对象虽然已经不在栈中,但还被数组引用着,导致GC无法对其回收。
链表实现
栈的另外一种实现方式是采用链表,链表是一种递归的数据结构,它或者为空,或者指向一个结点的引用,该结点含有一个泛型的元素和一个指向另一条链表的引用。 构成链表的基本结点可以为:
private static class Node<Item> {
public Item item;
public Node next;
}
其中泛型的item变量存放数据,同样是Node类型的next变量用来指向下一个结点。将链表的头部作为栈顶,push相当于在表头插入元素,pop是从表头删除元素。 代码如下:
public class StackLinkedList<Item> {
private static class Node<Item> {
public Item item;
public Node next;
}
private Node<Item> first;
private int N;
private boolean isEmpty() {
return first == null;
}
public int size() {
return N;
}
public void push(Item item) {
Node<Item> oldFirst = first;
first = new Node<Item>();
first.item = item;
first.next = oldFirst;
N++;
}
public Item pop() {
if (isEmpty())
throw new NoSuchElementException("Stack underflow");
Item item = first.item;
first = first.next;
N--;
return item;
}
}
数组与链表的对比
数组与链表的区别决定了两种栈实现的区别:
- 存取方式上,数组可以顺序存取或者随机存取,而链表只能顺序存取;
- 存储位置上,数组逻辑上相邻的元素在物理存储位置上也相邻,而链表不一定;
- 存储空间上,链表由于带有指针域,存储密度不如数组大;
- 按序号查找时,数组可以随机访问,需要的时间是常数,而链表不支持随机访问,需要的时间与数据规模成线性关系。
- 按值查找时,若数组无序,数组和链表时间复杂度均为O(n),但是当数组有序时,可以采用折半查找将时间复杂度降为O(logn);
- 插入和删除时,数组平均需要移动n/2个元素,而链表只需修改指针即可;
- 空间分配方面: 虽然可变长数组可以扩充,但需要移动大量元素,导致操作效率降低,而且如果内存中没有更大块连续存储空间将导致分配失败; 链表存储的节点空间只在需要的时候申请分配,只要内存中有空间就可以分配,操作比较灵活高效;
队列
链表实现
先进先出队列(简称队列)是一种基于先进先出(FIFO)策略的集合类型。这里只关注队列的链表实现。与链表实现的栈类似,用结点包含泛型的item变量和next变量,前者存放数据,后者用来指向下一个结点。不同之处在于链表的头部、尾部都会被操作,从链表的一端入队(enqueue),从另一端出队(dequeue) 代码:
public class Queue<Item> {
private static class Node<Item> {
public Item item;
public Node next;
}
private Node<Item> first;
private Node<Item> last;
private int N;
public void enqueue(Item item) {
Node<Item> oldLast = last;
last = new Node<Item>();
last.item = item;
if (isEmpty()) {
first = last;
} else {
oldLast.next = last;
}
N++;
}
public Item dequeue() {
if (isEmpty()) {
return null;
}
Item result = first.item;
first = first.next;
if (isEmpty()) {
last = null;
}
N--;
return result;
}
public boolean isEmpty() {
return N == 0;
}
public int size() {
return N;
}
}
java栈和队列的更多相关文章
- java 栈和队列的模拟--java
栈的定义:栈是一种特殊的表这种表只在表头进行插入和删除操作.因此,表头对于栈来说具有特殊的意义,称为栈顶.相应地,表尾称为栈底.不含任何元素的栈称为空栈. 栈的逻辑结构:假设一个栈S中的元素为an,a ...
- 数据结构与算法分析java——栈和队列
1. 栈 1.1 分类 顺序栈:顺序线性表实现 链式栈:单向链表存储堆栈 1.2栈的应用 1)数制转换 import java.util.Scanner; import java.util.Stack ...
- java——栈和队列 面试题
(1)栈的创建 (2)队列的创建 (3)两个栈实现一个队列 (4)两个队列实现一个栈 (5)设计含最小函数min()的栈,要求min.push.pop.的时间复杂度都是O(1) (6)判断栈的push ...
- Java 堆、栈、队列(遇见再更新)
目录 Java 栈.队列 栈 常用方法 案例 队列 Java 栈.队列 栈 常用方法 boolean empty() 测试堆栈是否为空 Object peek() 查看堆栈顶部的对象 Object p ...
- 栈和队列的面试题Java实现【重要】
栈和队列: 面试的时候,栈和队列经常会成对出现来考察.本文包含栈和队列的如下考试内容: (1)栈的创建 (2)队列的创建 (3)两个栈实现一个队列 (4)两个队列实现一个栈 (5)设计含最小函数min ...
- Java中ArrayDeque,栈与队列
package ch8; import java.util.*; /** * Created by Jiqing on 2016/11/27. */ public class ArrayDequeSt ...
- 线性表 及Java实现 顺序表、链表、栈、队列
数据结构与算法是程序设计的两大基础,大型的IT企业面试时也会出数据结构和算法的题目, 它可以说明你是否有良好的逻辑思维,如果你具备良好的逻辑思维,即使技术存在某些缺陷,面试公司也会认为你很有培养价值, ...
- 栈和队列的面试题Java
栈和队列: 面试的时候,栈和队列经常会成对出现来考察.本文包含栈和队列的如下考试内容: (1)栈的创建 (2)队列的创建 (3)两个栈实现一个队列 (4)两个队列实现一个栈 (5)设计含最小函数min ...
- 栈和队列的面试题Java实现
栈和队列: 面试的时候,栈和队列经常会成对出现来考察.本文包含栈和队列的如下考试内容: (1)栈的创建 (2)队列的创建 (3)两个栈实现一个队列 (4)两个队列实现一个栈 (5)设计含最小函数min ...
随机推荐
- javaScript中 数组的新方法(reduce)
定义和用法 reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值. reduce() 可以作为一个高阶函数,用于函数的 compose. 注意: redu ...
- mock.js 模拟数据
1. 劫持请求,返回模拟数据: 用于前后台对接前数据模拟 相比于静态json文件而言:代码完成后不必修改源文件对应的接口调用.可模拟增删改查 2.实例代码 <!doctype html> ...
- python多线程之_thread
多线程类似于同时执行多个不同程序,多线程运行有如下优点: 使用线程可以把占据长时间的程序中的任务放到后台去处理. 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进 ...
- 使用ELK进行日志分析
0x01 前言: 前段时间做应急,总是需要溯源分析,痛点是数据量比较大,想要短时间能分析出来.再者就是之前在调查某酒店事件的时候特别羡慕某产商有各种分析溯源工具.反思过后,终于在没有那么忙的时候开始搭 ...
- List的Select 和Select().tolist()
List<Person> delp = new List<Person> { ,Name=,Sign= }, ,Name= ,Sign=}, }; delp.Select(u ...
- 13、yum
1.yum yum是管理rpm包的工具 2.yum源(yum仓库) 要使用yum前,需要准备一个yum源(我们也称为yum仓库), 这个可以是一个互联网上的仓库,也可以是本地自己搭建的仓库. 仓库里面 ...
- 2019.10.28sql注入工具
SQLMAP工具的使用 sql注入工具:明小子 啊D 萝卜头 穿山甲 sqlmap等等 开源自动化注入利用工具,支持12中数据库,在/plugins中可以看到支持的数据库种类 支持的注入类型:bool ...
- zabbix 邮件报警事件:Zabbix discoverer processes more than 75% busy
Problem has been resolved at :: on Problem name: Zabbix discoverer processes more than % busy Host: ...
- PAT Basic 1002 写出这个数 (20 分)
读入一个正整数 n,计算其各位数字之和,用汉语拼音写出和的每一位数字. 输入格式: 每个测试输入包含 1 个测试用例,即给出自然数 n 的值.这里保证 n 小于 1. 输出格式: 在一行内输出 n 的 ...
- Python中的序列
Python中有四种内建的数据结构,即列表.元组.字典.集合.其中字典和集合我会以后再写,现在先说列表和元组,它们两个和以前提到很多次的字符串, 其实都属于——序列. 一.列表(list): 1. l ...