背包、队列和栈都是集合的数据类型,区别仅在于删除或者访问对象的顺序不同。 而对于存储对象集合的方式,有数组和链表两种,常被分别称为顺序存储和链是存储。
下面关于每个数据类型,都将提供数组和链表两种代码实现方式。
链表是一种递归的数据结构,它或者为空(null),或者是指向一个结点(node 的引用, 该结点含有一个泛型的元素和一个指向另一条链表的引用
特点:
- 可以处理任意类型的数据
- 所需的空间总是和集合的大小成正比
- 操作所需的时间总是和集合的大小无关
背包(Bag)
帮助用例收集元素并迭代遍历所有收集到的元素
特点:
- 不支持删除元素
- 迭代顺序不确定且与用例无关
数组实现:
链表实现:
import java.util.Iterator;
public class LinkedBag%3CItem%3E implements Iterable<Item> {
private int size;
private Node first;
public class Node {
Item item;
Node next;
}
public boolean isEmpty() {
return size == 0;
}
public int size() {
return size;
}
public void push(Item item) {
Node oldFirst = first;
first = new Node();
first.item = item;
first.next = oldFirst;
size++;
}
public Iterator<Item> iterator() {
return new ListIterator();
}
private class ListIterator implements Iterator<Item> {
Node current = first;
public boolean hasNext() {
return current != null;
}
public Item next() {
Item item = current.item;
current = current.next;
return item;
}
public void remove() {
}
}
public static void main(String[] args) {
}
}
队列(Queue)
帮助迭代并按照添加顺序输出元素
特点:
- 先进先出,入列顺序和出列顺序相同
数组实现:
import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;
public class ResizingArrayQueueOfStrings<Item> {
private Item[] a = (Item[]) new Object[1];
private int size;
private int first;
private void resize(int max) {
Item[] temp = (Item[]) new Object[max];
if (size + first < a.length) {
for (int i = 0; i < size; i++) {
temp[i] = a[first + i];
}
first = 0;
}
else {
for (int i = 0; first + i < a.length; i++) {
temp[max - a.length + first + i] = a[first + i];
}
for (int i = 0; i < first + size - a.length; i++) {
temp[i] = a[i];
}
first = max - a.length + first;
}
a = temp;
}
public boolean isEmpty() {
return size == 0;
}
public int size() {
return size;
}
public void enqueue(Item item) {
if (size == a.length) resize(a.length * 2);
if (size + first < a.length) a[size + first] = item;
else a[size + first - a.length] = item;
size++;
}
public Item dequeue() {
Item item = a[first];
// a[first] = null;
if (first < a.length - 1) first++;
else first = 0;
if (size < a.length / 4) resize(a.length / 2);
size--;
return item;
}
}
链表实现:
import edu.princeton.cs.algs4.Queue;
import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;
import java.util.Iterator;
public class LinkedQueue<Item> implements Iterable<Item> {
private int size;
private Node first;
private Node last;
private class Node {
Item item;
Node next;
}
public boolean isEmpty() {
return size == 0;
}
public int size() {
return size;
}
public void push(Item item) {
Node oldlast = last;
last = new Node();
last.item = item;
oldlast.next = last;
size++;
}
public Item pop() {
Item item = first.item;
first = first.next;
size--;
return item;
}
public Iterator<Item> iterator() {
return new ListIterator();
}
private class ListIterator implements Iterator<Item> {
Node current = first;
public boolean hasNext() {
return current != null;
}
public Item next() {
Item item = current.item;
current = current.next;
return item;
}
public void remove() {
}
}
public static void main(String[] args) {
// 创建一个队列并操作字符串入列或出列
Queue<String> q = new Queue<String>();
while (!StdIn.isEmpty()) {
String item = StdIn.readString();
if (!item.equals("-"))
q.enqueue(item);
else if (!q.isEmpty()) StdOut.print(q.dequeue() + " ");
}
StdOut.println("(" + q.size() + " left on queue)");
}
}
栈(Stack)
用集合保存元素的同时颠倒他们的相对顺序
特点:
- 后进先出,总是从最新的元素开始迭代
下压(LIFO)栈
特点: 能够动态调整数组大小的实现
数组实现:
import java.util.Iterator;
public class ResizingArrayStack<Item> {
private int size;
private Item[] a = (Item[]) new Object[1];
private void resize(int max) {
Item[] temp = (Item[]) new Object[max];
for (int i = 0; i < size; i++) {
temp[i] = a[i];
}
a = temp;
}
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 * 4 < a.length) {
resize(a.length / 2);
}
return item;
}
public boolean isEmpty() {
return size == 0;
}
public int size() {
return size;
}
public Iterator<Item> iterator() {
return new ResizingArrayStackIterator();
}
private class ResizingArrayStackIterator implements Iterator<Item> {
// 支持后进先出的迭代
private int i = size;
public boolean hasNext() {
return i > 0;
}
public Item next() {
return a[--i];
}
public void remove() {
}
}
public static void main(String[] args) {
}
}
链表实现:
import edu.princeton.cs.algs4.Stack;
import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;
import java.util.Iterator;
public class LinkedStack%3CItem%3E implements Iterable<Item> {
private int size;
private Node first;
public class Node {
Item item;
Node next;
}
public boolean isEmpty() {
return size == 0;
}
public int size() {
return size;
}
public void push(Item item) {
Node oldFirst = first;
first = new Node();
first.item = item;
first.next = oldFirst;
size++;
}
public Item pop() {
Item item = first.item;
first = first.next;
size--;
return item;
}
public Iterator<Item> iterator() {
return new ListIterator();
}
private class ListIterator implements Iterator<Item> {
Node current = first;
public boolean hasNext() {
return current != null;
}
public Item next() {
Item item = current.item;
current = current.next;
return item;
}
public void remove() {
}
}
public static void main(String[] args) {
// 创建一个栈并根据StdIn中的指示压入或弹出字符串
Stack<String> s = new Stack<String>();
while (!StdIn.isEmpty()) {
String item = StdIn.readString();
if (!item.equals("-"))
s.push(item);
else if (!s.isEmpty()) StdOut.print(s.pop() + " ");
}
StdOut.println("(" + s.size() + " left on stack)");
}
}
节省内存策略
- 在push和pop操作时检查并适时调整数组大小
- 避免对象游离