当前位置:   article > 正文

《大话数据结构》—— 队列的顺序存储结构 (循环队列)—— C++、C# 代码实现_队列的顺序存储代码流程图

队列的顺序存储代码流程图

 


 队列 


 队列的概念:

  队列(简称作队,Queue)也是一种特殊的线性表,队列的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置插入和删除,而队列只允许在其一端进行插入操作在其另一端进行删除操作。

队列中允许进行插入操作的一端称为队尾,允许进行删除操作的一端称为队头。队列的插入操作通常称作入队列,队列的删除操作通常称作出队列。

下图是一个依次向队列中插入数据元素a0,a1,...,an-1后的示意图:

faf7d1e6-07b1-44bb-9752-5fcc113a0648

上图中,a0是当前 队头数据元素,an-1是当前 队尾数据元素。

为了避免当只有一个元素时,对头和队尾重合使得处理变得麻烦,所以引入两个指针:front指针指向队头元素,rear指针指向队尾元素的下一个位置,这样的话,当front指针等于rear时,此队列不是还剩一个元素,而是空队列。


顺序队列


 顺序队列 队列的顺序存储结构称为顺序队列,顺序队列实际上是运算受限的顺序表,和顺序表一样,顺序队列也是必须用一个数组来存放当前队列中的元素。由于队列的队头和队尾的位置是变化的,因而要设两个指针和分别指示队头和队尾元素在队列中的位置。 

 顺序队列中的溢出现象:

607ede1a-91b5-4ac9-8850-07078379fddb

上图中,front指针指向队头元素,rear指针指向队尾元素的下一个位置。

图(d)中b、c、d出队后,front指针指向元素e,rear指针在数组外面。假设这个队列的总个数不超过5个,但目前如果接着入队的话,因数组末尾元素已经被占用,再向后加就会产生数组越界的错误,可实际上队列在下标为0、1、2、3、4的地方还是空闲的,我们把这种现象叫做“假溢出”——也叫假上溢。

下溢:队列为空时,做出队操作产生的溢出现象。

真上溢:当队列满时,做入队操作产生的空间溢出现象。

顺序队列的基本操作

入队时:将新元素插入rear所指的位置,并将rear+1。

出队时:删除front所指的元素,并将front+1。

 


循环队列


  所以解决假溢出的办法就是后面满了,就再从头开始,也就是头尾相接的循环。我们把队列的这种逻辑上首尾相连的顺序存储结构称为循环队列。

如何判断循环队列究竟是空的还是满的:

  现在问题又来了,我们之前说,空队列时,front指针等于rear指针,那么现在循环队列满的时候,也是front等于rear,那么如何判断循环队列究竟是空的还是满的?有如下办法:

办法1:设置一个标志位flag。初始时置flag=0;每当入队列操作成功就置flag=1;每当出队列操作成功就置flag=0。则队列空的判断条件为:rear == front && flag==0;队列满的判断条件为:rear = = front && flag= =1。

办法2:保留一个元素的存储空间。此时,队列满时的判断条件为  (rear + 1) % maxSize == front;队列空的判断条件还是front == rear。

办法3:设计一个计数器count,统计队列中的元素个数。此时,队列满的判断条件为:count > 0 && rear == front ;队列空的判断条件为count == 0。

我们在接下来的代码中采用方法2来实现。

CirQueue.h 头文件

  1. #include<iostream>
  2. #include<cassert>
  3. using namespace std;
  4. #ifndef TT_CIR_QUEUE_H
  5. #define TT_CIR_QUEUE_H
  6. namespace tt
  7. {
  8. class CirQueue
  9. {
  10. public:
  11. using ElemType = int;
  12. using Status = void;
  13. enum State
  14. {
  15. TT_ERROR = 0,
  16. TT_OK = 1
  17. };
  18. public:
  19. CirQueue(ElemType INI_SIZE); //初始化队列
  20. ~CirQueue();
  21. ElemType isEmpty()const; //判断队列是否为空。
  22. ElemType isFull()const; //确定队列是否满了
  23. ElemType clear(); //将队列清空
  24. ElemType getHead(ElemType &elemOut); //若队列存在且非空,用elem返回队列的队头元素
  25. ElemType insert(ElemType elem); //若队列存在,插入新元素elem到队列中并成为队尾元素。
  26. ElemType remove(ElemType &elemOut);// 删除队列中的队头元素,并用elem返回。
  27. ElemType destroy(); //若队列存在,则销毁它
  28. Status getLength()const; //返回队列中当前元素的个数。
  29. Status show(); //显示队列中的所有元素
  30. private:
  31. ElemType *m_data; //数据域
  32. ElemType m_front; //指向队头元素
  33. ElemType m_rear; //指向队尾元素的下一个位置
  34. ElemType m_queueSize; //队列的最大容量
  35. };
  36. inline CirQueue::ElemType CirQueue::isEmpty()const //判断队列是否为空
  37. {
  38. return (m_front == m_rear);
  39. }
  40. inline CirQueue::Status CirQueue::getLength()const //返回队列中当前元素的个数
  41. {
  42. cout<< "当前队列中的元素个数为:" << (m_rear - m_front + m_queueSize) % m_queueSize << endl;
  43. }
  44. inline CirQueue::ElemType CirQueue::clear() //将队列清空
  45. {
  46. m_front = m_rear = 0;
  47. return TT_OK;
  48. }
  49. inline CirQueue::ElemType CirQueue::isFull()const //确定队列是否满了
  50. {
  51. return (m_rear + 1) % m_queueSize == m_front;
  52. }
  53. }
  54. #endif //TT_CIR_QUEUE_H

