队列
上一篇随笔记录了一个不单单用来记录数据的,更多的用来作为构思算法的辅助工具的一种数据结构 栈,今天我们来介绍另外一种 队列。
首先,介绍一下队列的基本概念
队列(queue)是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。
队列的数据元素又称为队列元素。在队列中插入一个队列元素称为入队,从队列中删除一个队列元素称为出队。因为队列只允许在一端插入,在另一端删除,所以只有最早进入队列的元素才能最先从队列中删除,故队列又称为先进先出(FIFO—first in first out)线性表。
比如我们去电影院排队买票,第一个进入排队序列的都是第一个买到票离开队列的人,而最后进入排队序列排队的都是最后买到票的。
在比如在计算机操作系统中,有各种队列在安静的工作着,比如打印机在打印列队中等待打印。
队列分为:
①、单向队列(Queue):只能在一端插入数据,另一端删除数据。
②、双向队列(Deque):每一端都可以进行插入数据和删除数据操作。
这里我们还会介绍一种队列——优先级队列,优先级队列是比栈和队列更专用的数据结构,在优先级队列中,数据项按照关键字进行排序,关键字最小(或者最大)的数据项往往在队列的最前面,而数据项在插入的时候都会插入到合适的位置以确保队列的有序。
单向队列
单向队列的实现,很大程度上是根据一种“循环队列”的原理进行操作。也就是说,如果我们的队尾指针指向队列最大值处,同时之前队列有过删除操作,那么此时的队列并不满,再进行插入操作时,队尾指针回指向队头,进行插入。
我们直接上代码:
package discovery; /** * Author :zhanghong * Date :2019-02-17 16:01. */ public class MyQueue { private Object[] queArray; //队列总大小 private int maxSize; //前端 private int front; //后端 private int rear; //队列中元素的实际数目 private int nItems; public MyQueue(int Size){ maxSize=Size; queArray=new Object[maxSize]; front=0; rear=-1; nItems=0; } //返回队列的大小 public int getSize(){ return nItems; } //判断队列是否为空 public boolean isEmpty(){ return (nItems ==0); } //判断队列是否满了 public boolean isFull(){ return (nItems == maxSize); } //查看队头数据 public Object getFront(){ return queArray[front]; } //删除数据 public Boolean delete(){ if(!isEmpty()){ queArray[front]=null; front++; if(front==maxSize){ front=0; } nItems--; } return false; } //增加数据 public void add(Object item){ if(isFull()){ System.out.println("队列已满"); }else { if(rear==maxSize-1){ rear=-1; } queArray[++rear]=item; nItems++; } } }
测试一下:
package discovery; import static discovery.ChoiceSort.display; import static discovery.ChoiceSort.sort; /** * Author :zhanghong * Date :2018-08-13 15:00. */ public class Run { public static void main(String[] args) { // MyThread t1 = new MyThread(); // MyThread t2 = new MyThread(); // MyThread t3 = new MyThread(); // t1.start(); // t2.start(); // t3.start(); //region 数组 // MyArray myArray=new MyArray(4); // myArray.add(1); // myArray.add(2); // myArray.add(3); // myArray.add(4); // myArray.display(); // int i=myArray.getelement(0); // System.out.println(i); // myArray.delete(4); // myArray.display(); // myArray.update(3,33); // myArray.display(); //endregion //region 冒泡 // int[] array = {4,2,8,9,5,7,6,1,3}; // //未排序数组顺序为 // System.out.println("未排序数组顺序为:"); // display(array); // System.out.println("-----------------------"); // array = sort(array); // System.out.println("-----------------------"); // System.out.println("经过冒泡排序后的数组顺序为:"); // display(array); //endregion //region 选择排序 // int[] array = {4,2,8,9,5,7,6,1,3}; // //未排序数组顺序为 // System.out.println("未排序数组顺序为:"); // display(array); // System.out.println("-----------------------"); // array = sort(array); // System.out.println("-----------------------"); // System.out.println("经过选择排序后的数组顺序为:"); // display(array); //endregion //region 插入排序 //endregion //region 栈1 // ArrayStack stack = new ArrayStack(3); // stack.push(1); // //System.out.println(stack.peek()); // stack.push(2); // stack.push(3); // stack.push("abc"); // System.out.println(stack.getTop()); // stack.pop(); // stack.pop(); // stack.pop(); // System.out.println(stack.getTop()); //endregion //region 栈2 // ArrayStack stack = new ArrayStack(); // String str = "how are you"; // char[] cha = str.toCharArray(); // for(char c : cha){ // stack.push(c); // } // while(!stack.isEmpty()){ // System.out.print(stack.pop()); // } //endregion //region 栈3 // ArrayStack stack = new ArrayStack(3); // String str = "12<a[b{c}]>"; // char[] cha = str.toCharArray(); // for(char c : cha){ // switch (c) { // case '{': // case '[': // case '<': // stack.push(c); // break; // case '}': // case ']': // case '>': // if(!stack.isEmpty()){ // char ch = stack.pop().toString().toCharArray()[0]; // if(c=='}' && ch != '{' // || c==']' && ch != '[' // || c==')' && ch != '('){ // System.out.println("Error:"+ch+"-"+c); // } // } // break; // default: // break; // } // } //endregion //region 队列 MyQueue queue = new MyQueue(3); queue.add(1); queue.add(2); queue.add(3);//queArray数组数据为[1,2,3] System.out.println(queue.getFront()); //1 queue.delete();//queArray数组数据为[null,2,3] System.out.println(queue.getFront()); //2 queue.add(4);//queArray数组数据为[4,2,3] queue.add(5);//队列已满,queArray数组数据为[4,2,3] //endregion } }
返回结果:
1
2
队列已满
双向队列:
顾名思义,就是一个两端都可以进行删除和插入操作的队列,例如,在定义的时候,我们可以定义insertRight()、insertLeft()、removeLeft()、removeRight()等方法,
如果严格禁止调用insertLeft()和removeLeft()(或禁用右端操作),那么双端队列的功能就和前面讲的栈功能一样。
如果严格禁止调用insertLeft()和removeRight(或相反的另一对方法),那么双端队列的功能就和单向队列一样了。
优先级队列:
优先级队列(priority queue)是比栈和队列更专用的数据结构,在优先级队列中,数据项按照关键字进行排序,关键字最小(或者最大)的数据项往往在队列的最前面,而数据项在插入的时候都会插入到合适的位置以确保队列的有序。
我们先用数组来实现一个简单的优先级队列,这样的队列插入数据速度并不快,在数据量不大的情况下是可以的,之后我们学习了堆,用堆来实现优先级队列的插入操作效率会更高,查询时的优先级队列会根据优先权
我们这里先用数组实现一个简单的优先级队列,这里的优先级是值越小,优先级越高,查找和删除都是对优先级高的数据进行
上代码
package discovery; /** * Author :zhanghong * Date :2019-02-24 20:46. */ public class PriorityQue { private int maxsize; private int length; private int[] array; public PriorityQue(int s){ maxsize=s; array=new int[maxsize]; length=0; } //获取优先级最高的元素 public int getTop(){ return array[length-1]; } //判断是否为空 public boolean isEmpty(){ if(length==0){ return true; } return false; } //判断是否已满 public boolean isFull(){ if(length==maxsize){ return true; } return false; } public void insert(int value){ int j; if(length==0){ array[length]=value; length++; }else { //数组下标 j=length-1; while (j>=0&&value>array[j]){ array[j+1]=array[j]; j--; } array[j+1] = value; length++; } } //删除遵循先进先出原则 public int remove(){ int k = length -1; int value = array[k]; array[k] = -1;//-1表示这个位置的数据被移除了 length--; return value; } }
总结:
1、栈、队列等通常是对数据访问的优化,而不是作为数据的存储
2、栈、队列每次只能访问单个对象
3、栈允许在栈顶压入数据,在栈顶弹出数据;也只能访问栈顶数据。
4、队列(单向队列)只能在队尾插入数据,对头删除数据,并且只能访问对头的数据。而且队列还可以实现循环队列,它基于数组,数组下标可以从数组末端绕回到数组的开始位置。
5、优先级队列是有序的插入数据,并且只能访问当前元素中优先级别最大(或最小)的元素。