下压栈(LIFO)
算法1.1 可动态调整数组大小的实现
public class ResizingArrayStack<Item> implements Iterable<Item> {private Item[] a = (Item []) new Object[1];//元素栈private int N;//元素个数public boolean isEmpty() {return N == 0;}public int size() {return N;}private void resize(int max) {Item[] temp = (Item []) new Object[max];for(int i = 0; i < max; i++) {temp[i] = a[i];}a = temp;}//调整数组大小public void push(Item item) {if(N == a.length) resize(2*a.length);a[N++] = item;}//添加元素到栈顶public Item pop() {Item item = a[--N];a[N] = null;//防止对象游离if(N > 0 && N == a.length/4) resize(a.length/2);return item;}//从栈顶删除元素@Overridepublic Iterator<Item> iterator() {return new ReverseArrayIterator;}private class ReverseArrayIterator implements Iterator<Item> {private i = N;@Overridepublic boolean hasNext() {return i > 0;}@Overridepublic Item next() {return a[--i];}@Overridepublic void remove() {}}}
要点
- 可变数组下压栈的主类和内部类需要分别实现Iterable,Iterator接口,从而实现LIFO逆序迭代,否则会按照数组FIFO迭代;
 - algs4书中对于remove()总为空,避免在迭代中穿插修改数据结构的操作
 - 为保证数组缩减后有一半的空间利用率,判断条件应该是N == a.length/4
 - 删除栈顶元素时,实际上被弹出元素的引用仍保存在数组中,但该元素永远不会被访问,直到下次push()后,原有引用指向新元素.Java垃圾收集器才会回收空间,期间造成空间浪费,使用a[N] = null避免元素游离.
 
特点
- 算法1.1的每项操作用时与集合大小无关:操作始终只针对栈顶元素;
 - 空间需求总是不超过集合大小乘一个常数;
 - 栈永远不会溢出,使用率也不会低于四分之一,除非栈为空时,数组大小为1;
 
算法1.2 链表实现
import edu.princeton.cs.algs4.StdIn;import edu.princeton.cs.algs4.StdOut;import java.util.Iterator;public class Stack<Item> implements Iterable<Item> {private Node first;private int N;private class Node {Item item;Node next;}public boolean isEmpty(){ return N == 0;}public int size(){ return N; }public void push(Item item){Node oldFirst = first ;first = new Node();first.item = item;first.next = oldFirst;N++;}public Item pop(){Item item;item = first.item;first = first.next;N--;return item;}@Overridepublic Iterator<Item> iterator(){return new ListIterator();}private class ListIterator implements Iterator<Item>{private Node current = first;@Overridepublic boolean hasNext(){ return current != null;}@Overridepublic Item next(){Item item = current.item;current = current.next;return item;}@Overridepublic void remove(){}}}
要点
- 实例变量:头结点first
 - 完成内部类Node;
 - isEmpty()可以判断N == 0或first == null;
 - 迭代实现同上
 
特点
- 可以处理任意类型数据;
 - 所需空间总是和集合大小成正比;
 - 操作所需时间和集合大小无关(链式结构);
 
关于内部类实现泛型接口*
算法内部类
private class ListIterator implements Iterator<Item>{}//不是private class ListIterator<Item> implements Iterator<Item>
算法外部类
public class Stack<Item> implements Iterable<Item>
当类实现泛型接口时,不能确定接口中的泛型,这时就要求这个类也必须定义泛型,而且泛型名称要一致,因此主类Stack后也要定义泛型;当内部类实现和主类泛型类型一致的接口(本算法中),此时泛型已经可以由主类的定义判断,则内部类的泛型无需在定义泛型,如果重复定义会提示错误.
