您的位置:首页 > 产品设计 > UI/UE

java集合源码解读---Queu和Stack的数组和链式实现

2015-11-04 19:22 483 查看

栈和队列

所谓的栈,是一个含有至少两个基本操作的抽象数据类型:插入新的元素;删除最近时间插入的元素。遵循FILO(First in,last out,先进后出)的原则。

所谓的队列,也是一个含有至少两个基本操作的抽象数据类型:插入新的元素;删除最久时间插入的元素。遵循FIFO(First in,first out,先进先出)的原则。

关于栈和队列的具体实现,我们即可以借助于数组,也可以采用链表来实现。

1) 栈的数组实现方式

java代码

public class MyStack <E>{

public int count;
public Object[] items;

public MyStack()
{
items = new Object[20];
count = 0;
}
public MyStack(int len)
{
items = new Object[len];
count = 0;
}
//判断栈是否为空
boolean isEmpty(){return count==0;}

//重整数组的大小
private void resize(int size)
{
Object[] newItems = new Object[size];
for(int i =0;i<count;i++)
newItems[i] = items[i];
items = newItems;
}
//进栈
public void push(E e)
{
//如果栈满,则重整数组大小。
if(count == items.length) resize(2*items.length);
items[count++] = e;//数组的起始索引是0,入栈后,数组的大小应增加1
}
//出栈
public E pop()
{
if(count==0) return null; //如果栈为空
E item = (E)items[count-1];
items[count-1] = null;
count--;
//重整数组大小,节省存储空间。
if(count>0&&count<=items.length/4) resize(items.length/2);

return item;
}

//返回栈中的最后一个元素
public E peek()
{
if(count==0) return null;

E item = (E)items[count-1];
return item;
}
}


2)栈的链式实现方式

java代码

public class MyStack<E> {
Node head;//表示栈顶
private class Node<E>
{
E item;
Node next;
}
public boolean isEmpty()
{
return head==null;
}
public void push(E e)
{
Node<E> node = new Node();
node.item = e;
node.next = head; //栈的物理连接顺序是从上到下
head = node;
}
public E pop()
{
if(head==null) return null;
E e = (E)head.item;//栈顶元素先出
head=head.next;
return e;
}
public E peek()
{
if(head == null) return null;
else
return (E)head.item;
}
}


3)队列的数组实现方式

java代码

//用数组实现循环队列
public class ArrayQueue <E>
{
private int front;
private int rear;
private int capacity;
private int count;
private int capacityIncrement;
private Object[] itemArray;

public ArrayQueue(){
front = 0;
rear = 0;
count = 0;
capacity = 10;
capacityIncrement = 5;//新增队列的长度。
itemArray = new Object[capacity];
}

boolean isEmpty() {return count==0;}

//1.入队
public void insert(E e)
{
//1.如果队列已满,就先扩充队列,后插队。
if(count==capacity) {
capacity+=capacityIncrement;
Object[] newArray = new Object[capacity];
/**
* 将原队列中的元素原样拷贝到新队列中。如果不是原样拷贝,则会破坏队列的FIFO特性。
*/
//如果队列中的元素位于itemArray[font.....rear-1]中
if(front<rear){
for(int i = front;i<rear;i++){
newArray[i] = itemArray[i];
}
}
else{
//因队列已满,此时front==rear,应该将队列分成两个区间:[0:rear-1] 和[front:count-1],分别拷贝到新数组的两端。
//在原队列的中间插入一段新的存储空间。
//否则,如果在原队列的后面插入新的空间,那么再次进行入队操作时,原来的元素就会被覆盖掉。
for(int i =0;i<rear;i++){newArray[i] = itemArray[i];}
for(int i = front;i<count;i++)
{newArray[i+capacityIncrement] = itemArray[i];}
front+=capacityIncrement;//然后,将front改为指向其新位置.
}
itemArray = newArray;
}

//2.如果队列未满,直接插队。
itemArray[rear]=e;
rear=(rear+1)%capacity;
count++;
}

//2.出队
public E remove()
{
if(count==0) return null;
else{
E item = (E)itemArray[front];
itemArray[front] = null;
front = (front+1)%capacity;
count--;
return item;
}
}
}
//另外一种数组实现循环队列的简单实现
import java.util.NoSuchElementException;

