数据结构——循环队列(顺序队列)模板类实现

朴灿烈づ我的快乐病毒、 2022-06-07 07:17 498阅读 0赞

数据结构笔记3.3
顺序队列是用顺序表实现的(即依托于数组),这里实现的是循环队列,其实也可以不用循环,但是那样的话,空间的利用效率就太低了,这就是”假溢出”问题,因为在数组的前端可能还有空闲的位置(因为队列中的数据是在动态变化的,可能出队也可能入对)。
为了能够充分利空间,所以用循环队列,即在逻辑上把数组的队结构看成一个环。具体实现:实现的方式还是十分巧妙地,运用两个指针和钟运算(就是取模或是取余运算)。
队头指针进1:front = (front + 1) % maxSize;
队尾指针进1 : rear = (rear + 1) % maxSize;
上面两个式子就是钟运算在队列数据操作时候的实现原理。
另外,在判断队列NULL与队列FULL的时候会遇到混淆的问题,NULL的时候,在即rear == front ,但是由于是循环表,当表FULL的时候,两者也是相等的,一种区分方式就是当rear检测到其下一个就是front的时候作为队列满的依据,这样就相当于队列满的时候也会有一个节点是空闲的。
好了,在编写这个类的过程中,需要强调的就这几个地方,下面贴出代码:
虚基类代码(此代码段放入queue.h当中,并在模板类代码中包含)

  1. template<class T>
  2. class Queue {
  3. public:
  4. Queue(){} //构造函数
  5. ~Queue(){} //析构函数
  6. virtual bool EnQueue(const T & x) = 0; //新元素x进入队列
  7. virtual bool DelQueue(T & x) = 0; //队头元素出队列
  8. virtual bool getFront(T & x) = 0; //读取队头元素的值
  9. virtual bool IsEmpty()const = 0; //判断队列是否为NULL
  10. virtual bool IsFull() const = 0; //判断队列是否已满
  11. virtual int getSize() const = 0; //求队列元素的个数
  12. };
  13. 模板class代码:
  14. #include <iostream>
  15. #include <cassert>
  16. #include <cmath>
  17. #include "queue.h"
  18. using namespace std;
  19. //顺序队列模板类定义(循环队列)
  20. template<class T>
  21. class SeqQueue : public Queue<T> {
  22. public:
  23. SeqQueue(int sz = 10); //构造函数
  24. ~SeqQueue(); //析构函数
  25. //若队列不满则将x进入队列,否则溢出处理
  26. bool EnQueue(const T & x);
  27. //若队列不空则删除队头元素x,并返回true,否则返回false
  28. bool DelQueue(T & x);
  29. //若队列不空则函数返回队头元素并返回true,否则返回false
  30. bool getFront(T & x);
  31. //置空操作,队头指针与队尾指针置0
  32. void makeEmpty();
  33. //判断队列是否为空,是则返回true否则返回false
  34. bool IsEmpty() const;
  35. //判断队列是否已满,是返回true否则返回false
  36. bool IsFull() const;
  37. //求队列元素的个数
  38. int getSize() const;
  39. //输出队列元素,运算符重载函数调用
  40. void output(ostream & out);
  41. protected:
  42. int rear, front; //队尾与队头指针
  43. T *elements; //存放队列元素的数组
  44. int maxSize; //队列最大可容纳的元素个数
  45. };
  46. //函数定义
  47. template<class T>
  48. SeqQueue<T>::SeqQueue(int sz) {
  49. //建立一个最大就有maxSzie个元素的空队列
  50. maxSize = sz;
  51. elements = new T[sz]; //开辟内存
  52. assert(elements != NULL); //内存分配不成功的中断处理
  53. rear = front = 0; //初始化队头与队尾指
  54. }
  55. template<class T>
  56. SeqQueue<T>::~SeqQueue() {
  57. //析构函数,释放程序中相应的资源
  58. delete[] elements;
  59. }
  60. template<class T>
  61. bool SeqQueue<T>::EnQueue(const T & x) {
  62. //若队列不满则将x进入队列,否则溢出处理
  63. if (IsFull()) {
  64. //如果队列已经满,则返回false
  65. return false;
  66. }
  67. elements[rear] = x;
  68. rear = (rear + 1) % maxSize; //通过钟运算实现元素的循环填充
  69. return true;
  70. }
  71. template<class T>
  72. bool SeqQueue<T>::DelQueue(T & x) {
  73. //若队列不空则删除队头元素x,并返回true,否则返回false
  74. if (IsEmpty()) {
  75. return false;
  76. }
  77. x = elements[front];
  78. front = (front + 1) % maxSize;
  79. return true;
  80. }
  81. template<class T>
  82. bool SeqQueue<T>::getFront(T & x) {
  83. //若队列不空则函数返回队头元素并返回true,否则返回false
  84. if (IsEmpty()) {
  85. return false;
  86. }
  87. x = elements[front];
  88. return true;
  89. }
  90. template<class T>
  91. bool SeqQueue<T>::IsEmpty() const {
  92. if (rear == front) {
  93. return true;
  94. }
  95. else {
  96. return false;
  97. }
  98. }
  99. template<class T>
  100. bool SeqQueue<T>::IsFull() const {
  101. if (fmod((rear + 1), maxSize) == front) {
  102. //如果rear的下一个节点与front相同则定义为队列已满
  103. //从而区分队列为NULL,即rear==front的情况
  104. return true;
  105. //注意这个时候队列中会有一个NULL的节点
  106. }
  107. else {
  108. return false;
  109. }
  110. }
  111. template<class T>
  112. void SeqQueue<T>::makeEmpty() {
  113. //置NULL操作
  114. rear = front = 0;
  115. }
  116. template<class T>
  117. int SeqQueue<T>::getSize() const {
  118. //求队列元素的个数
  119. return (rear - front + maxSize) % maxSize;
  120. }
  121. template<class T>
  122. void SeqQueue<T>::output(ostream & out) {
  123. for (int i = front; i != rear; i = (i + 1) % maxSize) {
  124. out << elements[i] << ' ';
  125. }
  126. cout << endl;
  127. }
  128. template<class T>
  129. ostream & operator << (ostream & out, SeqQueue<T> & SQ) {
  130. //重载插入运算符
  131. SQ.output(out);
  132. return out;
  133. }

