前面一篇博客我们讲解了并不像数组一样完全作为存储数据功能,而是作为构思算法的辅助工具的数据结构——栈,本篇博客我们介绍另外一个这样的工具——队列。栈是后进先出,而队列刚好相反,是先进先出。

回到顶部

1、队列的基本概念

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

  队列的数据元素又称为队列元素。在队列中插入一个队列元素称为入队,从队列中删除一个队列元素称为出队。因为队列只允许在一端插入,在另一端删除,所以只有最早进入队列的元素才能最先从队列中删除,故队列又称为先进先出(FIFO—first in first out)线性表。

  比如我们去电影院排队买票,第一个进入排队序列的都是第一个买到票离开队列的人,而最后进入排队序列排队的都是最后买到票的。

  在比如在计算机操作系统中,有各种队列在安静的工作着,比如打印机在打印列队中等待打印。

  队列分为:

  ①、单向队列(Queue):只能在一端插入数据,另一端删除数据。

  ②、双向队列(Deque):每一端都可以进行插入数据和删除数据操作。

  这里我们还会介绍一种队列——优先级队列,优先级队列是比栈和队列更专用的数据结构,在优先级队列中,数据项按照关键字进行排序,关键字最小(或者最大)的数据项往往在队列的最前面,而数据项在插入的时候都会插入到合适的位置以确保队列的有序。

回到顶部

2、Java模拟单向队列实现

  在实现之前,我们先看下面几个问题:

  ①、与栈不同的是,队列中的数据不总是从数组的0下标开始的,移除一些队头front的数据后,队头指针会指向一个较高的下标位置,如下图:

  

  ②、我们再设计时,队列中新增一个数据时,队尾的指针rear 会向上移动,也就是向下标大的方向。移除数据项时,队头指针 front 向上移动。那么这样设计好像和现实情况相反,比如排队买电影票,队头的买完票就离开了,然后队伍整体向前移动。在计算机中也可以在队列中删除一个数之后,队列整体向前移动,但是这样做效率很差。我们选择的做法是移动队头和队尾的指针。

  ③、如果向第②步这样移动指针,相信队尾指针很快就移动到数据的最末端了,这时候可能移除过数据,那么队头会有空着的位置,然后新来了一个数据项,由于队尾不能再向上移动了,那该怎么办呢?如下图:

  

  为了避免队列不满却不能插入新的数据,我们可以让队尾指针绕回到数组开始的位置,这也称为“循环队列”。

  

  弄懂原理之后,Java实现代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

package com.ys.datastructure;

public class MyQueue {

    private Object[] queArray;

    //队列总大小

    private int maxSize;

    //前端

    private int front;

    //后端

    private int rear;

    //队列中元素的实际数目

    private int nItems;

    

    public MyQueue(int s){

        maxSize = s;

        queArray = new Object[maxSize];

        front = 0;

        rear = -1;

        nItems = 0;

    }

    

    //队列中新增数据

    public void insert(int value){

        if(isFull()){

            System.out.println("队列已满!!!");

        }else{

            //如果队列尾部指向顶了,那么循环回来,执行队列的第一个元素

            if(rear == maxSize -1){

                rear = -1;

            }

            //队尾指针加1,然后在队尾指针处插入新的数据

            queArray[++rear] = value;

            nItems++;

        }

    }

    

    //移除数据

    public Object remove(){

        Object removeValue = null ;

        if(!isEmpty()){

            removeValue = queArray[front];

            queArray[front] = null;

            front++;

            if(front == maxSize){

                front = 0;

            }

            nItems--;

            return removeValue;

        }

        return removeValue;

    }

    

    //查看对头数据

    public Object peekFront(){

        return queArray[front];

    }

    

    

    //判断队列是否满了

    public boolean isFull(){

        return (nItems == maxSize);

    }

    

    //判断队列是否为空

    public boolean isEmpty(){

        return (nItems ==0);

    }

    

    //返回队列的大小

    public int getSize(){

        return nItems;

    }

    

}

  测试:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

package com.ys.test;

import com.ys.datastructure.MyQueue;

public class MyQueueTest {

