1:概念
首先介绍下三者的概念:
- 栈 :所谓的“栈”也称之为“后进先出队列”,可以想像成放在桌上的一叠书,每次无论增加还是减少都在顶部。
- 队列:“先进先出队列”,类比生活中的排队。增加在队尾,减少在队头
- 背包:背包本质上和前两者没有什么不同,可以是栈,也可以是队列,使用这个概念意在表示在个别情况下元素处理的顺序不重要,可以是“先进先出”也可以是“后进先出”
这三种数据类型称之为 “集合数据类型”
2:API
3:栈的数组的实现以及对其一些改进
首先为了简单起见,我们先使用数组来表示栈:
import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;
class FixedCapacityStackOfStrings {
private String[] a;
private int size;
public FixedCapacityStackOfStrings(int n) {
a = new String[n];
}
public void push(String item) {
a[size++] = item;
}
public String pop() {
return a[--size];
}
public boolean isEmpty() {
return size == 0;
}
public int size() {
return size;
}
}
public class Test {
public static void main(String args[]) {
FixedCapacityStackOfStrings s = new FixedCapacityStackOfStrings(100);
while(!StdIn.isEmpty()) {
String item = StdIn.readString();
if(!item.equals("-"))
s.push(item);
else if(!s.isEmpty())
System.out.print(s.pop() + " ");
}
}
}
结果如下:
由于该种栈只支持“String”类型,所以可以用泛型对其进行改进,以便符合其它类型的栈
import edu.princeton.cs.algs4.StdIn;
class FixedCapacityStack<Item> {
private Item[] a;
private int size;
public FixedCapacityStack(int n) {
a = (Item[]) new Object[n];
}
public void push(Item item) {
a[size++] = item;
}
public Item pop() {
return a[--size];
}
public boolean isEmpty() {
return size == 0;
}
public int size() {
return size;
}
}
public class Test {
public static void main(String args[]) {
FixedCapacityStack<String> s = new FixedCapacityStack(100);
while(!StdIn.isEmpty()) {
String item = StdIn.readString();
if(!item.equals("-"))
s.push(item);
else if(!s.isEmpty())
System.out.print(s.pop() + " ");
}
System.out.println(s.size());
}
}
但是这样依旧还有一些缺点,比如说大小的调整。因为无法实现确定栈的大小,只能采取多分配大一些的空间,这样无疑绘很浪费。所以进一步改进如下:
import java.util.Iterator;
import edu.princeton.cs.algs4.StdIn;
class FixedCapacityStack<Item> implements Iterable<Item>{
private Item[] a;
private int size = 0; //元素的大小
private void resize(int len) { //该方法将a[]大小扩大(缩小)到len
Item[] temp = (Item[]) new Object[len];
for(int i = 0; i < len; i++)
temp[i] = a[i];
a = temp;
}
public FixedCapacityStack(int n) {
a = (Item[]) new Object[n];
}
public void push(Item item) {
if(size == a.length)
resize(2 * a.length);
a[size++] = item;
}
public Item pop() {
Item item = a[--size];
a[size] = null; //避免对象游离
if(size > 0 && size == a.length)
resize(a.length / 2);
return item;
}
public boolean isEmpty() {
return size == 0;
}
public int size() {
return size;
}
//为了能够使用foreach打印,实现了一个iterator()方法以及一个ReverseArrayIterator内部类
public Iterator<Item> iterator() {
return new ReverseArrayIterator();
}
private class ReverseArrayIterator implements Iterator<Item>{
private int i = size;
public boolean hasNext() {
return i > 0;
}
public Item next() {
return a[--i];
}
public void remove() {}
}
}
这段代码相比前面两个做了3点优化:
- 实现了数组可自动调整
- 在pop()方法中使用了a[size] = null; 避免对象游离
- 新增加一个iterator()方法以及一个ReverseArrayIterator内部类,以便能够使用foreach()方法打印该对象
尽管这是数组来表示栈最好的方式,但是数组里面空间的浪费依然不可避免。所以下面给出另一种数据结构来表示栈
4:使用链表来表示栈
import java.util.Iterator;
public class Stack<Item> implements Iterable<Item>{
private Node top; //栈顶元素
private int size; //元素数量
private class Node {
Item item;
Node next;
}
public boolean isEmpty() {
return top == null;
}
public int size() {
return size;
}
public void push(Item item) {
Node oldTop = top;
top = new Node();
top.item = item;
top.next = oldTop;
size++;
}
public Item pop() {
Item item = top.item;
top = top.next;
size--;
return item;
}
//以下部分是为了实现foreach打印
public Iterator<Item> iterator() {
return new ListIterator();
}
private class ListIterator implements Iterator<Item> {
private Node current = top;
public boolean hasNext() {
return current != null;
}
public void remove() {}
public Item next() {
Item item = current.item;
current = current.next;
return item;
}
}
}
public class Test {
public static void main(String args[]) {
Stack<String> s = new Stack();
while(!StdIn.isEmpty()) {
String item = StdIn.readString();
if(!item.equals("-"))
s.push(item);
else if(!s.isEmpty())
System.out.print(s.pop() + " ");
}
}
}
5:用链表实现队列以及背包
链表实现队列
import java.util.Iterator;
public class Queue<Item> implements Iterable<Item>{
private Node first;
private Node last;
private int size;
private class Node {
Item item;
Node next;
}
public boolean isEmpty() {
return first == null;
}
public int size() {
return size;
}
public void push(Item item) {
Node oldLast = last;
last = new Node();
last.item = item;
last.next = null;
if(isEmpty())
first = last;
else
oldLast.next = last;
size++;
}
public Item pop() {
Item item = first.item;
first = first.next;
if(isEmpty())
last = null;
size--;
return item;
}
//以下部分是为了实现foreach打印
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;
}
}
}
用链表实现背包
import java.util.Iterator;
public class Bag<Item> implements Iterable {
private Node first;
private int size;
private class Node {
Item item;
Node next;
}
public void add(Item item) {
Node oldFirst = first;
first = new Node();
first.item = item;
first.next = oldFirst;
size++;
}
//以下部分是为了实现foreach打印
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;
}
}
}