栈
栈是一种基于后进先出(LIFO)策略的数据结构。无论是在现实生活中,还是计算机中都大量运用了栈这个数据结构。例如:在浏览网页时,点击超链接会访问一个新的页面(压入栈中),你可以不断的点击新的超链接来访问新的页面。但是你总是可以点击回退按钮去访问以前访问的页面(从栈中弹出)。即程序添加元素的顺序和程序使用foreach遍历栈的顺序相反。栈有两种实现方法,一种是数组实现,一种是链表实现。下面我会一一详细介绍。
动态数组实现栈
使用数组来表示栈,即意味程序必须实现预估计数组的大小。在java中,数组一旦创建,其大小是无法改变的。所以必须动态的改变数组的大小。实现方法:将数组元素复制到另一个长度数组中。即在元素的数量等于数组的长度时,将长度为N数组中元素复制到另一个长度为2N的数组中。在数组过大,即大于元素的4倍时,将数组长度减少一半,方法同上。这时肯定有人会有疑问为什么不在元素是数组长度的一半时将数组长度减半?这是防止程序频繁的删除元素和添加元素,导致的数组频繁创建而使栈的性能变差。
public class ResizingArrayStack<Item> implements Iterable<Item> {
//元素的个数
private int N;
private Item[] items=(Item[])new Object[1];//java不允许创建泛型数组
//判断数组是否为空
public boolean isEmpty(){
return N==0;
}
//获得栈中元素的个数
public int size(){
return N;
}
//动态的调整数组大小
private void resize(int n){
Item[] array=(Item[])new Object[n];
for(int x=0;x<items.length;x++){
array[x]=items[x];
}
items=array;
}
public void push(Item item){//将元素压入栈
if(N>=items.length) resize(2*N);
items[N++]=item;
}
public Item pop(){//将元素弹出栈
Item val=items[--N];
items[N]=null;//避免元素游离
if(N>0 && N<=items.length/4) resize(N/2);
return val;
}
public Iterator<Item> iterator(){
return new ReverseArrayIterator();
}
private class ReverseArrayIterator implements Iterator<Item>{
private int i=N;
public boolean hasNext() {
return i>0;
}
public Item next() {
return items[--i];
}
public void remove() {
}
}
}
链表实现栈
链表也是一种计算机中常见的数据结构。它或者为空,或者指向一个结点的引用。该结点含有一个泛型元素和一个指向另一个链表的引用。在本例中,我使用一个内部类来表示一个结点。
public class Stack<Item> implements Iterable<Item>{
//内部类,用来表示链表中的每个节点
private class Node{
Item item;//每个节点的值
Node next;//每个节点指向下一个节点的引用
}
//头节点
private Node first;
//元素个数
private int N;
public boolean isEmpty(){
return first==null;
}
public int size(){
return N;
}
public void push(Item data){
if(first==null){
first=new Node();
first.item=data;
first.next=null;
}else{
Node oldFirst=first;
first=new Node();
first.item=data;
first.next=oldFirst;
}
N++;
}
public Item pop(){
if(!isEmpty()){
Item item=first.item;
first=first.next;
N--;
return item;
}
return null;
}
@Override
public Iterator<Item> iterator() {
return new ListIterator();
}
private class ListIterator 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 ;
}
@Override
public void remove(){
}
}
}
队列
先进先出队列是一种基于先进先出(FIFO)策略的数据结构。这种数据结构在现实生活中也很常见。即在食堂排队买饭,在公交车站排队上车等等。在程序使用foreach语句迭代时,元素添加的顺序和遍历的顺序是一样的。下面我将会使用链表来实现队列。
public class Queue<Item> implements Iterable<Item>{
private class Node{
Item item;
Node next;
}
private Node first;
private Node last;
private int N;
public boolean isEmpty(){
return first==null;
}
public int size(){
return N;
}
public void enqueue(Item data){
Node oldlast=last;
last=new Node();
last.item=data;
if(isEmpty()){
first=last;
}else{
oldlast.next=last;
}
N++;
}
public Item dequeue(){
Item item=first.item;
first=first.next;
if(isEmpty()){
first=last;
}
N--;
return item;
}
public Iterator<Item> iterator() {
return new ListIterator();
}
public class ListIterator implements Iterator<Item>{
private Node current=first;
@Override
public boolean hasNext() {
return current!=null;
}
public Item next() {
Item item=current.item;
current=current.next;
return item;
}
public void remove() {
}
}
}
背包
背包是一种不支持从中删除元素的集合数据类型——它的目的就是为了帮助用例收集元素并迭代遍历所有收集到的元素。
public class Bag<Item> implements Iterable<Item> {
private class Node{
Item item;//每个节点的值
Node next;//每个节点指向下一个节点的引用
}
//头节点
private Node first;
//元素个数
private int N;
public boolean isEmpty(){
return first==null;
}
public int size(){
return N;
}
public void add(Item data){
Node oldfirst=first;
first=new Node();
first.item=data;
oldfirst.next=first;
}
@Override
public Iterator<Item> iterator() {
return new ListIterator();
}
private class ListIterator 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 ;
}
@Override
public void remove(){
}
}
}