Deques and Randomized Queues
Deque.java
双向队列,因为要求所有操作的复杂度为 O ( 1 ) O(1) O(1),采用双向链表进行实现。
import java.util.Iterator;
import java.util.NoSuchElementException;
public class Deque<Item> implements Iterable<Item> {
private Node first = null;
private Node last = null;
private int size = 0;
// construct an empty deque
public Deque() {}
// is the deque empty?
public boolean isEmpty() {
return first == null;
}
// return the number of items on the deque
public int size() {
return size;
}
// add the item to the front
public void addFirst(Item item) {
if (item == null) {
throw new IllegalArgumentException();
}
size++;
Node old = first;
first = new Node();
first.item = item;
// 若原队列为空需要进行特殊处理
if (old == null) {
last = first;
return;
}
first.next = old;
old.prev = first;
}
// add the item to the back
public void addLast(Item item) {
if (item == null) {
throw new IllegalArgumentException();
}
size++;
Node old = last;
last = new Node();
last.item = item;
// 若原队列为空需要进行特殊处理
if (old == null) {
first = last;
return;
}
old.next = last;
last.prev = old;
}
// remove and return the item from the front
public Item removeFirst() {
if (isEmpty()) {
throw new NoSuchElementException();
}
Node temp = first;
first = first.next;
// 若移除后为空队列需要进行特殊处理
if (first == null) {
last = null;
} else {
first.prev = null;
}
size--;
return temp.item;
}
// remove and return the item from the back
public Item removeLast() {
if (isEmpty()) {
throw new NoSuchElementException();
}
Node temp = last;
last = last.prev;
// 若移除后为空队列需要进行特殊处理
if (last == null) {
first = null;
} else {
last.next = null;
}
size--;
return temp.item;
}
// return an iterator over items in order from front to back
public Iterator<Item> iterator() {
return new DequeIterator();
}
private class Node {
Item item;
Node next;
Node prev; // 双向链表需要记录前一个节点
}
private class DequeIterator implements Iterator<Item> {
private Node start = first;
@Override
public Item next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
Item temp = start.item;
start = start.next;
return temp;
}
@Override
public boolean hasNext() {
return !(start == null);
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
// unit testing (required)
// 需要调用构造器和所有的公开方法
public static void main(String[] args) {
Deque<String> dq = new Deque<>();
dq.addFirst("1");
dq.addLast("2");
dq.addFirst("3");
dq.addLast("4");
System.out.println(dq.size());
dq.removeFirst();
dq.removeLast();
System.out.println(dq.isEmpty());
Iterator<String> it = dq.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
RandomizedQueue.java
注意dequeue()、sample()、next()都是随机返回,并要求队列操作均摊成本为常数,使用数组进行实现。
import edu.princeton.cs.algs4.StdRandom;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class RandomizedQueue<Item> implements Iterable<Item> {
private int n;
private Item[] arr;
// construct an empty randomized queue
public RandomizedQueue() {
arr = (Item[]) new Object[1];
}
// is the randomized queue empty?
public boolean isEmpty() {
return n == 0;
}
// return the number of items on the randomized queue
public int size() {
return n;
}
// add the item
public void enqueue(Item item) {
if (item == null) {
throw new IllegalArgumentException();
}
if (n == arr.length) {
resize(2 * arr.length);
}
arr[n++] = item;
}
// remove and return a random item
public Item dequeue() {
if (isEmpty()) {
throw new NoSuchElementException();
}
// 出队时将随机位置处的元素与末尾元素相调
int random = StdRandom.uniform(n);
Item res = arr[random];
arr[random] = arr[--n];
arr[n] = null;
if (n > 0 && n == arr.length / 4) {
resize(arr.length / 2);
}
return res;
}
// return a random item (but do not remove it)
public Item sample() {
if (isEmpty()) {
throw new NoSuchElementException();
}
int random = StdRandom.uniform(n);
return arr[random];
}
// return an independent iterator over items in random order
public Iterator<Item> iterator() {
return new RQIterator();
}
private class RQIterator implements Iterator<Item> {
private Item[] temp = (Item[]) new Object[n];
private int size = n;
public RQIterator() {
// 复制数组以保证每个iterator的随机顺序相互独立
for (int i = 0; i < n; i++) {
temp[i] = arr[i];
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public boolean hasNext() {
return size > 0;
}
@Override
public Item next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
// 将出队过的元素调换至末尾并缩减size,保证不会被再次随机到
int random = StdRandom.uniform(size);
Item res = temp[random];
temp[random] = temp[--size];
temp[size] = null;
return res;
}
}
private void resize(int size) {
Item[] temp = (Item[]) new Object[size];
for (int i = 0; i < n; i++) {
temp[i] = arr[i];
}
arr = temp;
}
// unit testing (required)
// 需要调用构造器和所有的公开方法
public static void main(String[] args) {
RandomizedQueue<String> rq = new RandomizedQueue<>();
rq.enqueue("1");
rq.enqueue("2");
rq.enqueue("3");
rq.enqueue("4");
System.out.println(rq.size());
System.out.println(rq.sample());
rq.dequeue();
System.out.println(rq.isEmpty());
Iterator<String> it = rq.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
Permutation.java
输入若干个元素,要求随机输出其中的k个元素,使用RandomizedQueue实现。
import edu.princeton.cs.algs4.StdIn;
public class Permutation {
public static void main(String[] args) {
RandomizedQueue<String> rq = new RandomizedQueue<>();
int k = Integer.parseInt(args[0]);
// 实际需要读取的个数n并没有给出
while (!StdIn.isEmpty()) {
rq.enqueue(StdIn.readString());
}
for (int i = 0; i < k; i++) {
System.out.println(rq.dequeue());
}
}
}