• 用两个栈实现一个队列,并实现在多线程环境下


    在知乎上看到这道题目,就实现了下看看。如有错误,麻烦各位看官留言指导下。

    首先两个栈实现一个队列的思路是这样的:

          (1)用栈A作为队列的入口,只提供入队操作, 用栈B作为队列的出口,只提供出口。

          (2)由于栈的特性是后进先出, 队列是先进先出, 若要出队(即把栈A最底层的元素pop出来), 需要把栈A整个转移到栈B(转移后就变为了倒序),此时只要pop栈B就能成功出队一个元素

          (3)同理若要入队, 则要先把栈B整个转移到栈A,再push一个元素到栈A  ( 具体的操作只要简单画个图就能明白 )

    具体见代码:

     1 #pragma once
     2 class Stack
     3 {
     4 public:
     5     Stack();
     6     ~Stack();
     7 
     8     bool isEmpty();
     9     void push(int value);
    10     int pop();
    11     int count();
    12 
    13 private:
    14     int m_nTop;
    15     int m_nArray[400];
    16 
    17 };
    Stack.h
     1 #include "Stack.h"
     2 #include <string.h>
     3 
     4 Stack::Stack()
     5 {
     6     memset(m_nArray, sizeof(m_nArray), 0);
     7     m_nTop = -1;
     8 }
     9 
    10 Stack::~Stack()
    11 {
    12 
    13 }
    14 
    15 bool Stack::isEmpty()
    16 {
    17     return -1 == m_nTop;
    18 }
    19 
    20 void Stack::push(int value)
    21 {
    22     m_nArray[++m_nTop] = value;
    23 }
    24 
    25 int Stack::pop()
    26 {
    27     return m_nArray[m_nTop--];
    28 }
    29 
    30 int Stack::count()
    31 {
    32     return m_nTop + 1;
    33 }
    Stack.cpp
     1 #pragma once
     2 #include "Stack.h"
     3 
     4 //make a queue by using two stacks
     5 class StackQueue 
     6 {
     7 public:
     8     StackQueue();
     9     ~StackQueue();
    10 
    11 public:
    12     void push(int value);
    13     int pop(int thread_id);
    14     bool isEmpty();
    15     int count();
    16 
    17 private:
    18     Stack m_InStack; //负责入队
    19     Stack m_OutStack; //负责出队
    20 };
    StackQueue.h
     1 #include "StackQueue.h"
     2 #include <iostream>
     3 
     4 StackQueue::StackQueue()
     5 {
     6 }
     7 
     8 StackQueue::~StackQueue()
     9 {
    10 }
    11 
    12 bool StackQueue::isEmpty()
    13 {
    14     return m_InStack.isEmpty() && m_OutStack.isEmpty();
    15 }
    16 
    17 int StackQueue::count()
    18 {
    19     return m_InStack.count() + m_OutStack.count();
    20 }
    21 
    22 void StackQueue::push(int value)
    23 {    
    24     if (!m_OutStack.isEmpty())
    25     {
    26         while(!m_OutStack.isEmpty())
    27         {
    28             int tmp = m_OutStack.pop();
    29             m_InStack.push(tmp);
    30         }
    31     }        
    32     m_InStack.push(value);
    33 }
    34 
    35 int StackQueue::pop(int thread_id)
    36 {
    37     while(!m_InStack.isEmpty())
    38     {    
    39         int tmp = m_InStack.pop();
    40         m_OutStack.push(tmp);
    41     }
    42     if (!m_OutStack.isEmpty())
    43     {
    44         int tmp = m_OutStack.pop();
    45         std::cout << "pop queue! value=" << tmp << "  thread_id=" << thread_id << std::endl;
    46         return tmp;
    47     }
    48     else
    49     {
    50         std::cerr << " empty queue! pop failed! " << std::endl;
    51         return -1;
    52     }
    53 }
    StackQueue.cpp

    相信各位看官看懂小弟的代码不成问题,然后就讲解下加入多线程环境要如何分析

          (1)由于栈A只作为入队,那么栈A入栈的时候需要锁住栈A

          (2)同理栈B只作为出队,那么栈B出栈的时候需要锁住栈B

          (3)当入队或出队时,可能会需要整个栈A转移到栈B(或栈B转移到栈A), 做转移时,需要同时锁住栈A和栈B。 注意:这里的转移操作的范围是整个栈的,直到其转移完成为止,都必须锁住栈A和栈B。

    所以修改后的代码是这样的:

     1 //头文件中定义栈A和栈B的互斥量
     2 boost::recursive_mutex in_mtx;
     3 boost::recursive_mutex out_mtx;
     4 
     5 void StackQueue::push(int value)
     6 {
     7     {    
     8         boost::recursive_mutex::scoped_lock out_lock(out_mtx); //对栈B的互斥量加锁
     9         if (!m_OutStack.isEmpty())
    10         {
    11             while(!m_OutStack.isEmpty())
    12             {
    13                 int tmp = m_OutStack.pop();
    14                 boost::recursive_mutex::scoped_lock in_lock(in_mtx);  //对栈A的互斥量加锁
    15                 m_InStack.push(tmp);
    16             }
    17         }    
    18     }
    19     
    20     {
    21                 //对栈A的互斥量加锁
    22         boost::recursive_mutex::scoped_lock in_lock(in_mtx); 
    23         m_InStack.push(value);
    24     }    
    25 }
    26 
    27 int StackQueue::pop(int thread_id)
    28 {
    29     {
    30                 //对栈A的互斥量加锁
    31         boost::recursive_mutex::scoped_lock in_lock(in_mtx);
    32         while(!m_InStack.isEmpty())
    33         {
    34             
    35             int tmp = m_InStack.pop();
    36             boost::recursive_mutex::scoped_lock out_lock(out_mtx); //对栈B的互斥量加锁
    37             m_OutStack.push(tmp);
    38         }
    39     }
    40     
    41     {
    42         boost::recursive_mutex::scoped_lock out_lock(out_mtx); //对栈B的互斥量加锁
    43         if (!m_OutStack.isEmpty())
    44         {
    45             int tmp = m_OutStack.pop();
    46             std::cout << "pop queue! value=" << tmp << "  thread_id=" << thread_id << std::endl;
    47             return tmp;
    48         }
    49         else
    50         {
    51             std::cerr << " empty queue! pop failed! " << std::endl;
    52             return -1;
    53         }
    54     }
    55 }
    加入多线程后的入队出队操作

           懒得去查资料就用了boost的互斥量和锁,其实也就是一样的东西。 

          

  • 相关阅读:
    测试开发进阶——Spring cloud——理解——微服务中微服务网关理解(转载)
    测试开发进阶——Spring cloud——理解——微服务中断路器模式理解(转载)
    测试开发进阶——Spring cloud——理解——微服务中负载均衡理解(转载)
    ORM 多表作业
    python-Matplotlib库
    beego Dockerfile
    java单例模式-饿汉式
    Java字符串连接:Java8字符串连接收集器Collectors.joining
    Odoo14学习笔记(11) 实例-简单的按年份月份查询报表
    002. git 分支管理
  • 原文地址:https://www.cnblogs.com/elenno/p/stack_queue_multi_thread.html
Copyright © 2020-2023  润新知