环形队列(索引从0开始(C语言、C++、Java)、索引从1开始(Matlab))

超、凢脫俗 2022-12-01 15:36 292阅读 0赞

环形队列

  • 综合分析
  • 0索引开始的代码实现(C++)
  • 从1索引开始的代码实现(Matlab)

综合分析

关于数组模拟环形队列的问题,有两点疑问。

  • 为什么用数组模拟?
  • 为什么要有环形队列?

刚开始想用数组模拟队列,因为数组索引方便,使用简单。但是数组模拟队列有几点局限性。数组是一个定长的类型,即一经分配,无法修改长度。但是我们在使用队列的时候,可能需要很多个数据,那么对于队列的长度选取就存在着问题。因此,聪明的人们开始想着用环形队列进行代替,即环岛一样,可以重复利用多余的空间。

那么在使用数组进行环形队列模拟的时候有几点问题需要解决:

1、这个类中需要什么成员变量?

存储该队列的最大数量、front指针位置、rear指针位置、内部数组,在这里我们为了方便,将数组的真实长度为MAXSIZE - 1,即空出一个位置来计算队列满和队列空的条件。
具体如下图所示:
在这里插入图片描述

2、front 和 rear 位置确定?

  • 对于起始索引为 0 ,如C语言、c++、JAVA、Python需要从0开始进行,这时候我们需要将
    front 和 rear 初始位置都是 0 ,front 指向当前数组的首元素位置,rear 指向当前队列末尾元素的下一个元素
    即先赋值再进行计算,这点必须要注意。
  • 对于起始索引为 1 的数组,我们可以将 front 和 rear 起始位置分别设为0和0,或者是1和1。不同的是我们需要对不同的处理方法有不同的逻辑操作,我们需要对0初始化这种操作先进行计算下一个位置该往哪里放,对1初始化这种操作先进性赋值再进行下一个位置的计算,这点在程序中也有体现。不同的只是先计算还是先进行赋值。 需要注意的是:起始索引是1的这种情况有一个比较关心的问题是下一跳的位置,需要添加一个判断条件,否则永远无法到达 MAXSIZE 的位置。

3、队列中真实大小如何计算?

两种情况:
1、如果rear 比 front 大,那么真实大小为 rear - front。
2、如果rear 比 front 小,那么真实大小是 maxSize - front + rear。
综合一下,可以写成一个表达式为:
(maxSize - front + rear)% maxSize

4、队列空和满的条件是什么呢?

空的条件:front == rear
满的条件:(rear + 1) % maxSize == front

5、下一跳的条件是什么?
rear =(rear + 1) % maxSize;
front=(front+ 1) % maxSize;
需要注意的是上面提及的那个问题,如果索引从1开始,则需要考虑一个问题是如果下一跳是 0, 需要给它过滤掉。
需要注意的是:maxSize中我们约定了一个空余位置,目的是什么呢?
因为如果不约定一个空余位置,队列满和队列空的条件相同。那么有其他的解决办法吗?可以通过设置flag变量的方法来解决,但是其逻辑不清晰。遂取后者。

