Java数据结构和算法(1)之队列
2021-02-18 21:20
1 package com.ys.datastructure; 2 3 public class MyQueue { 4 private Object[] queArray; 5 //队列总大小 6 private int maxSize; 7 //前端 8 private int front; 9 //后端 10 private int rear; 11 //队列中元素的实际数目 12 private int nItems; 13 14 public MyQueue(int s){ 15 maxSize = s; 16 queArray = new Object[maxSize]; 17 front = 0; 18 rear = -1; 19 nItems = 0; 20 } 21 22 //队列中新增数据 23 public void insert(int value){ 24 if(isFull()){ 25 System.out.println("队列已满!!!"); 26 }else{ 27 //如果队列尾部指向顶了,那么循环回来,执行队列的第一个元素 28 if(rear == maxSize -1){ 29 rear = -1; 30 } 31 //队尾指针加1,然后在队尾指针处插入新的数据 32 queArray[++rear] = value; 33 nItems++; 34 } 35 } 36 37 //移除数据 38 public Object remove(){ 39 Object removeValue = null ; 40 if(!isEmpty()){ 41 removeValue = queArray[front]; 42 queArray[front] = null; 43 front++; 44 if(front == maxSize){ 45 front = 0; 46 } 47 nItems--; 48 return removeValue; 49 } 50 return removeValue; 51 } 52 53 //查看对头数据 54 public Object peekFront(){ 55 return queArray[front]; 56 } 57 58 59 //判断队列是否满了 60 public boolean isFull(){ 61 return (nItems == maxSize); 62 } 63 64 //判断队列是否为空 65 public boolean isEmpty(){ 66 return (nItems ==0); 67 } 68 69 //返回队列的大小 70 public int getSize(){ 71 return nItems; 72 } 73 74 } 75 //测试类 76 package com.ys.test; 77 78 import com.ys.datastructure.MyQueue; 79 80 public class MyQueueTest { 81 public static void main(String[] args) { 82 MyQueue queue = new MyQueue(3); 83 queue.insert(1); 84 queue.insert(2); 85 queue.insert(3);//queArray数组数据为[1,2,3] 86 87 System.out.println(queue.peekFront()); //1 88 queue.remove();//queArray数组数据为[null,2,3] 89 System.out.println(queue.peekFront()); //2 90 91 queue.insert(4);//queArray数组数据为[4,2,3] 92 queue.insert(5);//队列已满,queArray数组数据为[4,2,3] 93 } 94 95 }
3、双端队列
双端队列就是一个两端都是结尾或者开头的队列, 队列的每一端都可以进行插入数据项和移除数据项,这些方法可以叫做:
insertRight()、insertLeft()、removeLeft()、removeRight()
如果严格禁止调用insertLeft()和removeLeft()(或禁用右端操作),那么双端队列的功能就和前面讲的栈功能一样。
如果严格禁止调用insertLeft()和removeRight(或相反的另一对方法),那么双端队列的功能就和单向队列一样了。
4、优先级队列
优先级队列(priority queue)是比栈和队列更专用的数据结构,在优先级队列中,数据项按照关键字进行排序,关键字最小(或者最大)的数据项往往在队列的最前面,而数据项在插入的时候都会插入到合适的位置以确保队列的有序。
优先级队列 是0个或多个元素的集合,每个元素都有一个优先权,对优先级队列执行的操作有:
(1)查找
(2)插入一个新元素
(3)删除
一般情况下,查找操作用来搜索优先权最大的元素,删除操作用来删除该元素 。对于优先权相同的元素,可按先进先出次序处理或按任意优先权进行。
这里我们用数组实现优先级队列,这种方法插入比较慢,但是它比较简单,适用于数据量比较小并且不是特别注重插入速度的情况。
后面我们会讲解堆,用堆的数据结构来实现优先级队列,可以相当快的插入数据。
数组实现优先级队列,声明为int类型的数组,关键字是数组里面的元素,在插入的时候按照从大到小的顺序排列,也就是越小的元素优先级越高
1 package com.ys.datastructure; 2 3 public class PriorityQue { 4 private int maxSize; 5 private int[] priQueArray; 6 private int nItems; 7 8 public PriorityQue(int s){ 9 maxSize = s; 10 priQueArray = new int[maxSize]; 11 nItems = 0; 12 } 13 14 //插入数据 15 public void insert(int value){ 16 int j; 17 if(nItems == 0){ 18 priQueArray[nItems++] = value; 19 }else{ 20 j = nItems -1; 21 //选择的排序方法是插入排序,按照从大到小的顺序排列,越小的越在队列的顶端 22 while(j >=0 && value > priQueArray[j]){ 23 priQueArray[j+1] = priQueArray[j]; 24 j--; 25 } 26 priQueArray[j+1] = value; 27 nItems++; 28 } 29 } 30 31 //移除数据,由于是按照大小排序的,所以移除数据我们指针向下移动 32 //被移除的地方由于是int类型的,不能设置为null,这里的做法是设置为 -1 33 public int remove(){ 34 int k = nItems -1; 35 int value = priQueArray[k]; 36 priQueArray[k] = -1;//-1表示这个位置的数据被移除了 37 nItems--; 38 return value; 39 } 40 41 //查看优先级最高的元素 42 public int peekMin(){ 43 return priQueArray[nItems-1]; 44 } 45 46 //判断是否为空 47 public boolean isEmpty(){ 48 return (nItems == 0); 49 } 50 51 //判断是否满了 52 public boolean isFull(){ 53 return (nItems == maxSize); 54 } 55 56 }
insert() 方法,先检查队列中是否有数据项,如果没有,则直接插入到下标为0的单元里,否则,从数组顶部开始比较,找到比插入值小的位置进行插入,并把 nItems 加1.
remove 方法直接获取顶部元素。
优先级队列的插入操作需要 O(N)的时间,而删除操作则需要O(1) 的时间,后面会讲解如何通过 堆 来改进插入时间。
5、总结
我们介绍了队列的三种形式,分别是单向队列、双向队列以及优先级队列。其实大家听名字也可以听得出来他们之间的区别,单向队列遵循先进先出的原则,而且一端只能插入,另一端只能删除。双向队列则两端都可插入和删除,如果限制双向队列的某一段的方法,则可以达到和单向队列同样的功能。最后优先级队列,则是在插入元素的时候进行了优先级别排序,在实际应用中单项队列和优先级队列使用的比较多。后面讲解了堆这种数据结构,我们会用堆来实现优先级队列,改善优先级队列插入元素的时间。
通过前面讲的栈以及本篇讲的队列这两种数据结构,我们稍微总结一下:
①、栈、队列(单向队列)、优先级队列通常是用来简化某些程序操作的数据结构,而不是主要作为存储数据的。
②、在这些数据结构中,只有一个数据项可以被访问。
③、栈允许在栈顶压入(插入)数据,在栈顶弹出(移除)数据,但是只能访问最后一个插入的数据项,也就是栈顶元素。
④、队列(单向队列)只能在队尾插入数据,对头删除数据,并且只能访问对头的数据。而且队列还可以实现循环队列,它基于数组,数组下标可以从数组末端绕回到数组的开始位置。
⑤、优先级队列是有序的插入数据,并且只能访问当前元素中优先级别最大(或最小)的元素。
⑥、这些数据结构都能由数组实现,但是可以用别的机制(后面讲的链表、堆等数据结构)实现。