队列-循环队列及其实现

来源:互联网 发布:mac java环境变量设置 编辑:程序博客网 时间:2024/06/05 04:45

概念:队列也是一种特殊的线性表,它的特殊性在于队列置允许在表尾插入数据元素,在表头删除数据元素,所以队列也是一种操作受限的线性表,它具有先进先出的特性。

允许进行插入的一端称为队尾(rear),允许进行删除的一端称为队首(front),队列的插入操作通常称为入队操作,队列的删除操作通常称为出队操作

——————————————-

队列的抽象数据类型描述:
队列的基本操作与栈类似,主要有以下6种操作:
–清空队列操作 clear()
—判断空操作 isEmpty()
—求队列长度 length()
—取队首操作peek()
—入队操作offer(x)
—出队操作 poll() s删除队首元素并且返回其值,若队列尾空,则返回null。

队列的抽象数据类型用java接口描述如下:
package com.queueTest;

public interface Queue
{
public void clear();
public boolean isEmpty();
public int length();
public Object peek();
public void offer(Object x) throws Exception;
public void poll();

}
这里写图片描述

顺序队列与顺序栈类似,在顺序队列的存储结构中,需要分配一块地址连续的存储区域来依次存放队列中从队首到队尾的所有元素。这样也可以使用一维数组来表示,假设数组名queueElem ,数组的最大容量是maxSize,,由于队列的入队操作只能在队尾进行,出队操作只能在队首进行,所以需要加上变量front和rear来分别指向队首和队尾元素在数组中的位置,其初始值都是0.front指向队首元素,rear指向队尾元素的下一个存储位置。

初始化队列时,令front = rear =0,入队时,直接将新的数据元素放入rear所指的存储单元中,然后将rear的值加1;出队时,直接取出front所指的存储单元数据元素的值,然后将front值加1.

如上图中,如果要继续将数据元素H入队,H应该存放于rear = 6的位置处,顺序队列则会因为数组下标越界而引起“溢出”,但此时顺序队列的首部还空出了两个数据元素的存储空间。因此,这种溢出不是因为数组空间不够而产生的溢出,这种因顺序队列的多次入队和出队操作后出现的存储空间,当不能进行入队操作的溢出现象称为“假溢出”。

要解决假溢出的问题,最好的办法就是把顺序队列的存储空间看成是一个逻辑上首尾相连的循环队列。当rear或者front到达 maxSize - 1 时,再加1就自动到0.这种转换可以利用java语言对整形数据求模(或者取余)运算来实现,即令 rear =(rear + 1) % maxSize;

这里写图片描述

解决循环队列的队空盒队满的判断问题通常可以采用如下三种方法:
(1)少用一个存储单元。当顺序存储空间的容量为maxSize时,只允许最多存储maxSize-1个数据元素,此时判断空的条件为 front == rear ,判断满的条件是front == (rear+1) % maxSize;

(2)设置一个标志变量 flag,其初始值为0,每当入队操作成功后就置flag = 1,出队操作成功后就置flag=0;则此时队空的判断条件为 front = rear && flag == 0,队满的条件是front == rear && flag == 1.

(3)设置一个计数器num,其初始值是0,入队操作成功后就将计数变量num+1,出队操作成功后就将计数变量num-1,则此时判断队空的条件为num=0,队满的条件为 num>0 && front = rear


下面是实现接口Queue的循环队列类的java语言描述。

package com.queueTest;public class CircleSqQueue  implements   Queue{    private  Object[]  queueElem;  //队列存储空间    private  int  front;  //队头的引用,若队列不为空,则指向队列头元素    private  int  rear; //队尾的引用,若队列不为空,指向队尾元素的下一个存储位置    //循环队列的构造函数:     public CircleSqQueue(int  maxSize)    {         front =rear= 0;//队头,队尾初始化为0         queueElem = new  Object[maxSize];  //为队列分配maxSize个存储单元    }//队列置空    @Override    public void clear()     {        front =rear =0;    }//判断队列是否为空    @Override    public boolean isEmpty()    {        return front == rear;    }    //求队列长度    @Override    public int length()    {        return (rear - front + queueElem.length)  %  queueElem.length;    }    //读取队首元素    @Override    public Object peek()    {        if(front == rear)        {            return  null;        }        else        {            return  queueElem[front];        }    }    /*     * 循环队列的入队操作:     * 1。判断循环队列是否为满,若满,则抛出异常后结束操作,否则到下一步     * 2.先将新的数据元素x存入rear所指示的数组存储位置中,使其成为新的队尾元素,再将rear值循环加1.使     * 使rear始终指向队尾元素的下一个存储位置.     *      */    @Override    public void offer(Object x) throws Exception    {        if((rear+1) % queueElem.length == front)        {            throw  new  Exception("队列已满");        }        else        {            queueElem[rear] = x;            rear = (rear+1)  % queueElem.length;        }    }    /*     * 循环队列的出队操作     * 判断队列是否为空,为空,则返回null     * 取出front所指元素的值,再将front值循环加1     *      */    @Override    public Object poll()    {        if(front == rear)        {            return  null;        }        else        {            Object t=queueElem[front];            front=(front + 1) % queueElem.length;            return  t;        }    }    //输出所有元素    public  void display()    {        if(! isEmpty())        {            for(int i =front;i != rear;i=(i+1) % queueElem.length)            {                System.out.println(queueElem[i].toString()+"");            }        }        else{            System.out.println("队列为空");        }    }}
0 0
原创粉丝点击