队列
队列与栈不同,栈是一种先进后出的数据结构,因此对于入栈push和出栈pop操作来说可以使用同一个指针。而队列是先进先出的,对于插入和删除操作来说,插入(进)的位置在队尾,删除(出)的位置在队首,因此需要队首(front)和队尾(rear)两个指针。
循环队列
对于用数组实现的队列来说,最初的实现方式是插入操作从数组的0下标位置开始,每次插入下标+1,删除也从0下标开始依次从队首往队尾的方向删除。并且删除一次,剩余的所有元素向前移动一位以便队尾有空余位置用来插入新数据。这种方式较为简单但是效率极低,不被采用。
为了避免每次删除队首元素都要移动剩余元素的位置,出现了一种新的思路,就是删除队首元素后,不移动剩余元素,而是移动队首指针,使其指向被删除元素的下一个元素。这样虽然提高了效率,但是会出现更大的问题,因为每次删除操作都会让队首指针+1,而队尾指针永远>=队首指针,因此每次插入都是往数组的高位插入,删除元素后空出的位置将会闲置。为了提高插入和删除的效率同时避免数组空间的浪费,引入了循环队列的概念。
所谓循环队列,就是把数组首尾连起来以实现循环。具体的实现方法是,当添加元素时发现数组末尾没有空余位置时,考虑数组首部是否有空间,如果有则将元素插入到数组头部。此时的数组头部存储的是队列的尾部。对于删除操作来说,还是将队首指针向后移,但是当删除数组末尾的元素后,会将队首指针重新环绕回数组0下标位置。
和栈一样,队列中插入和删除数据的时间复杂度也为O(1)。
java实现
public class QueueArray {
public static void main(String[] args) {
Queue q = new Queue(5);
q.push(1);
q.push(2);
q.push(3);
q.push(4);
q.push(5);
q.push(6);
q.pop();
q.pop();
q.pop();
q.pop();
q.pop();
q.pop();
q.push(6);
q.push(5);
q.pop();
q.pop();
q.pop();
q.pop();
}
}
//countElem用来统计元素个数,当元素个数等于队列长度时即队列已满,当元素个数为零时队列为空!!!
class Queue{
private int front=0,rear=-1,size,countElem=0;
private int[] arr;
public Queue(int size){
//System.out.println("请输入队列长度:");
this.size = size;
this.arr = new int[size];
}
public void pop(){
//只有当队列不为空时才能进行删除操作
if(!isEmpty()){
if(front<size-1){
countElem--;
System.out.println("删除的队首元素是:"+arr[front++]+";此时front="+front+",rear="+rear);
}else if(front==size-1){
countElem--;
System.out.print("删除的队首元素是:"+arr[front]);
front = 0;
System.out.println(";此时front="+front+",rear="+rear);
}
}
}
public void push(int in){
//只有当队列不满时才能进行插入操作
if(!isFull()){
if(rear<size-1){
arr[++rear] = in;
countElem++;
System.out.println("插入的元素是:"+in+";此时front="+front+",rear="+rear);
}else if(rear==size-1){
rear = -1;
arr[++rear] = in;
countElem++;
System.out.println("插入的元素是:"+in+";此时front="+front+",rear="+rear);
}
}
}
public boolean isEmpty(){
if(countElem==0){
System.out.println("当前队列为空!");
return true;
}else
return false;
}
public boolean isFull(){
if(countElem==size){
System.out.println("队列已满!");
return true;
}else{
return false;
}
}
}