    public static void main(String[] args) {

        MyQueue queue = new MyQueue(3);

        queue.insert(1);

        queue.insert(2);

        queue.insert(3);//queArray数组数据为[1,2,3]

        

        System.out.println(queue.peekFront()); //1

        queue.remove();//queArray数组数据为[null,2,3]

        System.out.println(queue.peekFront()); //2

        

        queue.insert(4);//queArray数组数据为[4,2,3]

        queue.insert(5);//队列已满,queArray数组数据为[4,2,3]

    }

}

  

回到顶部

3、双端队列

  双端队列就是一个两端都是结尾或者开头的队列, 队列的每一端都可以进行插入数据项和移除数据项,这些方法可以叫做:

  insertRight()、insertLeft()、removeLeft()、removeRight()

  如果严格禁止调用insertLeft()和removeLeft()(或禁用右端操作),那么双端队列的功能就和前面讲的栈功能一样。

  如果严格禁止调用insertLeft()和removeRight(或相反的另一对方法),那么双端队列的功能就和单向队列一样了。

回到顶部

4、优先级队列

  优先级队列(priority queue)是比栈和队列更专用的数据结构,在优先级队列中,数据项按照关键字进行排序,关键字最小(或者最大)的数据项往往在队列的最前面,而数据项在插入的时候都会插入到合适的位置以确保队列的有序。

  优先级队列 是0个或多个元素的集合,每个元素都有一个优先权,对优先级队列执行的操作有:

  (1)查找

  (2)插入一个新元素

  (3)删除

  一般情况下,查找操作用来搜索优先权最大的元素,删除操作用来删除该元素 。对于优先权相同的元素,可按先进先出次序处理或按任意优先权进行。

  这里我们用数组实现优先级队列,这种方法插入比较慢,但是它比较简单,适用于数据量比较小并且不是特别注重插入速度的情况。

  后面我们会讲解堆,用堆的数据结构来实现优先级队列,可以相当快的插入数据。

  数组实现优先级队列,声明为int类型的数组,关键字是数组里面的元素,在插入的时候按照从大到小的顺序排列,也就是越小的元素优先级越高。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

package com.ys.datastructure;

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;//-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) 的时间,后面会讲解如何通过 堆 来改进插入时间。

回到顶部

5、总结

  本篇博客我们介绍了队列的三种形式,分别是单向队列、双向队列以及优先级队列。其实大家听名字也可以听得出来他们之间的区别,单向队列遵循先进先出的原则,而且一端只能插入,另一端只能删除。双向队列则两端都可插入和删除,如果限制双向队列的某一段的方法,则可以达到和单向队列同样的功能。最后优先级队列,则是在插入元素的时候进行了优先级别排序,在实际应用中单项队列和优先级队列使用的比较多。后面讲解了堆这种数据结构,我们会用堆来实现优先级队列,改善优先级队列插入元素的时间。

  通过前面讲的栈以及本篇讲的队列这两种数据结构,我们稍微总结一下:

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

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

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

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

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

  ⑥、这些数据结构都能由数组实现,但是可以用别的机制(后面讲的链表、堆等数据结构)实现。

作者:YSOcean

出处:http://www.cnblogs.com/ysocean/

