Java数据结构与算法解析(二)——栈
来源:互联网 发布:数据字典怎么用 编辑:程序博客网 时间:2024/06/05 18:16
关联文章:
Java数据结构与算法解析(一)——表
栈是限制插入和删除只能在一个位置上进行的表,该位置是表的末端,叫做栈顶。对栈的基本操作有push(进栈)和pop(出栈),对空栈进行push和pop,一般被认为栈ADT的一个错误。当push时空间用尽是一个实现限制,而不是ADT错误。栈有时又叫做LIFO(后进先出)表。
基本概念
允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom),不含任何数据元素的栈称为空栈。栈又称为后进先出的线性表
栈的顺序存储结构
栈的数序结构可以使用数组来实现,栈底是:下标为0的一端
栈的链式存储结构
栈的实现
栈的实现,一般分为两种形式,链式结构和数组。两者均简化了ArrayList和LinkedList中的逻辑。
栈的数组实现
抽象出栈的必备接口
public interface Stack<T> { boolean isEmpty(); void push(T data); T pop(); int size();}
栈的数组实现形式
public class ArrayStack<T> implements Stack<T>, Iterable { private T[] mArray; private int mStackSize; private static final int DEFAULT_CAPACITY = 10; public ArrayStack(int capacity) { if (capacity < DEFAULT_CAPACITY) { ensureCapacity(DEFAULT_CAPACITY); } else { ensureCapacity(capacity); } } public boolean isEmpty() { return mStackSize == 0; } public int size() { return mStackSize; } public void push(T t) { if (mStackSize == mArray.length) { ensureCapacity(mStackSize * 2 + 1); } mArray[mStackSize++] = t; } public T pop() { if (isEmpty()) { throw new EmptyStackException(); } T t = mArray[--mStackSize]; mArray[mStackSize] = null; //调整数组的大小,防止不必要的内存开销 if (mStackSize > 0 && mStackSize < mArray.length / 4) { ensureCapacity(mArray.length / 2); } return t; } private void ensureCapacity(int newCapacity) { T[] newArray = (T[]) new Object[newCapacity]; for (int i = 0; i < mArray.length; i++) { newArray[i] = mArray[i]; } mArray = newArray; } @Override public Iterator iterator() { return null; } private class ArrayStackIterator implements Iterator<T> { @Override public boolean hasNext() { return mStackSize > 0; } @Override public T next() { return mArray[--mStackSize]; } }}
对象游离
Java的垃圾收集策略是回收所有无法被访问对象的内存,如果我们pop()弹出对象后,不调用如下代码,就会造成游离,因为数组中仍然持有这个对象的引用,保存一个不需要的对象的引用,叫做游离。
mArray[mStackSize] = null;
动态调整数组大小
pop()中,删除栈顶元素后,如果栈的大小小于数组的1/4,就将数组的大小减半,这样栈永远不会溢出,使用率也不会小于1/4。
栈的链表实现
采用链式存储结构的栈,由于我们操作的是栈顶一端,因此这里采用单链表(不带头结点)作为基础,直接实现栈的添加,获取,删除等主要操作即可。
链栈的出入栈操作
链栈的入栈操作:
链栈的出栈操作:
“`
public class LinkedStack implements Stack, Iterable {
private int mSize;private Node<T> endNote;private int modCount;public LinkedStack() { init();}private void init() { endNote = new Node<T>(null, null); modCount++;}@Overridepublic boolean isEmpty() { return mSize == 0;}@Overridepublic void push(T data) { Node<T> newNote = new Node<T>(data, null); endNote.mNext = newNote; mSize++; modCount++;}@Overridepublic T pop() { if (endNote.mNext == null) { throw new NoSuchElementException(); } T t = endNote.mNext.mData; endNote.mNext = endNote.mNext.mNext; mSize--; modCount++; return t;}@Overridepublic int size() { return mSize;}@Overridepublic Iterator iterator() { return new LinkedStackIterator();}private static class Node<T> { private Node<T> mNext; private T mData; public Node(T data, Node<T> next) { mData = data; mNext = next; }}private class LinkedStackIterator implements Iterator<T> { private Node<T> currentNode = endNote.mNext; private int expectedModCount = modCount; @Override public boolean hasNext() { return currentNode != null; } @Override public T next() { if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } if (!hasNext()) { throw new NoSuchElementException(); } T t = currentNode.mData; currentNode = currentNode.mNext; return t; }}
}
时间复杂度对比
顺序栈复杂度
链式栈复杂度
可知栈的主要操作都可以在常数时间内完成,这主要是因为栈只对一端进行操作,而且操作的只是栈顶元素。
栈的经典实用
逆波兰表达式法
标准四则运算表达式—中缀表达式
我们在小学学习的四则运算表达式就是中缀表达式 ,但是计算机是不认识中缀表达式的,它采用的是后缀表达式
计算机采用—后缀表达式
计算规则:
它的规则是,从头开始遍历,遇到数字进行压栈,遇到运算符号,将栈顶开始的两个元素进行运算符操作后,弹栈,结果进栈,931遇到“—”时,进行3-1=2,将2进栈,然后3进栈,遇到“*”,3*2=6进栈,遇到“+”,进行9+6=15进栈,然后10和2进栈,遇到“/”,进行10/2后结果进栈,最后是15+5=20,就完成了后缀表达式的计算操作。
中缀表达式转后缀表达式
数字输出,运算符进栈,括号匹配出栈,是当栈顶是运算符时,又压进来一个运算符,如果压进来的运算符优先级比栈顶的高,则这个压进来的运算符出栈。
如果我们见到任何其他的符号(+,*,(),那么我们从栈中弹出栈元素直到发现优先级更低的元素为止。有一个例外:除非是在处理一个)的时候,否则我们决不从栈中移走(。对于这种操作,+的优先级最低,而(的优先级最高。当从栈弹出元素的工作完成后,我们再将操作符压入栈中。
- Java数据结构与算法解析(二)——栈
- Java数据结构与算法解析(二)——栈
- Java数据结构与算法解析(一)——表
- Java数据结构与算法解析(一)——表
- Java数据结构与算法解析(六)——AVL树
- Java数据结构与算法解析(八)——伸展树
- Java数据结构与算法解析(六)——AVL树
- Java数据结构与算法解析(九)——B树
- Java数据结构与算法解析(八)——伸展树
- Java数据结构与算法解析(八)——伸展树
- Java数据结构与算法解析(九)——B树
- Java数据结构与算法解析(八)——伸展树
- Java数据结构与算法解析(十一)——红黑树
- Java数据结构与算法解析(十二)——散列表
- Java数据结构与算法解析(十一)——红黑树
- Java数据结构与算法解析(十三)——优先级队列
- Java数据结构与算法解析(十四)——二叉堆
- Java数据结构与算法解析(一)——表
- TCP通信的几种方式
- 爬虫实战之三--mysql安装
- 17. Letter Combinations of a Phone Number
- 64位ubuntu无法安装32位软件,或者是运行32位.run等文件,出现`no such file or directory`问题
- 十连测d1T3
- Java数据结构与算法解析(二)——栈
- PCIISA桥设计和实现
- 计算机网络的结构
- make makefile cmake qmake
- ZOJ1516_Uncle Tom's Inherited Land_二分图(匈牙利算法)
- 元组UPLE:戴上了枷锁的列表--2017/9/3--1
- 排序之插入排序
- LeetCode 326. Power of Three
- c面试考点