背包、队列和栈
API
背包 | |
---|---|
public class Bag |
|
Bag() | 创建一个空背包 |
void add(Item item) | 添加一个元素 |
boolean isEmpty() | 背包是否为空 |
int size() | 背包中的元素数量 |
先进先出(FIFO)队列 | |
---|---|
pubilc class Queue |
|
Queue() | 创建空队列 |
void enqueue(Item item) | 添加一个元素 |
Item dequeue() | 删除最早添加的元素 |
boolean isEmpty() | 队列是否 |
int size() | 队列中元素的数量 |
下压(后进先出,LIFO)栈 | |
---|---|
public class Stack |
|
Stack() | 创建一个空栈 |
void push(Item item) | 添加一个元素 |
Item pop() | 删除最近添加的元素 |
boolean isEmpty() | 栈是否为空 |
int size() | 栈中的元素数量 |
背包
背包是一种不支持从中删除元素的集合数据类型——它的目的就是帮助用例手机元素并迭代遍历所有收集到的元素,迭代的顺序不确定并且与用例无关。
典型用例:求平均值和方差
public class Statas {
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", mean);
StdOut.printf("Std dev: %.2f\n", std);
}
}
先进先出队列
先进先出队列(或简称队列)是一种基于先进先出(FIFO)策略的集合类型。
生活中的例子:在影剧院门前排队的人群、在收费站前排队的汽车或是计算机上某种软件中等待处理的任务。
用例:
public static void main(String[] args) {
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;
stack = new Stack<Integer>();
while (!StdIn.isEmpty()) {
stack.push(StdIn.readInt());
}
for (int i : stack) {
StdOut.pop();
}
}
}
栈的应用:算数表达式求值
用两个栈,一个用于保存运算符,一个用于保存操作数。
- 将操作数压入操作数栈
- 将运算符压入运算符栈
- 忽略左括号
- 在遇到右括号时,弹出一个运算符,弹出所需数量的操作数,并将运算符和操作数的运算结构压入操作数栈
在处理完最后一个右括号时,操作数栈上只会有一个值,它就是表达式的值。
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());
}
}