Java数据结构和算法(五)——队列相关推荐

  1. JAVA数据结构与算法【队列、数组模拟(环形)队列】

    队列 使用场景:排队 队列介绍 队列是一个有序列表,可以用数组或是链表来实现. 遵循先入先出的原则.即:先存入队列的数据,要先取出.后存入的要后取出 示意图:(使用数组模拟队列示意图) 数组模拟队列 ...

  2. Java数据结构与算法:队列

    1. 队列的介绍 队列 (Queue)是另一种限定性的线性表,它只允许在表的一端插入元素,而在另一端删除元素,所以队列具有先进先出(Fist In Fist Out, 缩写为FIFO)的特性.在队列中 ...

  3. Java数据结构与算法-环形队列

    队列介绍 队列是一个有序列表,可以用数组或是链表来实现 遵循先入先出的原则.即:先存入队列的数据,要先取出.后存入的数据要后取出 数组模拟环形队列 分析说明: 尾索引rear的下一个为头索引时表示队列 ...

  4. java数据结构与算法之(Queue)队列设计与实现

    [版权申明]转载请注明出处(请尊重原创,博主保留追究权) http://blog.csdn.net/javazejian/article/details/53375004 出自[zejian的博客] ...

  5. java数据结构与算法之顺序表与链表深入分析

    转载请注明出处(万分感谢!): http://blog.csdn.net/javazejian/article/details/52953190 出自[zejian的博客] 关联文章: java数据结 ...

  6. java数据结构与算法之双链表设计与实现

    转载请注明出处(万分感谢!): http://blog.csdn.net/javazejian/article/details/53047590 出自[zejian的博客] 关联文章: java数据结 ...

  7. java数据结构 队列_Java数据结构与算法[原创]——队列

    声明:码字不易,转载请注明出处,欢迎文章下方讨论交流. 前言:Java数据结构与算法专题会不定时更新,欢迎各位读者监督.本文介绍数据结构中的队列(queue)的概念.存储结构.队列的特点,文末给出ja ...

  8. Java 数据结构和算法(十五):无权无向图

    Java数据结构和算法(十五)--无权无向图 前面我们介绍了树这种数据结构,树是由n(n>0)个有限节点通过连接它们的边组成一个具有层次关系的集合,把它叫做"树"是因为它看起 ...

  9. 用数组实现环形队列(尚硅谷Java数据结构与算法)

    整个代码在文章最后面,gitee地址:java数据结构与算法: 自己学习与练习数据结构的仓库https://gitee.com/ALi_L/javaDataStructurs.git 环形队列的难点如 ...

  10. Java数据结构和算法(六)——前缀、中缀、后缀表达式

    前面我们介绍了三种数据结构,第一种数组主要用作数据存储,但是后面的两种栈和队列我们说主要作为程序功能实现的辅助工具,其中在介绍栈时我们知道栈可以用来做单词逆序,匹配关键字符等等,那它还有别的什么功能吗 ...

最新文章

  1. 076_浏览器对象模型
  2. boost之对象池使用实例
  3. 如何避免订单重复支付?
  4. vivo分屏_vivo分屏+Jovi语音助手!让你找到解题新思路
  5. 前端学习(3101):vue+element今日头条管理-react简介2
  6. 如何配置x225/x235/x335/x345的LSI SCSI卡实现RAID-1功能
  7. 做出产品不难,做好产品必须高手
  8. JavaSE环境搭建
  9. 【雷达】一维和二维自适应波束形成(DBF))DBF附matlab代码
  10. 如何查看secure crt的登录密码
  11. 使用ffmpeg解析mp4文件得到音频和视频数据
  12. 系统设计(二)如何写技术设计文档
  13. java gwt开发_java – 如何启动GWT超级开发模式
  14. ucharts 柱状图圆角_调整柱状图圆角弧度
  15. JavaScript 扁平化数组转成Tree
  16. 【定位问题】基于matlab chan算法、fang算法、taylor算法求解目标定位问题【含Matlab源码 2135期】
  17. dad my_My dad英语绘本.ppt
  18. 安卓镜像刻录软件_Android烧录工具-安卓烧录工具下载v6.0.43 官方最新版-西西软件下载...
  19. Java-Collection的子接口-List集合
  20. QTextEdit设置可输入字符字节限制

热门文章

  1. hbase windows安装
  2. 分组密码的工作模式--wiki
  3. Can't access RabbitMQ web management interface after fresh install
  4. 用C语言实现Ping程序功能---转
  5. 【采用】干货请收好:终于有人把用户画像的流程、方法讲明白了
  6. uni-app 使用vue的语法+小程序的标签和API。
  7. 借由AI招聘软件,这位CEO 48h 内从4000名求职者中锁定那一位
  8. Spring5源码 - 07 Spring Bean 生命周期流程 源码解读02
  9. ubuntu20.04下安装Docker和NVIDIA Container Toolkit教程
  10. linux挂载盘符扫描,Linux下挂载ISCSI的盘符问题