队列:
基本概念:
队列也是一种操作受限的线性表。只能在一端进行插入而在另一端进行删除。允许插入的一端称为队尾【rear】,允许删除的另一端称为队头【front】。队头删除元素称作出队,队尾插入元素称为进队。
队列ADT:
顺序队列:
队列顺序存储就是使用数组依次存储相应数据元素。此时队列称为顺序队列。
通常进队列数据由低地址到高地址一次存放。队头元素是数组中首元素。
public class SequenceQueue<T> {
private final int DEFAULT_CAPACITY = 10;
private Object[] elements;
private int capacity;
private int front = 0;
private int rear = 0;
public SequenceQueue(){
this.capacity = DEFAULT_CAPACITY;
elements = new Object[capacity];
}
public SequenceQueue(T element,int initCapacity){
this.capacity = initCapacity;
elements = new Object[capacity];
elements[0] = element;
rear++;
}
public int size(){
return rear - front;
}
public boolean isEmpty(){
return rear == front;
}
public void enQueue(T element){
if(rear > capacity - 1){
throw new IndexOutOfBoundsException("SequenceQueue is full");
}
elements[rear++] = element;
}
public T remove(){
if(isEmpty()){
throw new IndexOutOfBoundsException("SequenceQueue is empty");
}
T t = (T) elements[front];
elements[front++] = null;
return t;
}
//清空队列??
public void clear(){
front = 0;
rear = 0;
}
public T getFront(){
return (T) elements[front];
}
public String toString(){
if(isEmpty()){
return "[]";
}else{
StringBuilder sb = new StringBuilder("[");
for(int i = front;i < rear;i++){
sb.append(elements[i].toString()+",");
}
return sb.toString().substring(0,sb.length()-1)+"]";
}
}
public static void main(String[] args){
SequenceQueue<String> queue = new SequenceQueue<String>("a",4);
queue.enQueue("b");
queue.enQueue("c");
queue.enQueue("d");
System.out.println("the queue is :"+queue);
System.out.println("the queue front is:"+queue.getFront());
System.out.println("the queue remove is:"+queue.remove());
queue.enQueue("e");
}
}
下面为描述的过程:
当再次添加元素e时,出现队列已满的问题,但是实际上未满。即队列出现假满情况。
顺序队列容易出现“假满”现象
数据元素在底层数组中的位置是固定的。改变的只是front,rear两个整型变量的值。
即一般以rear=capacity来判断是否队列已经满。
如果此时再接着试图向队列中添加元素,将会引起队列“已满”的异常。
解决办法:
1.每次将元素移除时都将队列中的所有元素向front端移动1位,这种方式front的值永远为0,元素每次入队时,rear值+1出队时rear值-1.但是非常浪费时间。
2.将数组存储区看作是一个首尾相连的环形区域,当存放到数组的最大位置之后,,rear再次变为0.即为循环队列。
3.采用链式队列
循环队列:
【偷懒网上盗了两张图,侵删。。】
在上图中,front指向队列中第一个元素,rear指向队列队尾的下一个位置。
但依然存在一个问题:当front和rear指向同一个位置时,这代表的是队空还是队满呢?大家可以想象下这种情景。
解决这种问题的常见做法是这样的:
使用一标记,用以区分这种易混淆的情形。
牺牲一个元素空间。当front和rear相等时,为空;当rear的下一个位置是front时,为满。
public class QueueArray<T>{
private int capacity;
private Object[] elements;
private int front;
private int rear;
public QueueArray(int capacity){
this.capacity = capacity;
elements = new Object[capacity];
front = 0;
rear = 0;
}
public int getSize(){
return (rear-front+capacity)%capacity;
}
public boolean isEmpty(){
return (front==rear)?true:false;
}
public boolean isFull(){
return ((rear+1)%capacity == front)?true:false;
}
private void expandSpace(){
Object[] a = new Object[elements.length*2];
int i = front;
int j = 0;
while(i!=rear){
a[j++] = elements[i];
i = (i+1)%capacity;
}
elements = a;
capacity = elements.length;
//设置新的队首队尾指针
front = 0;
rear = j;
}
public void enQueue(Object e){
if((rear+1)%capacity == front){
expandSpace();
}
elements[rear] = e;
rear = (rear+1)%capacity;
}
public boolean deQueue(){
if(rear == front){
System.out.println("queue is empty");
return false;
}
else{
front = (front+1)%capacity;
return true;
}
}
public Object getFront(){
if(rear == front){
System.out.println("queue is empty");
}
return elements[front];
}
public String toString(){
if(isEmpty()){
return "[]";
}else{
StringBuilder sb = new StringBuilder("[");
for(int i = front;i < rear;i++){
sb.append(elements[i].toString()+",");
}
return sb.toString().substring(0,sb.length()-1)+"]";
}
}
public static void main(String[] args){
QueueArray queueArray = new QueueArray(4);
for(int i = 0;i < 4;i++){
queueArray.enQueue(i);
}
System.out.println("循环队列:"+queueArray);
System.out.println("0出队");
queueArray.deQueue();
System.out.println("4入队");
queueArray.enQueue(4);
System.out.println("循环队列:"+queueArray);
}
}
链式队列:
/**
* 链队列的结点
*
*/
class Node{
Object data; //数据元素
Node next; //后驱结点
public Node() {
this(null);
}
public Node(Object data) {
this.data = data;
this.next = null;
}
}
/**
* 链队列
*
*/
public class LinkQueue{
private Node front,rear; //队头指针和队尾指针
private int size;
public LinkQueue() {
front = rear = new Node();
size = 0;
}
public void clear() {
front.next = null;
rear = front;
size = 0;
}
public Object deQueue() {
Node p = front.next;
front.next = p.next;
rear = p.next;
size --;
return p.data;
}
public boolean isEmpty() {
if(size == 0)
return true;
else
return false;
}
public Object peek() {
return front.next.data;
}
public void enQueue(Object obj) {
Node p = new Node(obj);
rear.next = p;
rear = p;
size ++;
}
public int size() {
return size;
}
public String toString() {
StringBuilder sb= new StringBuilder("[");
Node p = front;
while((p=p.next) != null) {
sb.append(p.data + ", ");
}
sb.append("]");
return sb.toString();
}
public static void main(String[] args){
LinkQueue queue = new LinkQueue();
for(int i = 0;i < 5;i++){
queue.enQueue(i);
}
System.out.println("queue is:"+queue);
}
}
参考博客: