在知乎上看到这道题目,就实现了下看看。如有错误,麻烦各位看官留言指导下。
首先两个栈实现一个队列的思路是这样的:
(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 };
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 }
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 };
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 }
相信各位看官看懂小弟的代码不成问题,然后就讲解下加入多线程环境要如何分析
(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的互斥量和锁,其实也就是一样的东西。