http://1.tanqian.sinaapp.com/
1、内容
Lecture: Stacks and Queues. We consider two fundamental data types for storing collections of objects: the
stack and the
queue. We implement each using either a singly-linked list or a resizing array. We introduce two advanced Java features—generics and iterators—that simplify client code. Finally, we consider various applications of stacks and queues ranging from parsing arithmetic expressions to simulating queueing systems.
Lecture: Elementary Sorts. We introduce the sorting problem and Java’s Comparable interface. We study two elementary sorting methods (
selection sort and
insertion sort) and a variation of one of them (
shellsort). We also consider two algorithms for uniformly
shufflingan array. We conclude with an application of sorting to computing the convex hull via the
Graham scan algorithm.
Programming Assignment: Deques and Randomized Queues. Your programming assignment will involve developing implementations of two conceptually simple “collection” data types—the
deque and the
randomized queue—which are quite useful in practice. Properly implementing these data types will require using a linked data structure for one and a resizing array for the other.
Suggested readings. Section 1.3 and 2.1 in
Algorithms, 4th edition.
2、知识点
1)主要内容包括bag, queue和stack。都是collections。还介绍了generics和iteration:泛型和迭代器,链表linked list。
泛型:参数化类型,对于collection特别有用。编译时进行类型检查,比使用object更为安全。注:泛型必须是引用类型,所以定义时不可以使用基本类型,但是在使用时,由于java的autoboxing机制,可以直接用基本类型赋值。如Stack<Integer> stack = new Stack<Integer>(); stack.push(1); int i = stack.pop();
Iteration是遍历集合元素更为简洁,只需要实现Iterable接口。
Queue<Transaction> q = new Queue<Transaction> ();
for (Transaction t : q) {StdOut.println(t)}
2)bag:只进不出,不能remove,且item之间的顺序无关紧要。主要进行遍历工作和统计工作,如品均值和方差。
FIFO queue:先进先出队列。当item之间的顺序有关系时需要用,典型的例子是,如果一个人在餐馆点餐,那么,等待越久的(first in),就应该最早得到服务(first out)。
Pushdown stacks:可以用来reverse逆序。还可以用来计算算数表达式的值。
计算表达式的值需要使用两个stack,一个房operand,一个放operator。前提是每一个表达式都用括号括起来。算法:忽略左括号,push operand到stack1,push operator到stack2.如果遇到右括号,pop两个operand和一个operator,进行运算,将其运算结果push到stack1.如此依此进行,直到遇见最后一个右括号,再次进行运算后。stack1中的值即为最终的结果。
3)实现
可以使用固定数值,简单但是不使用。一般使用resizing数组,在push时检查如果N == a.length,则扩大一倍数组,当pop时,如果N == a.length / 4, 则缩小数组到a.length / 2.
同时,一定要注意在pop时,一定要将a[N] = null.放在loitering:字面意思是滞留街头,即该引用对象不会再使用,但是无法回收,最终造成内存泄露。
4)协变数组和类型擦除 covariant array and type erasure
协变性:如果Base是Sub的基类,则Base[]也是Sub[]的基类。
java数组是协变的。但是泛型不是。即List<Base> 不是List<Sub>的基类,更不是其子类。所以不可以用多态。
Object[] array = new String[10];
array[0] = 10;
可以编译通过,因为数组是协变的,但是运行时会出错。
而
List< Object> list = new ArrayList< String>();
list.add(10);
编译时就无法通过。
5)Selection Sort
comparisions: ~N^2 / 2 ; exchange : N
feature:
Running time is insensitive to input:对输入不敏感,无论正序和倒序都一样
Data movement is minimal : linear
int min;
for(int i = 0; i < N; i++) {
min = i;
for(int j = i + 1; j < N; j++){
if (a[j] < a[min] ) { min = j;}
}
exch(i, min);
}
6) Insertion Sort
Best case : comparisions: N – 1; exchanges: 0
Worst case: comparisions: N^2 / 2, exchanges: N^2 / 2;
Average: comparisions: N^2 / 4, exchanges: N^2 / 4;
feature: 输入敏感,对哪些sorted或者nearly sorted的数组尤其有效
for (int i = 1; i < N; i++) {
for(int j = i; j > 0; j–) {
if (a[j] < a[j-1]) {exch(j, j-1)}
}
}
改进版:减少交换次数
for (int i = 1; i < N; i++) {
int tmp = a[i];
for(int j = i – 1; j >=0; j–) {
if (tmp < a[j]) {a[j+1] = a[j]}
else {a[j+1] = tmp;}
}
}
7)shell sort
间隔需要满足数列:3*h + 1,即1, 4, 13, 40……
int h = 1;
while(h < N /3 ) {h = h* 3 + 1}
while(h >= 1) {
for (int i = h; i < N; i++) {
for (int j = i; j >= h; j-=h) {
if (a[j] < a[j-h]) {exch(j, j-h)}
}
}
h = h / 3;
}
Programming Assignment 2: Randomized Queues and Deque
需要实现一个双端队列,Deque和一个随机队列。其中双端队列的要求如下:
Dequeue. A
double-ended queue or
deque (pronounced “deck”) is a generalization of a stack and a queue that supports inserting and removing items from either the front or the back of the data structure. Create a generic data type Deque that implements the following API:
public class Deque<Item> implements Iterable<Item> {
public Deque() // construct an empty deque
public boolean isEmpty() // is the deque empty?
public int size() // return the number of items on the deque
public void addFirst(Item item) // insert the item at the front
public void addLast(Item item) // insert the item at the end
public Item removeFirst() // delete and return the item at the front
public Item removeLast() // delete and return the item at the end
public Iterator<Item> iterator() // return an iterator over items in order from front to end
public static void main(String[] args) // unit testing
}
除了实现上述API外还需注意题目的要求:
1) support each deque operation in
constant worst-case time
在常数时间内完成每一步操作:用链表可以实现,但是数组由于涉及到resize,并非严格的常数,所以还是用链表。
2)use space proportional to the number of items
currently in the deque
并非完全成正比,所以resizing数组和链表都行。唯一的区别是数组稍微浪费点空间。
3) Additionally, your iterator implementation must support the operations next() and hasNext() (plus construction) in constant worst-case time and use a constant amount of extra space per iterator
Randomized queue. A
randomized queue is similar to a stack or queue, except that the item removed is chosen uniformly at random from items in the data structure. Create a generic data type RandomizedQueue that implements the following API:
public class RandomizedQueue<Item> implements Iterable<Item> {
public RandomizedQueue() // construct an empty randomized queue
public boolean isEmpty() // is the queue empty?
public int size() // return the number of items on the queue
public void enqueue(Item item) // add the item
public Item dequeue() // delete and return a random item
public Item sample() // return (but do not delete) a random item
public Iterator<Item> iterator() // return an independent iterator over items in random order
public static void main(String[] args) // unit testing
}
要求:
1)support each randomized queue operation (besides creating an iterator) in
constant amortized time
数组取数据可以做到常数时间,而队列去随机数据则需要遍历,所以选数组,特别的
constant amortized time指的是分摊的时间时常数,这些时间主要用在了resize数组上。
思路:
1)双端队列用链表实现,由于需要删除最后一个节点,必须使用双向链表。由于使用的链表,无需考虑loitering
2)随机队列使用可变数组实现,总的思路是从数组末尾插入,随机取出时,需要将选中的item和末尾item进行交换。可以应用在抽奖应用中。另外需要主要loitering,取出时,需要将该地址置为null。
3)随机取出程序:
实现:
public class Deque< Item>
implements Iterable< Item> {
private int mSize ;
private Node mFirst ;
private Node mLast ;
private class Node {
Item item;
Node next ;
Node prev ;
}
public Deque () { // construct an empty
deque
mFirst =
null ;
mLast =
null ;
mSize = 0;
}
public boolean isEmpty () { // is the
deque empty?
return mSize == 0;
}
public int size () { // return the number of items on the
deque
return mSize ;
}
public void addFirst (Item item ) { // insert the item at the front
if ( item ==
null ) {
throw new NullPointerException ();
}
Node oldFirst = mFirst ;
mFirst =
new Node() ;
mSize++;
mFirst. item = item;
mFirst. next = oldFirst ;
if (oldFirst !=
null ) {
oldFirst .prev = mFirst ;
}
if ( mLast ==
null ) {
mLast = mFirst;
}
}
public void addLast (Item item ) { // insert the item at the end
if ( item ==
null ) {
throw new NullPointerException ();
}
Node oldLast = mLast ;
mLast =
new Node() ;
mSize++;
mLast. item = item;
mLast. prev = oldLast ;
if (oldLast !=
null ) {
oldLast .next = mLast ;
}
if ( mFirst ==
null ) {
mFirst = mLast;
}
}
public Item removeFirst () { // delete and return the item at the front
if ( isEmpty()) {
throw new NoSuchElementException ();
}
Item item = mFirst. item;
if ( mFirst. next !=
null ) {
mFirst. next. prev =
null ; // avoid loitering
}
mFirst = mFirst. next;
mSize–;
// only one item, then set
mlast to null
if ( isEmpty()) {
mLast =
null ;
}
return item;
}
public Item removeLast () { // delete and return the item at the end
if ( isEmpty()) {
throw new NoSuchElementException ();
}
Item item = mLast. item;
mLast = mLast. prev;
if ( mLast !=
null ) {
mLast. next =
null ; // avoid loitering
}
mSize–;
if ( isEmpty()) {
mFirst =
null ;
}
return item;
}
public Iterator <Item > iterator() { // return an iterator over items in order
// from front to end
return new DequeIterator ();
}
private class DequeIterator implements Iterator <Item > {
private Node current = mFirst ;
@Override
public boolean hasNext () {
//
TODO Auto-generated method stub
return current !=
null;
}
@Override
public Item next () {
//
TODO Auto-generated method stub
if ( current ==
null || current .item ==
null) {
throw new NoSuchElementException ();
}
Item item = current. item;
current = current. next;
return item;
}
@Override
public void remove () {
//
TODO Auto-generated method stub
throw new UnsupportedOperationException ();
}
}
public static void main(
String [] args ) { // unit testing
}
}
public class RandomizedQueue< Item>
implements Iterable< Item> {
private int N = 0;
private Item [] a ;
public RandomizedQueue () { // construct an empty randomized queue
a =
(
Item
[])
new
Object
[
1
];
}
public boolean isEmpty () { // is the queue empty?
return N == 0;
}
public int size () { // return the number of items on the queue
return N ;
}
private void resize (
int max) {
Item[] tmp =
(
Item
[])
new
Object
[
max
];
for (
int i = 0; i < N; i++ ) {
tmp[i] = a[i] ;
}
a = tmp ;
}
public void enqueue (Item item ) { // add the item
if ( item ==
null ) {
throw new NullPointerException ();
}
if ( N == a. length) {
resize( 2 * N) ;
}
a[ N++ ] = item ;
}
public Item dequeue () { // delete and return a random item
if ( isEmpty()) {
throw new NoSuchElementException ();
}
// make sure the a[N-1] be the uniformly random item.
int j =
StdRandom .
uniform (N );
Item tmp = a[j] ;
a[j] = a[ N-1 ];
a[ N-1 ] = tmp;
tmp = a[ --N ];
a[ N] =
null ; // avoid loitering
if ( N > 0 && N == a. length / 4) {
resize( N) ;
}
return tmp;
}
public Item sample () { // return (but do not delete) a random item
if ( isEmpty()) {
throw new NoSuchElementException ();
}
// make sure the a[N-1] be the uniformly random item.
int j =
StdRandom .
uniform (N );
return a [j];
}
private class RandomizedQueueIterator implements Iterator <Item > {
int n = N;
Item[] ai;
int
r;
public RandomizedQueueIterator () {
ai =
(
Item
[])
new
Object
[
N
];
for (
int i = 0; i < N; i++ ) {
ai[i] = a[i] ;
}
StdRandom .
shuffle (ai );
}
@Override
public boolean hasNext () {
//
TODO Auto-generated method stub
return n > 0;
}
@Override
public Item next () {
//
TODO Auto-generated method stub
if ( n == 0) {
throw new NoSuchElementException ();
}
return ai [-- n] ;
}
@Override
public void remove () {
//
TODO Auto-generated method stub
throw new UnsupportedOperationException ();
}
}
public Iterator <Item > iterator() { // return an independent iterator over
// items in random order
return new RandomizedQueueIterator ();
}
public static void main(
String [] args ) { // unit testing
}
}
public class Subset {
public static void main(
String [] args ) {
int k =
Integer .
parseInt (args [0 ]);
RandomizedQueue <String > rq =
new RandomizedQueue <String >() ;
String str;
while (!
StdIn.
isEmpty ()) {
str =
StdIn .
readString ();
rq. enqueue(str) ;
}
for (
int i = 0; i < k ; i ++) {
StdOut .
println (rq. dequeue()) ;
}
}
}