testCirQueue.cpp 源文件

  1. #include"CirQueue.h"
  2. namespace tt
  3. {
  4. CirQueue::CirQueue(ElemType INI_SIZE)
  5. {
  6. assert(INI_SIZE != 0);
  7. m_data = new int[INI_SIZE];
  8. assert(m_data != nullptr);
  9. m_queueSize = INI_SIZE; //把队列的初始化的最大容量赋值给成员数据
  10. m_front = m_rear = 0; //m_front等于m_rear 就是空队列
  11. cout << "*********** 循环队列初始化成功! **************" << endl;
  12. }
  13. CirQueue::~CirQueue()
  14. {
  15. this->destroy();
  16. }
  17. CirQueue::ElemType CirQueue::insert(ElemType elem) //插入元素致队列的尾部
  18. {
  19. if (((m_rear + 1) % m_queueSize) == m_front)//判断队列满的情况
  20. {
  21. return TT_ERROR;
  22. }
  23. m_data[m_rear] = elem; //将元素elem 添加到队列的末尾
  24. m_rear = (m_rear + 1) % m_queueSize; //尾指针应以此种方式加1,才会实现循环队列, 若到末尾转到数组的头部
  25. return TT_OK;
  26. }
  27. CirQueue::ElemType CirQueue::remove(ElemType &elemOut) //删除队列的队头元素
  28. {
  29. if (m_front == m_rear) //判断循环队列是否为空
  30. {
  31. return TT_ERROR;
  32. }
  33. elemOut = m_data[m_front]; //将对头元素赋给elem返回
  34. m_front = (m_front + 1) % m_queueSize; //m_front指针向后移动一位,若到最后则转到数组头部
  35. return TT_OK;
  36. }
  37. CirQueue::ElemType CirQueue::getHead(ElemType &elemOut) //若队列存在且非空,用elem返回队列的队头元素
  38. {
  39. if (m_front == m_rear) //判断循环队列是否为空
  40. {
  41. return TT_ERROR;
  42. }
  43. elemOut = m_data[m_front]; //把队头元素用elem返回
  44. return TT_OK;
  45. }
  46. CirQueue::ElemType CirQueue::destroy() //若队列存在,则销毁它
  47. {
  48. delete[] m_data;
  49. m_data = nullptr;
  50. m_front = m_rear = m_queueSize = 0;
  51. return ((!m_data) && (m_front == m_rear == m_queueSize == 0)); //多一个判断看队列是否被销毁
  52. }
  53. CirQueue::Status CirQueue::show() //显示队列的所有元素
  54. {
  55. if (m_front == m_rear)
  56. {
  57. cout << "错误,此队列中没有数据或者队列没有建立,无法显示!" << endl;
  58. }
  59. else
  60. {
  61. auto count = (m_rear - m_front + m_queueSize) % m_queueSize; //一个临时变量存储该队列的元素个数
  62. cout << "队列从队头至队尾内容依次为:";
  63. for (size_t i = m_front; i < m_front + count; ++i)
  64. {
  65. cout << m_data[i] << ' ';
  66. }
  67. cout << endl;
  68. }
  69. }
  70. }
  71. //测试循环队列的功能
  72. void testCirQueue()
  73. {
  74. int allocMemory(0);
  75. cout << "请输入队列初始化的最大容量:";
  76. cin >> allocMemory;
  77. tt::CirQueue myCirQueue(allocMemory); //初始化一个队列
  78. while (true)
  79. {
  80. {
  81. cout << ("\n***************************************************") << endl
  82. << "*************** 循环队列的基本功能展示 **************" << endl
  83. << "*******************************************************" << endl
  84. << "************** 选择1—— 数据进队列尾. ************" << endl
  85. << "************** 选择2—— 删除队列头元素. ************" << endl
  86. << "*************** 选择3—— 显示队列头元素. ************" << endl
  87. << "*************** 选择4—— 判断队列是否为空. ************" << endl
  88. << "*************** 选择5—— 判断队列是否满了. ************" << endl
  89. << "***************************************************************" << endl
  90. << "*************** 选择6—— 显示队列的元素个数. *************" << endl
  91. << "*************** 选择7—— 清空队列. *************" << endl
  92. << "**************** 选择8—— 销毁队列. *************" << endl
  93. << "**************** 选择9—— 显示队列中的所有元素. ***********" << endl
  94. << "**************** 选择10—— 清屏. *************" << endl
  95. << "**************** 选择0—— 退出程序! *************" << endl
  96. << "***************************************************************" << endl
  97. << "***************************************************************" << endl;
  98. }
  99. cout << "\n***************** 请输入你想要使用的队列功能的序号 ***************" << endl;
  100. cout << "请输入你的选择:";
  101. int userChoice(0);
  102. cin >> userChoice;
  103. if (!userChoice)
  104. {
  105. cout << "程序已退出,感谢您的使用!" << "\n" << endl;
  106. break;
  107. }
  108. switch (userChoice)
  109. {
  110. case 1:
  111. {
  112. int pushDatas(0);
  113. cout << "请输入想要添加的数据:";
  114. cin >> pushDatas;
  115. if (myCirQueue.insert(pushDatas)) //进队列
  116. {
  117. cout << "数据" << pushDatas << "成功进入队列中!" << endl;
  118. myCirQueue.getLength();
  119. myCirQueue.show(); //显示所有元素
  120. }
  121. else
  122. cout << "目前队列已满, 数据" << pushDatas << "进入失败!" << endl;
  123. break;
  124. }
  125. case 2:
  126. {
  127. int popDatas(0);
  128. if (myCirQueue.remove(popDatas)) //删除队列头元素
  129. {
  130. cout << "数据" << popDatas << "从队列中成功删除!" << endl;
  131. myCirQueue.getLength();
  132. myCirQueue.show();
  133. }
  134. else
  135. {
  136. cout << "目前队列为空, 数据" << popDatas << "删除失败!" << endl;
  137. myCirQueue.getLength();
  138. }
  139. break;
  140. }
  141. case 3:
  142. {
  143. int disHead(0);
  144. if (myCirQueue.getHead(disHead)) //获取队头元素
  145. {
  146. cout << "队列头元素为:" << disHead << endl;
  147. myCirQueue.getLength();
  148. myCirQueue.show();
  149. }
  150. else
  151. {
  152. cout << "目前队列为空, 数据" << disHead << "获取失败!" << endl;
  153. myCirQueue.getLength();
  154. }
  155. break;
  156. }
  157. case 4:
  158. if (myCirQueue.isEmpty()) //判断队列是否空
  159. {
  160. cout << "队列为空,或者队列尚未建立!" << endl;
  161. myCirQueue.getLength();
  162. }
  163. else
  164. {
  165. cout << "队列非空!" << endl;
  166. myCirQueue.getLength();
  167. myCirQueue.show();
  168. }
  169. break;
  170. case 5:
  171. if (myCirQueue.isFull()) //判断队列是否满
  172. {
  173. cout << "目前队列已满,不能再添加数据了!" << endl;
  174. myCirQueue.getLength();
  175. myCirQueue.show();
  176. }
  177. else
  178. {
  179. cout << "目前队列不满,还可以继续输入数据进栈!" << "\n" << endl;
  180. myCirQueue.getLength();
  181. myCirQueue.show();
  182. }
  183. break;
  184. case 6:
  185. myCirQueue.getLength(); //显示队列的元素个数
  186. myCirQueue.show();
  187. break;
  188. case 7:
  189. if (myCirQueue.clear())
  190. {
  191. cout << "队列已清空!" << endl;
  192. myCirQueue.getLength();
  193. }
  194. else
  195. {
  196. cout << "队列清空失败!" << endl;
  197. myCirQueue.getLength();
  198. myCirQueue.show();
  199. }
  200. break;
  201. case 8:
  202. {
  203. cout << "你确定要销毁一个队列吗?(若销毁请输入输入(Y/y))";
  204. char yesOrNo;
  205. cin >> yesOrNo;
  206. if ((yesOrNo == 'Y') || (yesOrNo == 'y'))
  207. {
  208. if (myCirQueue.destroy())
  209. {
  210. cout << "队列已被销毁!" << endl;
  211. }
  212. else
  213. cout << "队列销毁失败!" << endl;
  214. }
  215. break;
  216. }
  217. case 9:
  218. myCirQueue.getLength();
  219. myCirQueue.show();
  220. break;
  221. case 10:
  222. system("cls");
  223. cout << "屏幕已经清屏,可以重新输入!" << "\n" << endl;
  224. break;
  225. default:
  226. cout << "输入的序号不正确,请重新输入!" << "\n" << endl;
  227. }
  228. }
  229. }
  230. int main()
  231. {
  232. testCirQueue();
  233. system("pause");
  234. return 0;
  235. }

