背包、队列和栈
背包
定义
背包是一种不支持从中删除元素的集合类型。
使用场景
帮助用例收集元素并迭代遍历所有收集到的元素。迭代的顺序不确定并且与用例无关。
典型用例
求平均值和方差
public class Stats {
public static void main(String[] args) {
Bag<Double> numbers = new Bag<Double>();
while (!StdIn.isEmpty()) {
numbers.add(StdIn.readDouble());
}
int N = numbers.size();
double sum = 0.0;
for (double x : numbers) {
sum += x;
}
double mean = sum / N;
sum = 0.0;
for (double x : numbers) {
sum += (x - mean) * (x - mean);
}
double std = Math.sqrt(sum / (N - 1));
StdOut.printf("Mean: %.2f\n", mean);
StdOut.printf("Std dev: %.2f\n", std);
}
}
先进先出队列
定义
先进先出队列(或简称队列)是一种基于先进先出(FIFO)策略的集合类型。
使用场景
在应用程序中使用队列的主要原因是在用集合保存元素的同时保存它们的相对顺序:使它们入列顺序和出列顺序相同。
典型用例
用例无需预先知道文件的大小即可将文件中所有整数读入一个数组中
public static int[] readInts(String name) {
In in = new In(name);
Queue<Integer> q = new Queue<Integer>();
while (!in.isEmpty()) {
q.enqueue(in.readInt());
}
int N = q.size();
int[] a = new int[N];
for (int i = 0; i < N; i++) {
a[i] = q.dequeue();
}
return a;
}
下压栈
定义
下压栈(或简称栈)是一种基于后进先出策略(LIFO)的集合类型。
典型用例
在用集合保存元素的同时颠倒它们的相对顺序
public class Reverse {
public static void main(String[] args) {
Stack<Integer> stack = new Stack<Integer>();
while (!StdIn.isEmpty()) {
stack.push(StdIn.readInt());
}
for (int i : stack) {
StdOut.println(i);
}
}
}
Dijkstra双栈算数表达式求值算法
public class Evaluate {
public static void main(String[] args) {
Stack<String> ops = new Stack<String>();
Stack<Double> vals = new Stack<Double>();
while (!StdIn.isEmpty()) {
// 读取字符,如果是运算符则压入栈
String s = StdIn.readString();
if (s.equals("(")) {
;
} else if (s.equals("+")) {
ops.push(s);
} else if (s.equals("-")) {
ops.push(s);
} else if (s.equals("*")) {
ops.push(s);
} else if (s.equals("/")) {
ops.push(s);
} else if (s.equals("sqrt")) {
ops.push(s);
} else if (s.equals(")")) {
// 如果字符为 ")",弹出运算符合操作数,计算结果并压入栈
String op = ops.pop();
double v = vals.pop();
if (op.equals("+")) {
v = vals.pop() + v;
} else if (op.equals("-")) {
v = vals.pop() - v;
} else if (op.equals("*")) {
v = vals.pop() * v;
} else if (op.equals("/")) {
v = vals.pop() / v;
} else if (op.equals("sqrt")) {
v = Math.sqrt(v);
}
vals.push(v);
} else {
// 如果字符既非运算符也不是括号,将它作为 double 值压入栈
vals.push(Double.parseDouble(s));
}
}
StdOut.println(vals.pop());
}
}
链表
定义
链表是一种递归的数据结构,它或者为空(null),或者是指向一个结点(node)的引用,该接点含有一个泛型的元素和一个指向另一条链表队引用。
结点
class Node {
Item item;
Node next;
}
用链表实现栈
public class Stack<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 class Queue<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 viod 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;
}
}
用链表实现背包
import java.util.Iterator;
public class Bag<Item> implements Iterable<Item> {
private Node first;
private class Node {
Item item;
Node next;
}
public void add(Item item) {
Node oldfirst = first;
first = new Item();
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;
}
}
}