一、背包、栈、队列的概念
- 背包(Bag):背包是一种不支持从中删除元素的集合数据类型,它的目的就是帮助收集元素并迭代遍历所有收集到的元素。迭代的顺序不确定且与具体的用例无关。
- 队列(Queue):先进先出队列,简称队列,是一种基于先进先出(FIFO,first in first out)策略的集合类型。它在保存元素的同时也保存了他们的相对顺序。队列时许多日常现象的自然模型,也是无数应用程序的核心。
- 栈(Stack):下压栈,简称栈,是一种基于后进先出(LIFO,last in first out)策略的集合类型。在计算机领域,栈具有基础而深远的影响,在很多领域都用应用,比如我们日常使用浏览器的前进和后退功能就是基于栈来实现的。
二、基于数组实现背包、栈以及队列
- 基于数组的背包:
public class ArrayBag<Item> implements Iterable<Item> {
//背包中元素的数量
private int itemCount=0;
//创建大小为1的原始数组
private Item[] a=(Item[])new Object[1];
//返回背包中元素的数量
public int size(){
return itemCount;
}
//调整背包大小
private void resize(int max){
//创建中转数组,并把数组数据放入中转数组
Item[] temp=(Item[]) new Object[max];
for(int i=0;i<itemCount;i++){
temp[i]=a[i];
}
a=temp;
}
//添加元素到背包,如果背包放满,先调整背包大小
public void add(Item item){
if(itemCount==a.length){
resize(a.length*2);
}
a[itemCount]=item;
itemCount++;
}
@Override
//支持迭代
public Iterator<Item> iterator() {
return new ArrayIterator();
}
private class ArrayIterator implements Iterator<Item>{
private int i=itemCount;
@Override
public boolean hasNext() {
return i>0;
}
@Override
public Item next() {
return a[--i];
}
}
}
- 基于数组的栈:
public class ArrayStack<Item> implements Iterable<Item>{
//背包中元素的数量
private int itemCount=0;
//创建大小为1的原始数组
private Item[] a=(Item[])new Object[1];
//返回背包中元素的数量
public int size(){
return itemCount;
}
//调整背包大小
private void resize(int max){
//创建中转数组,并把数组数据放入中转数组
Item[] temp=(Item[]) new Object[max];
for(int i=0;i<itemCount;i++){
temp[i]=a[i];
}
a=temp;
}
public void push(Item item){
if(itemCount==a.length){
resize(a.length*2);
}
a[itemCount]=item;
itemCount++;
}
public Item pop(){
Item item=a[--itemCount];
if (itemCount>0 && itemCount==a.length/4){
resize(a.length/2);
}
return item;
}
public Iterator<Item> iterator() {
return new ArrayIterator();
}
private class ArrayIterator implements Iterator<Item>{
private int i=itemCount;
@Override
public boolean hasNext() {
return i>0;
}
@Override
public Item next() {
return a[--i];
}
}
}
- 基于数组的队列:数组非常不适用于队列的实现,需要频繁调整数组,严重影响性能。因此这里没有实现。当然,也可能是我本人思路受限,如果读者有更好的实现方法,欢迎反馈。
三、基于链表实现背包、栈以及队列
- 基于链表的背包实现:
public class LinkedListBag<Item> implements Iterable<Item> {
private int N;
//背包入口
private Node first;
//背包的子类,Node节点
class Node{
Item item;
Node next;
}
public boolean isEmpty(){
return N==0;
}
public int size(){
return N;
}
//添加元素
public void add(Item item){
Node oldFirst=first;
first= new Node();
first.item=item;
first.next=oldFirst;
N++;
}
//迭代支持
public Iterator<Item> iterator() {
return new BagIterator();
}
private class BagIterator implements Iterator<Item>{
private Node current=first;
@Override
public boolean hasNext() {
return current!=null;
}
@Override
public Item next() {
Item item=current.item;
current=current.next;
return item;
}
}
}
- 基于链表的栈实现:
-
public class LinkedListStack<Item> implements Iterable<Item> { private int N; private Node first; @Override public Iterator<Item> iterator() { return new StackIterator(); } private class StackIterator implements Iterator<Item>{ private Node temp=first; @Override public boolean hasNext() { return temp!=null; } @Override public Item next() { Item result=temp.item; temp=temp.next; return result; } } private class Node{ Item item; Node next; } //返回队列元素数量 public int size(){ return N; } //判断队列是否为空 public boolean isEmpty(){ return N==0; } //入栈 public void push(Item item){ Node oldfirst=first; first=new Node(); first.item=item; first.next=oldfirst; N++; } //出栈 public Item pop(){ Item item=first.item; first=first.next; N--; return item; } }
- 基于链表的队列实现:
public class LinkedListQueue<Item> implements Iterable<Item> {
//队列元素数量
private int N;
//队列的头
Node first;
//队列的尾
Node last;
@Override
//支持迭代
public Iterator<Item> iterator() {
return new QueueIterator();
}
private class QueueIterator implements Iterator<Item>{
Node temp=first;
@Override
public boolean hasNext() {
return temp!=null;
}
@Override
public Item next() {
Item result=temp.item;
temp=temp.next;
return result;
}
}
private class Node{
Item item;
Node next;
}
//返回队列元素数量
public int size(){
return N;
}
//判断队列是否为空
public boolean isEmpty(){
return N==0;
}
//元素入列
public void enQueue(Item item){
Node oldlast=last;
last=new Node();
last.item=item;
if(isEmpty()){
first=last;
}else{
oldlast.next=last;
}
N++;
}
//元素出列
public Item deQueue(){
Item temp=first.item;
if(N==1) {
first=last=null;
}else{
first=first.next;
}
N--;
return temp;
}
}
四、延伸
在实际问题中,解决不同问题的策略可能相同,但具体的要求却可能不同。比如,我们需要队列能够“插队”以应对特殊情况,在比如,我们需要栈能够快速返回栈底的元素等等。于是,这就要求对这些结构能够灵活得实现,从而适应我们的实际问题。
因此,学习这些抽象数据类型(ADT:abstract data type)一定要理解而不是机械地去记忆。理解它背后所表达出的策略,以及这些策略在不同场合的应用。代码一定要能自己写出来而不是背出来。只有自己写出来,才能真正理解它的含义。