数据结构 队列(JAVA语言描述)
队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
队列是一种先进先出(First In First Out)的线性表。允许插入的一端称为队尾,允许删除的一端称为队头。
队头(Front):允许删除的一端,又称队首。
队尾(Rear):允许插入的一端。
空队列:不包含任何元素的空表。
- 队列的常见方法
public interface Queue<E> extends Iterable<E> {
public void offer(E element);//入队
public E poll();//出队
public E element();
public boolean isEmpty();
public void clear();
public int size();
}
- 队列方法的实现
public class ArrayQueue<E> implements Queue<E> {
private ArrayList<E> list;
public ArrayQueue(){
list = new ArrayList<>();
}
@Override
public void offer(E element) {
list.add(list.size(),element);
}
@Override
public E poll() {
return list.remove(0);
}
@Override
public E element() {
return list.get(0);
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
@Override
public void clear() {
list.clear();
}
@Override
public int size() {
return list.size();
}
@Override
public Iterator<E> iterator() {
return list.iterator();
}
@Override
public String toString() {
return list.toString();
}
@Override
public boolean equals(Object o) {
if (null == o) return true;
if (this==o){
return true;
}
if (o instanceof ArrayQueue){
ArrayQueue other = (ArrayQueue) o;
return list.equals(other.list);
}
return false;
}
- 用队列去实现栈
class StackImplByQueue<E> implements Stack<E>{
private ArrayQueue<E> queue1;
private ArrayQueue<E> queue2;
public StackImplByQueue(){
queue1 = new ArrayQueue<>();
queue2= new ArrayQueue<>();
}
@Override
public int size() {
if (queue1.isEmpty()&&queue2.isEmpty()){
return 0;
}else if (!queue1.isEmpty()){
return queue1.size();
}else {
return queue2.size();
}
}
@Override
public boolean isEmpty() {
return queue1.isEmpty() && queue2.isEmpty();
}
@Override
public void push(E element) {
if(queue1.isEmpty() && queue2.isEmpty()){
queue1.offer(element);
}else if (!queue1.isEmpty()){
queue1.offer(element);
}else {
queue2.offer(element);
}
}
@Override
public E pop() {
if (isEmpty()){
return null;
}
E ret = null;
if (!queue1.isEmpty()){
while (queue1.size()!=1){
queue2.offer(queue1.poll());
}
ret = queue1.poll();
}else {
while (queue2.size()!=1){
queue1.offer(queue2.poll());
}
ret = queue2.poll();
}
return ret;
}
@Override
public E peek() {
if (isEmpty()){
return null;
}
E ret = null;
if (!queue1.isEmpty()){
while (queue1.size()!=1){
queue2.offer(queue1.poll());
}
ret = queue1.poll();
queue2.offer(ret);
}else {
while (queue2.size()!=1){
queue1.offer(queue2.poll());
}
ret = queue2.poll();
queue1.offer(ret);
}
return ret;
}
@Override
public void clear() {
queue1.clear();
queue2.clear();
}
@Override
public Iterator<E> iterator() {
if (isEmpty()){
return queue1.iterator();
}else if (!queue1.isEmpty()){
return queue1.iterator();
}else {
return queue2.iterator();
}
}
@Override
public String toString() {
if (isEmpty()){
return "[]";
}else if (!queue1.isEmpty()){
return queue1.toString();
}else {
return queue2.toString();
}
}
- 循环队列
将队列臆造成一个环状的空间,即把存储队列元素的表从按逻辑上视为一个环,称为循环队列。当队首指针 Q.front == MAXSIZE - 1,再前景一个位置就自动到0,这可以利用除法取余运算(%) 来实现。
队首指针进1:Q.front = (Q.front + 1) % MAXSIZE;
队尾指针进1:Q.rear = (Q.rear + 1)% MAXSIZE;
队列长度:(Q.front + MAXSIZE - Q.rear) % MAXSIZE;
//循环队列
public class ArrayLoopQueue<E> implements Queue<E> {
private E[] data;
//队首
private int front;
//队尾
private int rear;
//元素个数
private int size;
//默认容量
private static int DEFAULT_CAPACITY=10;
public ArrayLoopQueue(){
data = (E[]) new Object[DEFAULT_CAPACITY+1];
front =0;
rear =0;
size =0;
}
@Override
public void offer(E element) {
//判满
if ((rear+1)% data.length == front){
resize(data.length*2-1);
}
data[rear] = element;
rear= (rear+1)%data.length;
size++;
}
@Override
public E poll() {
//判空
if (isEmpty()){
throw new IllegalArgumentException("null");
}
E ret = data[front];
front = (front+1)% data.length;
size--;
if (size <= (data.length-1)/4&& data.length-1>DEFAULT_CAPACITY){
resize(data.length/2+1);
}
return null;
}
private void resize(int newLen) {
E[] newdata = (E[]) new Object[newLen];
int index=0;
for(int i = front;i!=rear;i=(i+1)% data.length){
newdata[index++]=data[i];
}
data = newdata;
front = 0;
rear = index;
}
@Override
public E element() {
if (isEmpty()){
throw new IllegalArgumentException("null");
}
return data[front];
}
@Override
public boolean isEmpty() {
return front == rear;
}
@Override
public void clear() {
data = (E[]) new Object[DEFAULT_CAPACITY];
front =0;
rear =0;
size =0;
}
@Override
public int size() {
return size;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append('[');
if (isEmpty()){
sb.append(']');
return sb.toString();
}else {
for (int i =front;i!=rear;i=(i+1)% data.length){
sb.append(data[i]);
if ((i+1)% data.length==rear){
sb.append(']');
}else{
sb.append(',');
}
}
}
return sb.toString();
}
@Override
public boolean equals(Object o) {
if (o == null) return false;
if (this == o) return true;
if (o instanceof ArrayLoopQueue){
ArrayLoopQueue<E> other = (ArrayLoopQueue<E>) o;
if (size != other.size){
return false;
}
int i =front;
int j =other.front;
while (i!=rear){
if (!data[i].equals(other.data[j])){
return false;
}
i = (i+1)% data.length;
j = (j+1)% other.data.length;
}
return true;
}
return false;
}
@Override
public Iterator<E> iterator() {
return new ArrayLoopQueueIterator();
}
class ArrayLoopQueueIterator implements Iterator<E>{
private int cur = front;
@Override
public boolean hasNext() {
return cur!=rear;
}
@Override
public E next() {
E ret = data[cur];
cur = (cur+1)% data.length;
return ret;
}
}
}
- 双端队列
双端队列(Deque:double ended queue)就是一个两端都是结尾的队列。
队列的每一端都能够插入数据项和移除数据项。
相对于普通队列,双端队列的入队和出队操作在两端都可进行。
public class ArrayDeque<E> implements Dequeue<E>, Stack<E> {
private E[] data;
private int front;
private int rear;
private int size;
private static int DEFAULT_CAPACITY=10;
public ArrayDeque(){
data = (E[]) new Object[DEFAULT_CAPACITY+1];
front =0;
rear =0;
size =0;
}
@Override
public void addFirst(E element) {
if ((rear+1)% data.length ==front){
resize(data.length*2-1);
}
front =(front-1+ data.length)% data.length;
data[front] = element;
size++;
}
private void resize(int newLen) {
E[] newdata = (E[]) new Object[newLen];
int index=0;
for(int i = front;i!=rear;i=(i+1)% data.length){
newdata[index++]=data[i];
}
data = newdata;
front = 0;
rear = index;
}
@Override
public void addLast(E element) {
if ((rear+1)% data.length ==front){
resize(data.length*2-1);
}
data[rear] =element;
rear =(rear+1)% data.length;
size++;
}
@Override
public E removeFirst() {
if (isEmpty()){
throw new IllegalArgumentException("null");
}
E ret = data[front];
front =(front-1)% data.length;
size--;
if (size<= (data.length-1)/4 && data.length-1 >DEFAULT_CAPACITY){
resize(data.length/2+1);
}
return ret;
}
@Override
public E removeLast() {
if (isEmpty()){
throw new IllegalArgumentException("null");
}
rear =(rear-1+ data.length)% data.length;
E ret = data[rear];
size--;
if (size<= (data.length-1)/4 && data.length-1 >DEFAULT_CAPACITY){
resize(data.length/2+1);
}
return ret;
}
@Override
public E getFirst() {
if (isEmpty()){
throw new IllegalArgumentException("null");
}
return data[front];
}
@Override
public E getLast() {
if (isEmpty()){
throw new IllegalArgumentException("null");
}
return data[(rear-1+ data.length)% data.length];
}
@Override
public void offer(E element) {
addLast(element);
}
@Override
public E poll() {
return removeFirst();
}
@Override
public E element() {
return getFirst();
}
@Override
public boolean isEmpty() {
return size == 0&&front ==rear;
}
@Override
public void push(E element) {
addLast(element);
}
@Override
public E pop() {
return removeLast();
}
@Override
public E peek() {
return getLast();
}
@Override
public void clear() {
data = (E[]) new Object[DEFAULT_CAPACITY];
front =0;
rear =0;
size =0;
}
@Override
public int size() {
return size;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append('[');
if (isEmpty()) {
sb.append(']');
return sb.toString();
}
for (int i = front; i != rear; i = (i + 1) % data.length) {
sb.append(data[i]);
if ((i + 1) % data.length == rear) {
sb.append(']');
} else {
sb.append(',');
sb.append(' ');
}
}
return sb.toString();
}
@Override
public Iterator<E> iterator() {
return new ArrayDequeIterator();
}
class ArrayDequeIterator implements Iterator<E> {
private int cur = front;
@Override
public boolean hasNext() {
return cur != rear;
}
@Override
public E next() {
E ret = data[cur];
cur = (cur + 1) % data.length;
return ret;
}
}
}