Java数据结构和算法学习(四)—— 队列

Java数据结构和算法学习(四)—— 队列

本次开始学习队列,队列和栈刚好相反,队列遵循是一种先进先出的原则。

一、队列的基本概念

队列(queue):一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表,进行插入操作的端称为队尾,进行删除操作的端称为对头,队列中没有元素时,称为空队列。

队列的数据元素又称为队列元素,在队列中插入一个队列元素称为入队,删除一个元素称为出队。因为队列只允许在一端插入,另一端删除,所以只有最早进入队列的元素才能最先从队列中删除,因此队列又称为先进先出(FIFO-first in first out)线性表。
队列分为:
1、单项队列(QUeue):只能在一端插入数据,另一端删除数据。
2、双向队列(Deque):每一端都可以进行插入数据和删除数据。
3、优先级队列:比栈和队列更专用的数据结构,在优先级队列中,数据项按照关键字进行排序,关键字最小(或最大)的数据项往往在队列的最前面,而数据项在插入的时候都会插入到合适的位置以确保队列的有序。

二、Java模拟单向队列实现

实现分析:
1、与栈不同的是,队列中的数据不总是从数组的0下标开始的,移除一些队头front的数据后,队头指针跟着移动到下一个不为空的元素的位置。
2、在设计时,队列中新增一个数据时,队尾的指针rear也会移动到新增数据的位置,移除数据时,队头指针front同样会移动到下一个位置。
3、如果像步骤2那样移动的话,那么队尾指针很快就移动到数据的最末端了,这时候可能移除过数据,那么队头会有空着的位置,当再次新来一个数据时,我们会让队尾指针绕回到数组开始的位置,这也称为循环队列

代码如下:

public class MyQueue {

    private Object[] queArry;

    //队列总大小
    private int maxSize;
    //前端
    private int front;
    //后端
    private int rear;
    //队列中元素的实际数目
    private int nItem;

    public MyQueue(int s)
    {
        maxSize=s;
        queArry=new Object[maxSize];
        front=0;
        rear=-1;
        nItem=0;
    }

    //队列中新增数据
    public void insert(int value)
    {
        if(isFull())
        {
            System.out.println("队列已满");
        }else {
            //如果队列尾部指向末尾,那么循环回来,执行第一个元素
            if(rear==maxSize-1)
            {
                rear=-1;
            }
            //队尾指针+1,然后在队尾指针处插入新的数据
            queArry[++rear]=value;
            nItem++;
        }
    }
    //移除数据
    public Object remove()
    {
        Object removeValue=null;
        if(!isEmpty())
        {
            removeValue=queArry[front];
            queArry[front]=null;
            front++;
            if(front==maxSize)
            {
                front=0;
            }
            nItem--;
            return removeValue;
        }
        return removeValue;

    }
    //查看队头数据
    public  Object peekFront()
    {
        return queArry[front];
    }
    //判断队列是否满了
    public boolean isFull()
    {
        return (nItem==maxSize);
    }
    //判断队列是否为空
    public boolean isEmpty()
    {
        return (nItem==0);
    }
    //返回队列的大小
    public int getSize()
    {
        return nItem;
    }
}
class MyQueueTest{

    public static void main(String[] args) {
        MyQueue queue=new MyQueue(3);
        queue.insert(1);
        queue.insert(2);
        queue.insert(3);

        System.out.println(queue.peekFront());
        queue.remove();
        System.out.println(queue.peekFront());

        queue.insert(4);
        System.out.println(queue.peekFront());
        //队列已满,不能再插入数据
        queue.insert(5);
    }
}

三、双端队列

双端对列就是一个两端都是结尾或者开头的队列,队列的每一端都可以进行插入和删除操作,方法有:
insertRight()、insertLeft()、removeLeft()、removeRight()
如果严格禁止调用insertLeft()、removeLeft()(或右端操作),那么双端队列的功能和栈一样。
如果禁止调用insertRight()、insertLeft()(或另一对方法),那么就和单项队列一样。

