队列介绍
1) 队列是一个有序列表,可以用数组或是链表来实现。
2) 遵循先入先出(FIFO)的原则。即:先存入队列的数据,要先取出。后存入的要后取出
3) 示意图:(使用数组模拟队列示意图)
数组模拟队列思路
- 队列本身是有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如下图, 其中 maxSize 是该队列的最大容量
- 因为队列的输出、输入是分别从前后端来处理,因此需要两个变量 front 及 rear 分别记录队列前后端的下标
- front 会随着数据输出而改变,而 rear 则是随着数据输入而改变
- 当我们将数据存入队列时称为”addQueue”,addQueue 的处理需要有两个步骤:
- 将尾指针往后移:rear+1 。 当 front == rear 【空】
- 若尾指针 rear 小于队列的最大下标 maxSize-1,则将数据存入 rear 所指的数组元素中,否则无法存入数据。当rear == maxSize - 1[队列满]
普通队列代码实现
1. class arrayqueue { 2. private int maxSize;//定义队列的最大长度 3. private int front;//队列头 4. private int rear;//队列尾 5. private int[] arr;//用于存储数据 6. 7. public arrayqueue(int maxSize) { 8. this.maxSize = maxSize; 9. this.arr = new int[maxSize]; 10. this.front = -1;//指向队列头部,分析出front是指向队列头的第一个数据(最早加进数组的) 11. this.rear = -1;//指向队列尾部,分析出rear指向队列最后一个数据(最新加进数组的) 12. } 13. 14. /** 15. * 判断队列是否为满 16. * 17. * @return 18. */ 19. public boolean isFull() { 20. return rear == maxSize - 1; 21. } 22. 23. /** 24. * 判断队列是否为空 25. * 26. * @return 27. */ 28. public boolean isEmpty() { 29. return front == rear; 30. } 31. 32. /** 33. * 数据入队列 34. * 35. * @param data 36. */ 37. public void addQueue(int data) { 38. if (isFull()) { 39. throw new RuntimeException("队列已满。"); 40. } 41. rear++;//rear后移 42. arr[rear] = data; 43. } 44. 45. /** 46. * 数据出队列 47. * 48. * @return arr[front] 49. */ 50. public int getQueue() { 51. if (isEmpty()) { 52. throw new RuntimeException("队列为空。"); 53. } 54. front++;//front后移 55. return arr[front]; 56. } 57. 58. /** 59. * 获取队列第一个元素 60. * 61. * @return 62. */ 63. public int headQueue() { 64. if (isEmpty()) { 65. throw new RuntimeException("队列为空。"); 66. } 67. return arr[front + 1]; 68. } 69. }
普通队列类的问题及优化
问题分析
1) 目前数组使用一次就不能用, 没有达到复用的效果
2) 解决方案:将这个数组使用算法,改进成一个环形的队列 取模:%
数组模拟环形队列
对前面的数组模拟队列的优化,充分利用数组. 因此将数组看做是一个环形的。(通过取模的方式来实现即可)
- 分析说明:
1) 尾索引的下一个为头索引时表示队列满,即将队列容量空出一个作为约定,这个在做判断队列满的 时候需要注意 (rear + 1) % maxSize == front [满]
2) rear == front [空]
3)思路分析:
- front变量的含义做一个调整:front指向队列的第一个元素,也就是说arr[front]就是队列的第一个元素,front的初始值为0.
- rear变量的含义做一个调整:rear指向队列的最后一个元素的后一个位置,因为希望空出一个空间作为约定,rear的初始值为0.
- 当队列满时,条件是(rear+1)%MaxSize==front
- 当队列为空时,条件为rear==front
- 当我们这样分析,队列中有效的数据个数为:(rear+MaxSize-front)%MaxSize
- 我们就可以在原来队列的基础上得到一个环形队列
环形队列代码实现
1. class criclequeue { 2. private int maxSize;//定义队列的最大长度 3. //front指向队列的第一个元素,也就是说arr[front]就是队列的第一个元素,front的初始值为0. 4. private int front; 5. //rear指向队列的最后一个元素的后一个位置,因为希望空出一个空间作为约定,rear的初始值为0. 6. private int rear; 7. private int[] arr;//用于存储数据 8. public criclequeue(int maxSize) { 9. this.maxSize = maxSize; 10. this.arr = new int[maxSize]; 11. } 12. 13. /** 14. * 判断队列是否为满 15. * 16. * @return 17. */ 18. public boolean isFull() { 19. return (rear + 1) % maxSize == front; 20. } 21. 22. /** 23. * 判断队列是否为空 24. * 25. * @return 26. */ 27. public boolean isEmpty() { 28. return front == rear; 29. } 30. 31. /** 32. * 数据入队列 33. * 34. * @param data 35. */ 36. public void addQueue(int data) { 37. if (isFull()) { 38. throw new RuntimeException("队列已满。"); 39. } 40. arr[rear] = data; 41. rear = (rear + 1) % maxSize;//将rear后移,这里必须考虑取模 42. } 43. 44. /** 45. * 数据出队列 46. * 47. * @return arr[front] 48. */ 49. public int getQueue() { 50. if (isEmpty()) { 51. throw new RuntimeException("队列为空。"); 52. } 53. int data = arr[front]; 54. front = (front + 1) % maxSize; 55. return data; 56. } 57. 58. /** 59. * 获取队列第一个元素 60. * 61. * @return 62. */ 63. public int headQueue() { 64. if (isEmpty()) { 65. throw new RuntimeException("队列为空。"); 66. } 67. return arr[front]; 68. } 69. 70. /** 71. * 遍历队列 72. */ 73. public void showQueue() { 74. if (isEmpty()) { 75. throw new RuntimeException("队列为空"); 76. } 77. for (int i = front; i < front + this.size(); i++) { 78. System.out.print(arr[i % maxSize] + " "); 79. } 80. System.out.println(); 81. } 82. 83. /** 84. * 获取队列中元素个数 85. */ 86. public int size() { 87. return (rear + maxSize - front) % maxSize; 88. } 89. } 来自 <http://www.planetb.ca/projects/syntaxHighlighter/popup.php>