Main测试代码:

  1. int main()
  2. {
  3. SeqQueue<int> squeue; //定义循环队列对象
  4. squeue.EnQueue(1); //进队与出队测试
  5. squeue.EnQueue(2);
  6. squeue.EnQueue(3);
  7. squeue.EnQueue(4);
  8. squeue.EnQueue(5);
  9. cout << squeue;
  10. int outQueVal_1, outQueVal_2;
  11. squeue.DelQueue(outQueVal_1);
  12. squeue.DelQueue(outQueVal_2);
  13. cout << squeue;
  14. int quFrontVal = 0;
  15. squeue.getFront(quFrontVal); //提取队头数据测试
  16. cout << quFrontVal << endl;
  17. squeue.makeEmpty(); //设置NULL与测试NULL测试
  18. if (squeue.IsEmpty()) {
  19. cout << "队列为NULL" << endl;
  20. }
  21. else {
  22. cout << "队列非空" << endl;
  23. }
  24. squeue.EnQueue(2); //取队列大小测试
  25. squeue.EnQueue(3);
  26. squeue.EnQueue(4);
  27. cout << squeue.getSize() << endl;
  28. system("pause");
  29. return 0;
  30. }

运行结果:
这里写图片描述

发表评论

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

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

相关阅读

    相关 C++模板实现循环队列

    以下是本人用C++类模板实现的一种数据结构——循环队列。希望对人们有所帮助,也希望人们提出宝贵的意见! //循环队列 \ifndef \_QUEUE\_H\_I