四、优先级队列

优先级队列是比栈和队列更专用的数据结构,在优先级队列中,数据项按照关键字进行排序,关键字最小(或最大)的数据项往往在队列的最前面,而数据项在插入的时候都会插入到合适的位置以确保队列的有序。
优先级队列是0个或多个元素的集合,每个元素都有一个优先权,对优先级队列执行的操作有:
查找
插入一个新元素
删除
一般情况下,查找操作用来搜索优先权最大的元素,删除操作用来删除该元素。对于优先权相同的元素,可按先进先出次序处理或按任意优先权进行。
这里用数组实现优先级队列,这种方法插入比较慢,但比较简单,适用于数据量比较小并且不是特别注重插入速度的情况。
后面学习到堆时,会用堆的数据结构来实现优先级队列,可以相当快的插入数据。
数组实现优先级队列,声明为int类型的数组,关键字是数组里面的元素,在插入的时候按照从大到小的顺序排列,也就是越小的元素优先级越高。

代码如下:

public class PriorityQue {
    private int maxSize;
    private int[] priQueArray;
    private int nItems;

    public PriorityQue(int s)
    {
        maxSize=s;
        priQueArray=new int[maxSize];
        nItems=0;
    }

    //插入数据
    public void insert(int value)
    {
        int j;
        if(nItems==0)
        {
            priQueArray[nItems++]=value;
        }else{
            j=nItems-1;
            //选择的排序方法时插入排序,按照的从小到大的顺序排列,越小的元素在越顶端
            while (j>=0&&value>priQueArray[j])
            {
                priQueArray[j+1]=priQueArray[j];
                j--;
            }
            priQueArray[j+1]=value;
            nItems++;
        }
    }
    //移除数据,由于是按照大小排序的,所以移除数据指针向下移动
    //被移动的地方由于是int类型的,不能设置为null,这里设置为-1
    public int remove()
    {
        int k=nItems-1;
        int value=priQueArray[k];
        priQueArray[k]=-1;//表示数据被移除
        nItems--;
        return value;
    }
    //查看优先级最高的元素
    public int peekMin(){
        return priQueArray[nItems-1];
    }
    //判断是否为空
    public boolean isEmpty(){
        return (nItems==0);
    }
    //判断是否满了
    public boolean isFull(){
        return (nItems==maxSize);
    }
}

insert()方法,先检查队列中是否有数据项,如果没有,则直接插入到下标为0的单元里,否则,从数组的顶部开始比较,找到比插入值小的位置进行插入,并把nItems+1。

remove方法直接获取顶部元素。

优先级队列的插入操作需要O(N)的时间,而删除操作则需要O(1)的时间。

五、总结

单向队列遵循先进先出的原则,而且一端只能插入,另一端只能删除。双向队列则两端都可插入和删除,如果限制双向队列的某一段的方法,则可以达到和单向队列同样的功能。最后优先级队列,则是在插入元素的时候进行了优先级别排序,在实际应用中单项队列和优先级队列使用的比较多。

1、栈、队列(单向队列)、优先级队列通常是用来简化某些程序操作的数据结构,而不是主要作为存储数据的。

2、在这些数据结构中,只有一个数据项可以被访问。

3、栈允许在栈顶压入(插入)数据,在栈顶弹出(移除)数据,但是只能访问最后一个插入的数据项,也就是栈顶元素。

4、队列(单向队列)只能在队尾插入数据,对头删除数据,并且只能访问对头的数据。而且队列还可以实现循环队列,它基于数组,数组下标可以从数组末端绕回到数组的开始位置。

5、优先级队列是有序的插入数据,并且只能访问当前元素中优先级别最大(或最小)的元素。

六、学习参考链接

https://www.cnblogs.com/ysocean/p/7921930.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值