• 循环队列----数据结构


    缘由

    在队列的顺序存储中,采用第二种出队的方式,将头指针 +1 ,可以避免元素的移动,但是这样也出现了一个问题 "假溢出" ,如图:

    当出现这种情况时:头指针和尾指针都指向了不可访问的地方(越界了),就无法在插入(入队)了,队列的空间还空着,却无法利用,这造成了空间的浪费。

    为了使用到完全的空间(利用前面的空间),可以使用循环队列。(红色代表已经利用的空间)

    如图,当 tail 的值为5时,他应该指向下标为 0 的空间,也就是将 tail 赋值为0。这样队列就首尾相连,变成了循环队列。

    由于 头指针和尾指针的范围是 [ 0 , MAX_SIZE -1 ] ,一旦等于MAX_SIZE,就变为0,所以可以使用到取模操作,每次移动完,再对 MAX_SIZE 取模。

    队列的判空判满

    那出现下面这种情况还可以插入元素吗?如下图:

    假如可以的话,再插入一个元素,那 tail +1 就为 3 ,这时会发现一个问题:该如何判断队列为空,如何判断队列满了,有些困难。

    所以这种情况就无法再插入元素了,我们能使用到的空间只有 MAX_SIZE-1 个,其中一块空间是为了方便判断队列的状态,并不保存任何数据。

     判断队列为空的条件是:头指针与尾指针指向同一个位置;判断队列为满的条件是:尾指针的后一位是头指针。

     tail == head 为判空条件,结合之前的移动问题,所以不是 tail + 1 == head,而是 (tail + 1) % MAX_SIZE == head 为判满条件

    如图( front 是头指针,rear 是尾指针):

    获取元素个数

    顺序队列中求元素个数的方法为 尾指针减去头指针 ,可是现在有两种情况:

    一、头指针在尾指针的前面(tail >= head):元素个数为 tail - head

    二、尾指针在头指针的前面(tail

    取模操作可以将两种情况统一为一种:元素个数为 (head - tail + MAX_SIZE) % MAX_SIZE

    具体实现

    就是顺序队列改动了一下需要注意的点。

    1. #include <iostream>
    2. using namespace std;
    3. //循环队列的定义
    4. #define MAX_SIZE 5
    5. typedef int DateElem;
    6. typedef struct Queue
    7. {
    8. DateElem date[MAX_SIZE];
    9. int head; //头指针
    10. int tail; //尾指针
    11. }squeue;
    12. //初始化循环队列
    13. void InitQueue(squeue* sq)
    14. {
    15. if (!sq) return;
    16. sq->head = 0;
    17. sq->tail = 0;
    18. }
    19. //判断循环队列是否满了
    20. bool IsFull(squeue* sq)
    21. {
    22. if (!sq) return false;
    23. if ((sq->tail+1)%MAX_SIZE == sq->head) //*
    24. {
    25. return true;
    26. }
    27. else
    28. {
    29. return false;
    30. }
    31. }
    32. //判断循环队列是否为空
    33. bool IsEmpty(squeue* sq)
    34. {
    35. if (!sq) return false;
    36. if (sq->head == sq->tail)
    37. {
    38. return true;
    39. }
    40. else
    41. {
    42. return false;
    43. }
    44. }
    45. //循环队列入队
    46. bool EnterQueue(squeue* sq, DateElem e)
    47. {
    48. if (IsFull(sq))
    49. {
    50. cout << "无法插入元素" << e << ",队列已满。" << endl;
    51. return false;
    52. }
    53. sq->date[sq->tail] = e;
    54. sq->tail = (sq->tail + 1) % MAX_SIZE; //*
    55. return true;
    56. }
    57. //循环队列出队
    58. bool PopQueue(squeue* sq, DateElem* date)
    59. {
    60. if (!sq || IsEmpty(sq))
    61. {
    62. return false;
    63. }
    64. *date = sq->date[sq->head];
    65. sq->head = (sq->head + 1) % MAX_SIZE; //*
    66. return true;
    67. }
    68. //打印队列
    69. bool PrintQueue(squeue* sq)
    70. {
    71. if (!sq) return false;
    72. for (int i = sq->head; i != sq->tail; i = (i+1) %MAX_SIZE) //*
    73. {
    74. printf("%d ", sq->date[i]);
    75. }
    76. return true;
    77. }
    78. //获取队首元素
    79. int GetHeadElem(squeue* sq)
    80. {
    81. if (!sq || IsEmpty(sq)) return 0;
    82. return sq->date[sq->head];
    83. }
    84. //销毁(清空)队列
    85. bool DestoryQueue(squeue* sq)
    86. {
    87. if (!sq) return false;
    88. sq->head = 0;
    89. sq->tail = 0;
    90. return true;
    91. }
    92. //获取队列长度
    93. int GetLength(squeue* sq)
    94. {
    95. if (!sq) return 0;
    96. return (sq->tail - sq->head + MAX_SIZE) % MAX_SIZE; //*
    97. }
    98. int main(void)
    99. {
    100. squeue* sq = new squeue;
    101. DateElem* s = new DateElem;
    102. InitQueue(sq);
    103. DateElem e = 0;
    104. int choose = -1;
    105. while (choose != 0)
    106. {
    107. cout << "1.入队" << endl
    108. << "2.出队" << endl
    109. << "3.打印队列" << endl
    110. << "4.获取队首元素" << endl
    111. << "5.获取队列长度" << endl
    112. << "6.销毁队列" << endl
    113. << "0.退出" << endl;
    114. cin >> choose;
    115. switch (choose)
    116. {
    117. case 1:
    118. cout << "请输入要入队的元素:";
    119. cin >> e;
    120. if (EnterQueue(sq, e))
    121. {
    122. cout << "入队成功" << endl;
    123. }
    124. else
    125. {
    126. cout << "入队失败" << endl;
    127. }
    128. break;
    129. case 2:
    130. if (PopQueue(sq, s))
    131. {
    132. cout << "出队的元素是:" << *s << endl;
    133. }
    134. else
    135. {
    136. cout << "出队失败" << endl;
    137. }
    138. break;
    139. case 3:
    140. cout << "队列中的元素是:";
    141. PrintQueue(sq);
    142. cout << endl;
    143. break;
    144. case 4:
    145. cout << "队首元素是:" << GetHeadElem(sq) << endl;
    146. break;
    147. case 5:
    148. cout << "队列的长度是:" << GetLength(sq) << endl;
    149. break;
    150. case 6:
    151. if (DestoryQueue(sq))
    152. {
    153. cout << "队列已销毁" << endl;
    154. }
    155. else
    156. {
    157. cout << "队列不存在" << endl;
    158. }
    159. break;
    160. case 0:
    161. cout << "退出成功" << endl;
    162. break;
    163. default:
    164. cout << "输入非法" << endl;
    165. break;
    166. }
    167. }
    168. return 0;
    169. }

  • 相关阅读:
    Qt::绘制框架-选择节点-QGraphicsScene-items
    django 程序化配置form
    Python数据结构:解锁高效编程
    卷妹带你学jdbc---2天冲刺Day2
    【YOLOv5/v7改进系列】引入特征融合网络——ASFYOLO
    Vue3 - 什么是组合式 API?与选项式 API 有什么不同?(先从 Vue2 角度进行讲解,然后过渡到 Vue3)详细教程
    基于群智能的路径规划算法(二)------蚁群算法
    UE4基础必学系列:数据驱动
    元宇宙到底是什么?全球各行业纷纷入局,为什么会成为一种趋势?
    LeetCode 周赛 352(2023/07/02)一场关于子数组的专题周赛
  • 原文地址:https://blog.csdn.net/qq_66805048/article/details/133960346