• 一文讲清 c++ 之队列


    队列也是一种特殊的 “表”,使用队列时插入是在一端操作,而删除则是在另外一端

    1.队列模型

    队列的基本操作是enqueue(入队),它是在表的末端(称为队尾)插入--个元素;dequeue(出队),它是删除(并返回)表的开头(叫作队头)的元素。下图显示了一个队列的抽象模型。

     2.链表实现队列

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. struct Node{
    6. int val;
    7. Node* next;
    8. Node(int v){
    9. val = v;
    10. next = NULL;
    11. }
    12. };
    13. class Queue{
    14. int size;
    15. Node* head; //pointer to the font node
    16. Node* back; //pointer to the least node
    17. public:
    18. Queue(){
    19. size = 0;
    20. head = back = NULL;
    21. }
    22. bool empty(){
    23. return size == 0;
    24. }
    25. Node* front(){
    26. return head;
    27. }
    28. Node* push_back(int v){
    29. if (size == 0){
    30. //note that head-next should give valuation after head
    31. head->next = head = back = new Node(v);
    32. }
    33. else if (size == 1){
    34. head->next = back = new Node(v);
    35. }
    36. else {
    37. back->next = new Node(v);
    38. back = back->next;
    39. }
    40. size++;
    41. return back;
    42. }
    43. //delete the font node
    44. void pop(){
    45. if (empty()) return;
    46. Node* temp = head;
    47. head = head->next ;
    48. delete temp;
    49. size--;
    50. }
    51. };
    52. void test_queue(){
    53. Queue queue;
    54. int n;
    55. cin >> n;
    56. for (int i = 0; i < n; i++){
    57. int temp;
    58. cin >> temp;
    59. queue.push_back(temp);
    60. }
    61. //you have to judge if queue is empty before using this font node
    62. while (queue.empty() == false){
    63. cout << queue.front()->val << endl;
    64. queue.pop();
    65. }
    66. return;
    67. }
    68. int main(){
    69. test_queue();
    70. return 0;
    71. }

    2.用数组实现

    对于每一个队列数据结构,我们保留一个数组theArray以及位置front和back,它们代表队列的两端。我们还要记录实际存在于队列中的元素的个数currentsize。下图表示处于某个中间状态的一个队列。

     操作应该是清楚的。要enqueue元素x,可将currentsize和 back增1,然后置theArray[back]=x。要dequeue一个元素,可以置返回值为theArray[front],将currentsize减1,再将front增1。其他的方法也可以使用(将在后面讨论)。现在论述错误的检测。

    这种实现存在一个潜在的问题。经过10次enqueue后,队列似乎是满了,因为back现在是数组的最后一个下标,而下一次执行enqueue就会是一个不存在的位置。然而,队列中也许只存在几个元素,因为若干元素可能已经出队了。像栈一样,即使在有许多操作的情况下队列也常常不是很大。

    简单的解决方法是,只要front或back到达数组的尾端,就绕回到开头。下列图显示了在某些操作期间的队列情况。这称为循环数组(circular array)实现可以看成换环队列。

     环形队列与普通队列的区别:

    1.front头部指针

    一般队列:front头部指针初始值为-1,从队列取数据时,该值依次递增,指向的元素即待取出的数据,而队列的头部数据所在的指针位置为front+1。当front=maxSize-1时,队列最后一个数据取出,此时队列为空。

    环形队列:front头部指针初始值为0,指向的元素既是队列的头部数据也是待取出的数据。从队列取数据时,因逻辑上的闭环,指针可能再次回到前面的位置,不能单一递增处理,需通过取模来重新计算指针的值。

    2.rear尾部指针

    一般队列:rear尾部指针初始值为-1,队列添加数据时,该值依次递增,当rear=maxSize-1时,队列满,无法再添加数据。

    环形队列:rear尾部指针初始值为0,指向待添加数据的位置,队列添加数据时,因逻辑上的闭环,指针可能再次回到前面的位置,不能单一递增处理,会出现角标越界异常,需通过取模来重新计算指针的值。

    3.队列空的判断逻辑

    一般队列:rear == front时,队列空。

    环形队列:rear == front时,队列空。

    4.队列满的判断逻辑

    一般队列:rear = maxSize - 1时,队列满。

    环形队列:(rear + 1) % maxSize == front时,队列满。

    代码实现:

    1. #include
    2. #include
    3. #include
    4. class Ciclequeue
    5. {
    6. public:
    7. //队列最大容量
    8. int m_maxSize;
    9. //队列头指针
    10. int m_frontIdx;
    11. //队列尾指针
    12. int m_rearIdx;
    13. //队列数组
    14. int *m_queueArr;
    15. public:
    16. //构造函数
    17. Ciclequeue(int tmpSize)
    18. {
    19. m_maxSize = tmpSize;
    20. m_frontIdx = 0;
    21. m_rearIdx = 0;
    22. m_queueArr = new int[m_maxSize];
    23. memset(m_queueArr, 0 , sizeof(int)*m_maxSize);
    24. }
    25. //析构函数
    26. ~Ciclequeue()
    27. {
    28. delete m_queueArr;
    29. m_queueArr = NULL;
    30. }
    31. //入队
    32. void enqueue(int datavalue)
    33. {
    34. if(isfull())
    35. {
    36. std::cout<<"Queue is full!"<
    37. return;
    38. }
    39. m_queueArr[m_rearIdx] = datavalue;
    40. m_rearIdx = (m_rearIdx + 1)%m_maxSize;
    41. }
    42. //出队
    43. void dequeue()
    44. {
    45. if(isempty())
    46. {
    47. std::cout<<"Queue is empty!"<
    48. return;
    49. }
    50. m_queueArr[m_frontIdx] = -1; //模拟出队列动作
    51. m_frontIdx = (m_frontIdx + 1)%m_maxSize;
    52. }
    53. //检查队列是否已满
    54. bool isfull()
    55. {
    56. if(m_maxSize == -1)
    57. {
    58. std::cout<<"Create queue error!"<
    59. return false;
    60. }
    61. return (m_rearIdx + 1)%m_maxSize == m_frontIdx;
    62. }
    63. //检查队列是否为空
    64. bool isempty()
    65. {
    66. if(m_maxSize == -1)
    67. {
    68. std::cout<<"Create queue error!"<
    69. return false;
    70. }
    71. return m_rearIdx == m_frontIdx;
    72. }
    73. //当前队列元素各个数
    74. int size()
    75. {
    76. return (m_rearIdx - m_frontIdx + m_maxSize) % m_maxSize;
    77. }
    78. //显示队列
    79. void showqueue()
    80. {
    81. if(isempty())
    82. {
    83. return;
    84. }
    85. for(int i = m_frontIdx; i < m_frontIdx + size(); i++ )
    86. {
    87. std::cout<" "<
    88. }
    89. }
    90. //显示队列头
    91. void showqueuefront()
    92. {
    93. std::cout<
    94. }
    95. };
    96. int main(int argc, char **argv)
    97. {
    98. int tmpSize = std::atoi(argv[1]);
    99. if(tmpSize <= 0)
    100. {
    101. std::cout<<"Set MaxSize Error!"<
    102. return 0;
    103. }
    104. Ciclequeue *testqueue = new Ciclequeue(tmpSize);
    105. testqueue->enqueue(3);
    106. testqueue->enqueue(2);
    107. testqueue->dequeue();
    108. testqueue->enqueue(4);
    109. testqueue->dequeue();
    110. testqueue->enqueue(5);
    111. testqueue->enqueue(66);
    112. testqueue->enqueue(88);
    113. testqueue->enqueue(1204);
    114. testqueue->showqueue();
    115. delete testqueue;
    116. testqueue = NULL;
    117. return 0;
    118. }

    3.队列的应用

    关于计算机网络的。有许多种PC机的网络设置,其中磁盘是放一台叫作文件服务器(file server)的机器上的。使用其他计算机的用户是按照先到先使用的原则访问文件的,

    因此其数据结构是一个队列

    升级:

    一个称为排队论(queuing theory)的数学分支用概率的方法处理--些诸如计算用户预计要排队等待的时间、等待的队伍能够排多长等类问题。问题的答案依赖于用户加入队列的频率以及-一旦用户得到服务时处理服务花费的时间。这两个参数作为概率分布函数给出。在一些简单的情况下,答案可以解析地算出。一种简单的例子是条电话线有一个接线员。如果接线员忙,打来的电话就被放到个等待队列中(这还与某个容许的最大限度有关)。这个问题在商业上很重要,因为研究表明,人们会很快挂上电话。如果有k个接线员,那么这个问题解决起来要困难得多。解析求解困难的问题往往使用模拟的方法求解。此时,需要使用一个队列来进行模拟。如果k很大,那么还需要其他一些数据结构来使得模拟更有效地进行。

    关注我一起学!!!

  • 相关阅读:
    HAproxy+keepalived+nginx 实验部署
    http https http2 http3
    Verilog 延迟反标注
    【C++天梯计划】1.9 回溯法(bark tracking method)
    【 OpenGauss源码学习 —— 列存储(CUStorage)】
    docker 启动镜像命令
    2d关键点转bvh fbx
    SpringMVC之全局异常拦截器
    独立站shopify卖家如何玩转TikTok?
    VS Code 在线运行:code-server部署(系列一)
  • 原文地址:https://blog.csdn.net/qq_62309585/article/details/126772828