public class SimpleArrayQueue {
protected Object [] data;
protected int size,
head,
tail;
public SimpleArrayQueue(){
final int INITIAL_LENGTH=10;
data=new Object[INITIAL_LENGTH];
size=0;
head=0;
tail=-1;
}
//获取队列的大小和判断队列是否为空
public int theSize(){ return size;}
public boolean isEmpty(){ return size==0;}

//获取队头元素
public Object front(){
if(size==0) throw new NoSuchElementException();
return data[head];
}

//入队操作
public void enqueue(Object element){
if(size==data.length){

//在java中允许将一个数组变量拷贝给另外一个数组变量。这时,两个变量将引用同一个数组。
Object [] oldData=data;//保存原数组data
data=new Object[data.length*2]; //double the length of data

//将数组分成两个区间进行拷贝:区间1:[head:OldData.length-1]和区间2:[0:tail]
//当head==0时,原数组只有区间1这一段需要被拷贝,当head>0时,原数组有区间1和区间2这两段需要被拷贝。
//copy oldData[head:OldData.length-1] to data[0:OldData.length-1-head]
System.arraycopy(oldData, head,data,0,oldData.length-head);
/*
* 如果希望将一个数组的所有值拷贝到一个新的数组中去,就要使用Arrays类中的copyOf()方法:
*  int[] copiedLckyNumbers = Arrays.copyOf(luckyNumbers,2*luckyNumbers.length);
*  第二个参数是新数组的长度,这个方法通常用来增加数组的大小。
*  如果数组的元素是数值型,那么多余的元素将被赋值为0;如果是boolean,多余的元素将会被赋值为false;
*  相反,如果长度小于原始数组的长度,则只会拷贝最前面的数据元素。
*/

if(head>0)//拷贝区间2
//copy oldData[0:tail] to data [oldData.length-head:oldlenght-1]
//System.arraycopy(oldData, 0, data, head+1, tail+1); //错误写法
System.arraycopy(oldData, 0, data,oldData.length-head, tail+1);//正确写法
head=0;
tail=oldData.length-1;
}

tail=(tail+1)%data.length;
data[tail]=element;
size++;
}

//出队操作
public Object dequeue(){
/* 注意 :
* if(size--==0){throw new NoSuchElementException();}//先执行if(size==0),后执行size--;
* 放置的顺序。
* 不能写成if(--size==0){ throw new NoSuchElementException(); }
* 因为当队列中就剩下一个元素时,--size;会使size为0,此时抛出异常,并没有对该异常进行处理。
* 程序中断,后面的语句无法执行。
*/
Object element=data[head];
head=(head+1)%data.length;//当队列满的时候size==data.length,即data.length就是当前size的值。
//如果size变小后,head就会跳过下一个元素,而不是顺移下一个,导致下一个元素被”遗忘“了。
if(size--==0){ throw new NoSuchElementException(); } //先执行if(size==0),后执行size--;
return element; //程序最后一句一定要是return语句。
}

}


4)队列的链式实现方式

java代码

public class ListQueue <E>{
private int count;
private Node<E> front,rear;

private class Node<E>
{
E item;
Node link;
}

//   //提供java类的空参数的构造函数。
//   ListQueue()
//  {
//      count =0;
//      front = null;
//      rear = null;
//      Node<E> node = new Node<E>();
//  }

public boolean isEmpty(){ return count==0;}

//入队
public void insert(E e)
{
Node<E> newNode = new Node<E>();//初始化为空节点。
newNode.item = e;

//如果队为空
if(rear==null)
front = rear = newNode;
else{
rear.link = newNode;//新节点连接到队尾处
rear = newNode;//新节点变成队尾
}
count++;
}
//出队
public E remove()
{
//如果队为空
if(count==0) return null;
else{
E item = front.item;
front = front.link;

if(front==null) { rear = null; }//队列为空。
count--;
return item;
}
}
//克隆队列
public ListQueue<E> clone()
{
ListQueue<E>Q = new ListQueue<E>();
for(Node<E>t=front;t!=null;t=t.link)//for循环的这种写法。等价于while循环。
Q.insert(t.item);
return Q;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: