stack:last in first out (LIFO)
queue: first in fist out (FIFO)
stack API
- linked-list stack implementation
public class LinkedStackofStrings{
private Node first = null;
private class Node(){
String item;
Node next;
}
//insert a new string into stack
public void push(String item){
//在鏈表的頭結點入棧
Node oldfirst = first;
first = new Node();
first.item = item;
first.next = oldfirst;
}
//remove and return the string most recently added
public String pop(){
String item = first.item;
first = first.next;
return item;
}
//is the stack empty?
public boolean isEmpty(){
return first==null;
}
}
- array stack implementation
s[N]為棧頂,為空
public class FixedCapacityStackofStrings{
private String[] s;
private int N = 0;
//固定大小的棧
public FixedCapacityStackofStrings(int capacity){
s = new String[capacity];
}
//insert a new string into stack
public void push(String item){
s[N++] =item;
}
//remove and return the string most recently added
public String pop(){
return s[--N];
}
//is the stack empty?
public boolean isEmpty(){
return N == 0;
}
}
問題:
1.underflow:從空棧pop時
2.overflow:向已滿的棧push時;解決方法為resize數組大小
3.空item:解決方法為允許null入棧
4.loitering(內存泄漏?):當pop時,依然有指向object的指針;更改為:
public String pop(){
String item = s[--N];
s[N] == null;
return item;
}
resizing array
但是上述數組的實現需要用戶提供棧的固定容量,但一般沒有人能確定棧的最大容量,因此最好能隨時增大數組。
- first try
push:array size加一;
pop:array size減一;
too expensive,每次改變數組大小時都要把所有項復制到新數組中,因此插入N項的時間復雜度為1+2+3+4+……+N,約為N的平方。
因此最好保證resize array不那么頻繁。
- 改進
如果數組滿了,則將數組的大小變為原來的二倍。
public ResizingArrayStackofStrings{
private s = new String[1];
public void push(String item){
if(N==s.length) resize(2*s.length);
s[N++] = item;
}
public void resize(int capacity){
String[] copy = new Stirng[2*capacity];
for(int i = 0;i<s.length;i++){
copy[i] = s[i];
}
s = copy;
}
}
此時插入N項所需的時間復雜度為2+4+8+……+N,即每次復制的item個數為2的k次方,則1+2+4+8+……+2的k次方為2的k+1次方,即2N(N為2的k次方),因此時間復雜度為N,相比每插入一項就增大數組size的N平方有了很大改進。
那縮小數組呢?
- first try
當數組內容變為原來的一半時將數組縮小至原來的一半。
但當數組滿的時候,push會加倍數組的長度,pop又會減半數組的長度,就這么交替地push、pop、push、pop,每次操作時間復雜度都為N
- efficient solution
當數組1/4滿時,將數組長度減半.
public String pop(){
String item = s[--N];
s[N] = null;
if(N>0 && N == s.length/4) resize(s.length/2);
return item;
}
這樣array的長度是在25%到100%之間。
因此,resizing arrays的push和pop時間復雜度都為O(N)。
Queue API
- linked-list implementation
public class LinkedListQueueofStrings{
private class Node{
String item;
Node next;
}
public void enqueue(String item){
Node oldlast = last;
Node last = new Node();
last.item = item;
last.next = null;
if(isEmpty()) first = last;
else oldlast.next = last;
}
public String dequeue(){
String item = first.item;
first = first.next;
if(isEmpty()) last = null;
}
public boolean isEmpty(){
return first == null;
}
}
- resizing arrays