下面介绍背包、队列和栈(基于链表)的实现,是对《算法(第四版)》1.3 节的部分总结。
首先,应该知道链表及链表的基本操作,在 Java 链表中做了总结,下面主要是给出具体的实现代码。
算法 1 将栈保存为一条链表,栈的顶部即为表头,实例变量 first 指向栈顶。
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 first == null; } // 或: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 = first.item; first = first.next; N--; return item; } public Iterator<Item> iterator() { return new StackIterator(); } private class StackIterator implements Iterator<Item> { private Node current = first; public boolean hasNext() { return current != null; } public Item next() { Item item = current.item; current = current.next; return item; } } public static void main(String[] args) { Stack<String> stack = new Stack<String>(); while (!StdIn.isEmpty()) { String item = StdIn.readString(); if (!item.equals("-")) stack.push(item); else if (!stack.isEmpty()) StdIn.print(stack.pop() + " "); } StdIn.println("(" + stack.size() + " left on stack)"); } }
图 2 显示了图 1 中测试的轨迹。
算法 2 将队列表示为一条从最早插入的元素到最近插入的元素的链表,实例变量 first 指向队列的开头,实例变量 last 指向队列的结尾。
import java.util.Iterator; public class Queue<Item> implements Iterable<Item> { private Node first; // 指向最早添加的结点的链接 private Node last; // 指向最近添加的结点的链接 private int N; // 队列中的元素数量 private class Node { // 定义了结点的嵌套类 Item item; Node next; } public boolean isEmpty() { return first == null; } // 或: N == 0. public int size() { return N; } public void enqueue(Item item) { // 向表尾添加元素 Node oldlast = last; last = new Node(); last.item = item; last.next = null; if (isEmpty()) first = last; else oldlast.next = last; N++; } public Item dequeue() { // 从表头删除元素 Item item = first.item; first = first.next; if (isEmpty()) last = null; N--; return item; } public Iterator<Item> iterator() { return new QueueIterator(first); } private class QueueIterator implements Iterator<Item> { private Node current; public QueueIterator(Node first) { current = first; } public boolean hasNext() { return current != null; } public Item next() { if (!hasNext()) return null; Item item = current.item; current = current.next; return item; } } public static void main(String[] args) { Queue<String> queue = new Queue<String>(); while (!StdIn.isEmpty()) { String item = StdIn.readString(); if (!item.equals("-")) queue.enqueue(item); else if (!queue.isEmpty()) StdIn.print(queue.dequeue() + " "); } StdIn.println("(" + queue.size() + " left on queue)"); } }
图 4 显示了图 3 中测试的轨迹。
用链表数据结构实现我们的 Bag API 只需要将 Stack 中的 push() 改名为 add(),并去掉 pop() 的实现即可,如算法 1.4 所示(也可以用相同的方法实现 Queue,但需要的代码更多)。
import java.util.Iterator; public class Bag<Item> implements Iterable<Item> { private Node first; //链表的首结点 private int N; // 元素数量 private class Node { Item item; Node next; } public boolean isEmpty() { return first == null; } // 或:N == 0 public int size() { return N; } public void add(Item item) { // 和 Stack 的 push() 方法完全相同 Node oldfirst = first; first = new Node(); first.item = item; first.next = oldfirst; } public Iterator<Item> iterator() { return new ListIterator(); } private class ListIterator implements Iterator<Item> { private Node current = first; public boolean hasNext() { return current ! = null; } public void remove() { } public Item next() { Item item = current.item; current = current.next; return item; } } }