0索引开始的代码实现(C++)

  1. #include <iostream>
  2. using namespace std;
  3. class CircleArray {
  4. private:
  5. int maxSize; //设置最大值,注意
  6. int front; //头部指针初始化为0
  7. int rear; //尾部指针初始化为0
  8. int *list;
  9. public:
  10. //进行初始化
  11. CircleArray(int size) {
  12. maxSize = size;
  13. front = 0;
  14. rear = 0;
  15. list = new int[size];
  16. }
  17. //判断是否为循环队列是否为空
  18. bool isEmpty() {
  19. return front == rear;
  20. }
  21. //判断是否已经满
  22. bool isFull() {
  23. return (rear + 1) % maxSize == front;
  24. }
  25. //添加元素 返回值返回的是添加的元素下一个元素的下标
  26. int add(int n) {
  27. if (isFull())
  28. {
  29. cout << "队列已经满了" << endl;
  30. return -1;
  31. }
  32. list[rear] = n;
  33. rear = (rear + 1) % maxSize;
  34. return rear;
  35. }
  36. //弹出元素 返回删除的元素的值
  37. int get() {
  38. if (isEmpty())
  39. {
  40. cout << "队列是空的,弹出失败" << endl;;
  41. return -1;
  42. }
  43. int temp = list[front];
  44. front = (front + 1) % maxSize;
  45. return temp;
  46. }
  47. //遍历队列
  48. void show() {
  49. if (isEmpty())
  50. {
  51. cout << "队列为空,无法进行遍历" << endl;;
  52. return;
  53. }
  54. for (int i = front; i < front + size(); i++) {
  55. printf("arr[%d]:%d\n", i % maxSize, list[i % maxSize]);
  56. }
  57. }
  58. //返回队列的有效元素的大小
  59. int size() {
  60. return (maxSize - front + rear) % maxSize;
  61. }
  62. //返回头部的元素
  63. int head() {
  64. if (isEmpty())
  65. {
  66. cout << "队列是空的,无法返回头部元素" << endl;;
  67. return -1;
  68. }
  69. return list[front];
  70. }
  71. };
  72. int main(int argc, char* argv[]) {
  73. CircleArray* circle = new CircleArray(4);
  74. char c;
  75. bool loop = true;
  76. while (loop)
  77. {
  78. cout << "s(show):显示所有数据 \t" << "a(add):添加元素\n"
  79. << "g(get):弹出队列首元素\t" << "e(isEmpty):判断队列是否为空\n"
  80. << "f(isFull):判断队列是否为满\t" << "x(exit):退出程序\n"
  81. << "h(head):返回头元素" << endl;
  82. cin >> c;
  83. switch (c)
  84. {
  85. case 's':
  86. try {
  87. circle->show();
  88. }
  89. catch (string a) {
  90. if (a == "队列为空")
  91. {
  92. cout << "队列为空,无法进行显示" << endl;
  93. }
  94. }
  95. break;
  96. case 'a':
  97. cout << "请输出需要插入的数据:" << endl;
  98. try {
  99. int a;
  100. cin >> a;
  101. circle->add(a);
  102. }
  103. catch (string e) {
  104. if (e == "队列已经满了")
  105. {
  106. cout << "队列已经满了,无法添加元素" << endl;
  107. }
  108. }
  109. break;
  110. case 'e':
  111. if (circle->isEmpty())
  112. {
  113. cout << "队列为空" << endl;
  114. }
  115. else
  116. {
  117. cout << "队列非空" << endl;
  118. }
  119. break;
  120. case 'f':
  121. if (circle->isFull()) {
  122. cout << "队列是满的" << endl;
  123. }
  124. else
  125. {
  126. cout << "队列是空的" << endl;
  127. }
  128. break;
  129. case 'h':
  130. printf("头元素是:%d\n", circle->head());
  131. break;
  132. case 'x':
  133. loop = false;
  134. break;
  135. case 'g':
  136. try {
  137. circle->get();
  138. }
  139. catch (string e) {
  140. if (e == "队列是空的") {
  141. cout << "队列是空的,无法弹出元素" << endl;
  142. }
  143. }
  144. break;
  145. default:
  146. break;
  147. }
  148. }
  149. return 0;
  150. }

从1索引开始的代码实现(Matlab)

这里运用到了 Matlab 中的面向对象编程。需要注意的是,如果进行

  1. classdef CircleArr
  2. properties
  3. m_front
  4. m_rear
  5. m_MAXSIZE
  6. m_arr
  7. end
  8. methods
  9. function this = CircleArr(front,rear, MAXSIZE)
  10. if nargin == 3
  11. this.m_front = front;
  12. this.m_rear = rear;
  13. this.m_MAXSIZE = MAXSIZE;
  14. this.m_arr = linspace(0, 0, MAXSIZE);
  15. end
  16. end
  17. function full = is_full(this)
  18. if (mod((this.m_rear + 1) , this.m_MAXSIZE) == this.m_front)
  19. full = true;
  20. else
  21. full = false;
  22. end
  23. end
  24. function newobj = add1(this, value)
  25. if this.is_full()
  26. newobj = this;
  27. return;
  28. else
  29. this.m_arr(this.m_rear) = value;
  30. this.m_rear = mod((this.m_rear + 1) , this.m_MAXSIZE);
  31. if this.m_rear == 0
  32. this.m_rear = this.m_MAXSIZE;
  33. end
  34. end
  35. newobj = this;
  36. end
  37. function m_display(this)
  38. display(this.m_MAXSIZE)
  39. display(this.m_arr);
  40. end
  41. function empty = is_empty(this)
  42. if this.m_front == this.m_rear
  43. empty = true;
  44. else
  45. empty = false;
  46. end
  47. end
  48. function [newobj,getNum] = get(this)
  49. if is_empty(this)
  50. getNum = '无法获取,已经空了';
  51. else
  52. getNum = this.m_arr(this.m_front);
  53. this.m_front = mod((this.m_front + 1),this.m_MAXSIZE);
  54. if this.m_front == 0
  55. this.m_front = this.m_MAXSIZE;
  56. end
  57. end
  58. newobj = this;
  59. end
  60. end
  61. end

发表评论

表情:
评论列表 (有 0 条评论,292人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Java学习 0.1开始(一)

      写在前面: 之前从事过.NET,C,C++相关的开发,Java是一直没有学习的新领域。最近,应工作需要,开始学习Java相关的知识。又因为新公司并没有完整的系统架构,所