您的位置:首页 > 产品设计 > UI/UE

Coursera Algorithms Programming Assignment 2: Deque and Randomized Queue

2017-07-19 11:38 387 查看
这次作业与第一周作业相比,稍微简单一些。有三个编程练习:双端队列(Deque)设计、随机队列(Randomized Queue)设计,还有一个排列组合类Permutation。

一、双端队列Deque

设计要求:A double-ended queue or deque (pronounced "deck") is a generalization of a stack and a queue that supports adding and removing items from either the front or the
back of the data structure.

异常处理要求:Throw a java.lang.IllegalArgumentException if the client attempts to add a null item; throw a java.util.NoSuchElementException if the client attempts to remove an item from an empty deque; throw a java.lang.UnsupportedOperationException if the client
calls the remove() method in the iterator; throw a java.util.NoSuchElementException if the client calls the next() method in the iterator and there are no more items to return.

性能要求:Your deque implementation must support each deque operation (including construction) in constant worst-case time. A deque containing n items must use at most 48n +
192 bytes of memory and use space proportional to the number of items currently in the deque. Additionally, your iterator implementation must support each operation (including construction) in constant
worst-case time.

分析:

要求可以同时从头尾移除元素,那么该队列内部采用链表更合适,代码如下

import java.util.Iterator;
import java.util.NoSuchElementException;

public class Deque implements Iterable {
private Node first; // 8 bytes
private Node last; // 8 bytes
private int size; // 4 bytes

private class Node { // 16字节对象开销+8字节内部类额外开销+8+8+8=48 bytes, n个节点就是48n bytes
private Node preNode; // 前一个节点的引用
private Item item;
private Node nextNode; // 后一个节点的引用
}

private class ListIterator implements Iterator {
// 16字节对象开销+8字节内部类额外开销+8=32 bytes
private Node curr = first;

@Override
public boolean hasNext() {
// TODO Auto-generated method stub
return curr != null;
}

@Override
public Item next() {
// TODO Auto-generated method stub
if (curr == null)
throw new NoSuchElementException("there are no more items!");
Item item = curr.item;
curr = curr.nextNode;
return item;
}
//remove不用设计,父类Iterator的remove方法就抛出UnsupportedOperationException("remove");
}

public Deque() {
// construct an empty deque
size = 0;
first = null;
last = null;
}

public boolean isEmpty() {
// is the deque empty?
return (size == 0);
}

public int size() {
// return the number of items on the deque
return size;
}

public void addFirst(Item item) {
// add the item to the front
valivate(item);
Node newNode = new Node();
newNode.item = item;
if (size == 0) { // 空队列的情况
newNode.preNode = null;
newNode.nextNode = null;
first = newNode;
last = newNode;
} else {
newNode.preNode = null;
newNode.nextNode = first;
first.preNode = newNode;
first = newNode;
}
size++;
}

public void addLast(Item item) {
// add the item to the end
valivate(item);
Node newNode = new Node();
newNode.item = item;
if (size == 0) { // 空队列的情况
newNode.preNode = null;
newNode.nextNode = null;
first = newNode;
last = newNode;
} else {
last.nextNode = newNode;
newNode.preNode = last;
newNode.nextNode = null;
last = newNode;
}
size++;
}

public Item removeFirst() {
// remove and return the item from the front
if (size == 0)
throw new NoSuchElementException("the deque is empty!");
Item returnItem = null;
if (size == 1) {
returnItem = first.item;
first = null;
last = null;
} else {
Node oldfirst = first;
returnItem = oldfirst.item;
first = oldfirst.nextNode;
first.preNode = null;
oldfirst.nextNode = null;
oldfirst.item = null;
}
size--;
return returnItem;
}

public Item removeLast() {
// remove and return the item from the end
if (size == 0)
throw new NoSuchElementException("the deque is empty!");
Item returnItem = null;
if (size == 1) {
returnItem = first.item;
first = null;
last = null;
} else {
Node oldlast = last;
returnItem = oldlast.item;
last = oldlast.preNode;
last.nextNode = null;
oldlast.preNode = null;
oldlast.item = null;
}
size--;
return returnItem;
}

public Iterator iterator() {
// return an iterator over items in order from front to end
return new ListIterator();
}

private void valivate(Item item) {
if (item == null)
throw new IllegalArgumentException("the item is null!");
}

public static void main(String[] args) {
// unit testing (optional)
Deque queue = new Deque();
System.out.println(queue.size);
queue.addFirst("a");
queue.addFirst("b");
queue.addLast("c");
queue.addFirst("d");
queue.addLast("e");
System.out.println(queue.size);
Iterator iter = queue.iterator();
while (iter.hasNext()) {
System.out.println(iter.next());
}
}
}


二、随机队列Randomized Queue

设计要求:A randomized queue is similar to a s
4000
tack or queue, except that the item removed is chosen uniformly at random from items in the data structure.

