关联文章: Java数据结构与算法解析(一)——表 Java数据结构与算法解析(二)——栈
像栈一样,队列也是表。然而,使用队列时插入在一端进行,而删除则在另一端进行。插入的一端称为队尾,删除的一端称为队头 。其插入和删除的操作分别在表的两端进行,队列的特点就是先进先出(First In First Out)。
缺点:出队复杂度高0(n),容易假溢出
Front为队头指针,rear为队尾指针,但是这种存储方式的缺点就是出队复杂度高0(n),容易假溢出,例如让a1,a2出队,则a1,a2存储的位置会被设置为null,然后将front进行移动,指向a3,容易假溢出是指,上图右边的情况,rear已经角标越界,说明要扩容,但是其实队列里有两个地方是空的,就是角标0和1的位置,这种就是假溢出现象
把队列的头尾相接的循环存储结构叫做循环队列。
循环队列就可以很好的解决假溢出的现象
声明队列的公用接口
public interface Queue<T> {
int size();
boolean isEmpty();
void enqueue(T t);
T dequeue();
}
public class ArrayQueue<T> implements Queue<T> {
private T[] mArray;
private int mQueueSize;
private int mFront;
private int mLast;
private static final int DEFAULT_CAPACITY = 10;
public ArrayQueue(int capacity) {
if (capacity < DEFAULT_CAPACITY) {
ensureCapacity(DEFAULT_CAPACITY);
} else {
ensureCapacity(capacity);
}
}
@Override
public int size() {
return mQueueSize;
}
@Override
public boolean isEmpty() {
return mFront == mLast;
}
@Override
public boolean enqueue(T t) {
//判断是否满队
if (mFront == (this.mLast + 1) % mArray.length) {
ensureCapacity(mArray.length * 2 + 1);
}
mArray[mLast] = t;
mLast = (mLast + 1) % mArray.length;
mQueueSize++;
return true;
}
private int findFirstEmptyIndex() {
for (int i = 0; i < mArray.length; i++) {
if (mArray[i] == null) {
return i;
}
}
}
@Override
public T dequeue() {
if (mLast == mFront) {
return null;
} else {
T t = mArray[mFront];
mFront = (mFront + 1) % mArray.length;
return t;
}
}
private void ensureCapacity(int newCapacity) {
T[] newArray = (T[]) new Object[newCapacity];
for (int i = 0; i < mArray.length; i++) {
newArray[i] = mArray[i];
}
mArray = newArray;
}
}
实现队列的最好的方式就是使用单链表来实现,队列的链式存储结构,其实就是线性表的单链表,只不过它只能尾进头出而已。
这种实现出队和入队就十分方便,出队只需要将头结点指向的位置进行改变,入队只需要将rear的指向进行改变
空队列的图如下:
public class LinkedQueue<T> implements Queue<T> {
//队列头指针
private Node<T> mFront;
//队列尾指针
private Node<T> mRear;
//队列长度
private int mSize = 0;
public LinkedQueue() {
Node n = new Node(null, null);
mFront = mRear = n;
}
@Override
public int size() {
return mSize;
}
@Override
public boolean isEmpty() {
return mFront == mRear;
}
@Override
public boolean enqueue(T t) {
Node n = new Node(t, null);
//将队尾指针指向新加入的节点,将s节点插入队尾
mFront.mNext = n;
mRear = n;
mSize++;
return true;
}
@Override
public T dequeue() {
if (mRear == mFront) {
throw new NoSuchElementException("The LinkedQueue is empty");
}
Node<T> deleNote = mFront.mNext;
T t = deleNote.mData;
mFront.mNext = deleNote.mNext;
//判断出队列长度是否为1
if (mFront.mNext == null) {
mFront = mRear;
}
mSize--;
return t;
}
private static class Node<T> {
private Node<T> mNext;
private T mData;
public Node(T data, Node<T> next) {
mData = data;
mNext = next;
}
}
}
背包是一种不支持从中删除元素的集合数据类型,它的目的就是帮助用例收集元素并迭代遍历所有收集到的元素,使用背包就说明元素的处理顺序不重要,可以想象一个背包,往里面放了N个小球,在取球的时候手伸进背包是随机取出来的,通常这样的数据结构用来进行计算平均值等对元素顺序没有要求的算法; 图1
public class ArrayBag<T> implements Iterable {
private T[] mArray;
private int mBagSize;
private static final int DEFAULT_CAPACITY = 10;
public ArrayBag() {
ensureCapacity(DEFAULT_CAPACITY);
}
public ArrayBag(int bagSize) {
if (bagSize > DEFAULT_CAPACITY) {
ensureCapacity(bagSize);
} else {
ensureCapacity(DEFAULT_CAPACITY);
}
}
public void add(T t) {
if (mArray.length == mBagSize) {
ensureCapacity(mArray.length);
}
mArray[mBagSize] = t;
mBagSize++;
}
private void ensureCapacity(int newCapacity) {
T[] newArray = (T[]) new Object[newCapacity];
for (int i = 0; i < mArray.length; i++) {
newArray[i] = mArray[i];
}
mArray = newArray;
}
@Override
public Iterator iterator() {
return new ArrayIterator();
}
private class ArrayIterator implements Iterator<T> {
private int currentPositon;
@Override
public boolean hasNext() {
return currentPositon < mBagSize;
}
@Override
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return mArray[currentPositon++];
}
}
}
public class LinkedBag<T> implements Iterable {
private int mBagSize;
private Node<T> headNote;
public LinkedBag() {
headNote = new Node<T>(null, null);
}
public void add(T t) {
Node<T> node = new Node<T>(t, null);
headNote.mNext = node;
}
@Override
public Iterator iterator() {
return new ArrayIterator();
}
private class ArrayIterator implements Iterator<T> {
private Node<T> currentNode = headNote.mNext;
@Override
public boolean hasNext() {
return currentNode != null;
}
@Override
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
T t = currentNode.mData;
currentNode = currentNode.mNext;
return t;
}
}
private static class Node<T> {
private Node<T> mNext;
private T mData;
public Node(T data, Node<T> next) {
mData = data;
mNext = next;
}
}
}