先从栈开始实现,从简单开始,栈的特点是先进后出LIFO,应该具有的操作有:入栈push 出栈pop,判断栈是否为空isEmpty和返回栈大小size,使用java中最简单的数组实现字符串栈为开始:
public class FixCapacityStringStack{
private
String[] str = null;
private int
n = 0;
public
FixCapacityStringStack(int m){
str = new
String[m];
}
public
boolean isEmpty(){
return n ==
0;
}
public int
size(){
return
n;
}
public void
push(String s){
str[n++] =
s;
}
public
String pop(){
return
str[--n];
}
}
这样的字符串栈仅能简单体现栈的基本功能,不可避免的有很多缺陷,首先由于固定类型只能存储字符串对象,其他对象无法复用,应该定义一个所有对象都能通用的通用栈,可以用java的泛型实现:
public class FixCapacityStack
{
private
Item[] stack = null;
private int
N = 0;
public
FixCapacityStack(int m){
stack =
(Item[]) new Object[m];
//stack =
new Item[m];//waring:Cannot create a generic array of
Item
}
public
boolean isEmpty(){
return N ==
0;
}
public int
size(){
return
N;
}
public void
push(Item item){
stack[N++] =
item;
}
public Item
pop(){
return
stack[--N];//此处对象游离
}
}
数组实现的泛型定容栈虽然解决了对象通用问题,但很多细节的实现仍然很粗糙,比如数组的大小固定,创建后就无法改变,出栈操作对象游离,虽然对象已出栈,但仍然在数组中,应该不保留出栈对象句柄,让此对象等待垃圾回收等等。
于是我们需要用数组实现一个对所有对象通用,并且能够动态调整数组大小,实现无上界的栈,同时对出栈对象及时消除句柄的栈,另外,作为集合对象类型,这样的栈应该支持迭代遍历栈中所有数据元素。
关于调整数组大小,可以采用这样的方式:
如果入栈后判断数组已满,则创建一个新数组,此数组长度为原数组的两倍,将原数组复制到新数组。
如果出栈后判断栈的长度小于数组长度的四分之一,则将创建新数组为原数组长度的一半,复制原数组到新数组。
如此以数组为原型的栈不会溢出,同时,栈的使用率永远不会低于四分之一,不会造成空间浪费。
如果要迭代遍历集合元素,类似其他集合类实现Iterable接口,实现iterator方法返回迭代器对象,迭代器对象应是一个实现hasNext,next,remove方法,操作栈对象。可以实现为内部类。
import java.util.Iterator;
public class ReizeArrayStack
implements Iterable{
private
Item[] stack = null;
private int
N = 0;
public
ReizeArrayStack(){
stack =
(Item[])new Object[1];
}
public
boolean isEmpty(){
return N ==
0;
}
public int
size(){
return
N;
}
public void
push(Item item){
if(N ==
stack.length){
resize(2*stack.length);
}
stack[N++] =
item;
}
public Item
pop(){
Item temp
= stack[--N];
stack[N] =
null;//出栈对象及时清除,无引用对象等待回收。
if(N ==
stack.length/4){
resize(stack.length/2);
}
return
temp;
}
public void
resize(int max){//重新调整数组大小
Item[] temp
= (Item[])new Object[max];
for(int i
=0;i
temp[i] =
stack[i];
}
stack =
temp;
}
@Override
public
Iterator iterator() {
// TODO
Auto-generated method stub
return new
ReizeArrayStackIterator();
}
private
class ReizeArrayStackIterator implements
Iterator{
private int
i = N;
@Override
public
boolean hasNext() {
// TODO
Auto-generated method stub
return i
> 0;
}
@Override
public Item
next() {
// TODO
Auto-generated method stub
return
stack[--i];
}
@Override
public void
remove() {
// TODO
Auto-generated method stub
}
}
}
如果使用链表实现栈,可以方便的多,链表实现栈达到了最优的设计目的:
可以处理任何数据类型;
所需空间和集合大小成正比;
操作所需的时间和集合的大小无关;(因为总是表头插入删除)
import java.util.Iterator;
public class ListStack
implements Iterable {
public Node
first;
public int N
= 0;
private
class Node{
public Item
item;
public Node
next;
}
public
boolean isEmpty(){
return N ==
0;
}
public int
size(){
return N
;
}
public void
push(Item item){
Node
oldfirst = first;
first = new
Node();
first.item =
item;
first.next =
oldfirst;
N ++ ;
}
public Item
pop(){
Item temp =
first.item;
first =
first.next;
N--;
return
temp;
}
@Override
public
Iterator iterator() {
// TODO
Auto-generated method stub
return
null;
}
private
class ListStackIterator implements
Iterator{
private Node
current = first;
@Override
public
boolean hasNext() {
// TODO
Auto-generated method stub
return
current != null;
}
@Override
public Item
next() {
// TODO
Auto-generated method stub
Item temp =
current.item;
current =
current.next;
return
temp;
}
public void
remove()
{}
}
}
队列的链表实现也如此类似(FIFO):
public class ListQueue {
private Node
first = null;
private Node
last = first;
private int
N = 0 ;
private
class Node{
public Item
item;
public Node
next;
}
public
boolean isEmpty(){
return first
== last;
}
public int
size(){
return
N;
}
public void
enqueue(Item item){
last = new
Node();
last.item =
item;
last.next =
null;
last =
last.next;
N++;
}
public Item
dequeue() {
if
(!isEmpty()) {
Item temp =
first.item;
first =
first.next;
N--;
return
temp;
}
else return
null;
}
}
背包是一种不支持从中删除元素的集合数据类型,目的是帮助用例收集数据元素,并迭代遍历所有收集到的元素,迭代顺序不确定。用例可以检查背包是否为空或者获取背包中元素的数量。
import java.util.Iterator;
public class ListBag
implements Iterable{
private Node
first;
private
class Node{
Item
item;
Node
next;
}
public void
add(Item item){
Node
oldfirst = first;
first = new
Node();
first.item =
item;
first.next =
oldfirst;
}
@Override
public
Iterator iterator() {
// TODO
Auto-generated method stub
return new
ListBagIterator();
}
private
class ListBagIterator implements
Iterator{
private Node
current = first;
@Override
public
boolean hasNext() {
// TODO
Auto-generated method stub
return
current == null;
}
@Override
public Item
next() {
// TODO
Auto-generated method stub
Item temp =
current.item;
current =
current.next;
return
temp;
}
@Override
public void
remove() {}
}
}