异常处理:The order of two or more iterators to the same randomized queue must be mutually independent; each iterator must maintain its own random order. Throw a java.lang.IllegalArgumentException if the client attempts
to add a null item; throw a java.util.NoSuchElementException if the client attempts to sample or dequeue an item from an empty randomized queue; throw a java.lang.UnsupportedOperationException if the client calls the remove() method in the iterator; throw
a java.util.NoSuchElementException if the client calls the next() method in the iterator and there are no more items to return.

性能要求: Your randomized queue implementation must support each randomized queue operation (besides creating an iterator) in constant amortized time. That is, any sequence of m randomized
queue operations (starting from an empty queue) should take at most cm steps in the worst case, for some constant c. A randomized queue containing n items
must use at most 48n + 192 bytes of memory. Additionally, your iterator implementation must support operations next() and hasNext() in constant worst-case time; and construction
in linear time; you may (and will need to) use a linear amount of extra memory per iterator.

分析:

该队列每次移除的元素是随机的,性能要求提到迭代器的next方法必须是常数时间,很容易发现链表不容易满足该需求,需要用数组,代码如下:
import java.util.Iterator;
import java.util.NoSuchElementException;
import edu.princeton.cs.algs4.StdRandom;

public class RandomizedQueue implements Iterable {
private Item[] rqArrays;
private int size;

private class RandomIterator implements Iterator {
private int rank; // rank 记录便利的次数
private Item[] iterArrays; //两个迭代器必须相互独立,并且拥有自己的随机顺序

public RandomIterator(){
rank = size;
iterArrays = (Item[]) new Object[rank];
for(int i = 0; i 0);
}
@Override
public Item next() {
// TODO Auto-generated method stub
if (rank == 0)
throw new NoSuchElementException("there are no more items!");
int r = StdRandom.uniform(0, rank); // 随机选取一个位置的元素返回
rank--;
Item item = iterArrays[r];
iterArrays[r] = iterArrays[rank];
iterArrays[rank] = item; // 将已经遍历过的元素放置队列末尾,这样下次迭代就不会被选到
return item;
}
}

public RandomizedQueue() {
// construct an empty randomized queue
rqArrays = (Item[]) new Object[1];
size = 0;
}

private void valivate(Item item) {
if (item == null)
throw new IllegalArgumentException("the item is null!");
}

public boolean isEmpty() {
// is the queue empty?
return (size == 0);
}

public int size() {
// return the number of items on the queue
return size;
}

private void resize(int cap) {
Item[] temp = (Item[]) new Object[cap];
for (int i = 0; i < size; i++)
temp[i] = rqArrays[i];
rqArrays = temp;
}

public void enqueue(Item item) {
// add the item
valivate(item);
rqArrays[size++] = item;
if (size == rqArrays.length)
resize(2 * rqArrays.length);
}

public Item dequeue() {
// remove and return a random item
// 随机选取一个位置,将这个位置的元素与队列末尾的元素交换位置
// dequeue末尾元素时就达到随机remove元素的目的
if (size == 0)
throw new NoSuchElementException("the RandomizeQueue is empty!");
int r = StdRandom.uniform(0, size);
size--;
Item delItem = rqArrays[r];
rqArrays[r] = rqArrays[size];
rqArrays[size] = null;
if (size > 0 && size == rqArrays.length / 4)
resize(rqArrays.length / 2);
return delItem;
}

public Item sample() {
// return (but do not remove) a random item
if (size == 0)
throw new NoSuchElementException("the RandomizeQueue is empty!");
return rqArrays[StdRandom.uniform(0, size)];
}

public Iterator iterator() {
// return an independent iterator over items in random order
return new RandomIterator();
}

public static void main(String[] args) {
// unit testing (optional)
RandomizedQueue rq = new RandomizedQueue();
rq.enqueue("a");
rq.enqueue("b");
rq.enqueue("c");
rq.enqueue("d");
rq.enqueue("e");
rq.enqueue("f");
rq.enqueue("g");
rq.dequeue();
Iterator iter1 = rq.iterator();
Iterator iter2 = rq.iterator();
while (iter1.hasNext()) {
System.out.print(iter1.next() + ",");
}
System.out.println();
while (iter2.hasNext()) {
System.out.print(iter2.next() + ",");
}
System.out.println();

}
}


三、 排列组合类Permutation

设计要求:Write a client program Permutation.java that takes a command-line integer k; reads in a sequence of strings from standard input using StdIn.readString(); and prints exactly k of
them, uniformly at random. Print each item from the sequence at most once.

性能要求:The running time of Permutation must be linear in the size of the input. You may use only a constant amount of memory plus either one Deque or RandomizedQueue object of maximum size at most n. (For an extra
challenge, use only one Deque or RandomizedQueue object of maximum size at most k.)

输出示例:



import edu.princeton.cs.algs4.StdIn;

public class Permutation {
public static void main(String[] args) {
RandomizedQueue rq = new RandomizedQueue();
int k = Integer.parseInt(args[0]);
while (!StdIn.isEmpty()) {
rq.enqueue(StdIn.readString());
// System.out.println(StdIn.readString());
}
while (k > 0) {
System.out.println(rq.dequeue());
k--;
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息