C# 代码实现的循环队列:

  1. namespace DateStructure
  2. {
  3. interface IQueue
  4. {
  5. void CreateQueue(params int[] arrElem);
  6. void clear();
  7. bool isEmpty();
  8. void EnQueue(int insertElem);
  9. int DeQueue();
  10. int getLength();
  11. void show();
  12. }
  13. class CirQueue : IQueue
  14. {
  15. private int[] m_data;
  16. private int m_front; // 循环队列队头指针
  17. private int m_rear; // 循环队列尾指针
  18. private int m_queueMaxLength;
  19. private int m_queueCurrentLength;
  20. public CirQueue(int maxSize)
  21. {
  22. Debug.Assert(maxSize > 0, "不能分配小于1的数组!");
  23. m_data = new int[maxSize];
  24. Debug.Assert(m_data != null, "初始化时,内存分配失败!");
  25. m_queueMaxLength = maxSize;
  26. m_front = m_rear = m_queueCurrentLength = 0;
  27. }
  28. public void CreateQueue(params int[] arrElem)
  29. {
  30. // arrElem.Length 不能等于 m_queueMaxLength,否则但添加元素时,会出现bug
  31. if ((arrElem != null) && (arrElem.Length != 0) && arrElem.Length < m_queueMaxLength)
  32. {
  33. m_rear = m_queueCurrentLength = arrElem.Length;
  34. for (int i = 0; i != m_queueCurrentLength; ++i)
  35. {
  36. m_data[i] = arrElem[i];
  37. }
  38. }
  39. else
  40. {
  41. throw new ArgumentException("循环队列整表创建失败!");
  42. }
  43. }
  44. public void clear()
  45. {
  46. m_front = m_rear = m_queueCurrentLength = 0;
  47. }
  48. public int DeQueue()
  49. {
  50. if (isEmpty() == true)
  51. {
  52. return -1;
  53. }
  54. int removeElem = m_data[m_front];
  55. m_front = (m_front + 1) % m_queueMaxLength;
  56. --m_queueCurrentLength;
  57. return removeElem;
  58. }
  59. public void EnQueue(int insertElem)
  60. {
  61. if ((m_rear + 1) % m_queueMaxLength == m_front)
  62. {
  63. throw new ArgumentException("当前循环队列已满,无法添加元素!");
  64. }
  65. m_data[m_rear] = insertElem;
  66. m_rear = (m_rear + 1) % m_queueMaxLength;
  67. ++m_queueCurrentLength;
  68. }
  69. public int getLength()
  70. {
  71. return m_queueCurrentLength;
  72. }
  73. public bool isEmpty()
  74. {
  75. return ((m_queueCurrentLength == 0) && (m_rear == m_front));
  76. }
  77. public void show()
  78. {
  79. if(m_queueCurrentLength == 0)
  80. {
  81. WriteLine("该循环队列中没有元素,无法输出!");
  82. return;
  83. }
  84. int index = m_front;
  85. WriteLine("输出链队列中的所有元素:");
  86. do
  87. {
  88. Write($"{m_data[index]},");
  89. index = (index + 1) % m_queueMaxLength;
  90. } while (index != m_rear);
  91. WriteLine();
  92. }
  93. }
  94. class Program
  95. {
  96. static void Main(string[] args)
  97. {
  98. WriteLine("输入循环队列的最大容量:");
  99. int sizeCapacity = Convert.ToInt32(Console.ReadLine());
  100. var myQueue = new CirQueue(sizeCapacity);
  101. const int arraySize = 5;
  102. int[] myIntArray = new int[arraySize] { 141, 11, 24, 347, 45 };
  103. myQueue.CreateQueue(myIntArray);
  104. myQueue.show();
  105. WriteLine("请输入你想插入的元素值:");
  106. int pushElem = Convert.ToInt32(Console.ReadLine());
  107. myQueue.EnQueue(pushElem);
  108. myQueue.show();
  109. int removeElem = myQueue.DeQueue();
  110. if (removeElem >= 0)
  111. {
  112. WriteLine($"被删除的元素为:{removeElem}");
  113. myQueue.show();
  114. }
  115. else
  116. {
  117. WriteLine("当前循环队列是空的,没有元素可以删除!");
  118. }
  119. if (myQueue.isEmpty())
  120. {
  121. WriteLine("当前的循环队列为空!");
  122. }
  123. else
  124. WriteLine("当前的循环队列非空!");
  125. WriteLine($"\n获取当前循环队列的总个数:{myQueue.getLength()}");
  126. myQueue.clear();
  127. WriteLine($"获取当前循环队列的总个数:{myQueue.getLength()}");
  128. }
  129. }
  130. }


 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/551857
推荐阅读
相关标签
  

闽ICP备14008679号