回顾前两篇文章
1> 由前2篇文章,我们知道栈的特性是:先进后出
队列的特性是:先进先出
用两个栈去实现一个队列,也就是我们要用两个”先进后出“ 去实现一个“先进先出”,我们不妨假设一个队列有2个元素,这2个元素就是2个栈stack1和stack2。 我们通过一个具体的例子来分析往队列里插入和删除元素的过程:
首先插入一个元素A, 我们不妨把它插入栈1即stack1,此时stack1里面元素有{A},栈2即stack2为空,再压入2个元素B和C,还是插入stack1,此时stack1中的元素有{A,B,C},其中C位于栈顶,而stack2仍然为空
这时候我们试着从队列里删除一个元素,按着队列先入先出的原则,由于A是最先插入的,最先被删除的应该是A,元素A存储在stack1,但是并不是位于栈顶,因此不能直接删除,注意到stack2一直没有被使用过,现在是时候让stack2发挥作用了,如果我们把stack1中的元素逐个弹出并压入到stack2,则元素在stack2中的顺序刚好跟原来的顺序相反,因此stack2中的元素是{C,B,A},stack1为空,A位于stack2的栈顶,弹出stack2中的栈顶元素,即满足了对队列删除A操作的要求。
如果我们还想继续删除队列的头部怎么办,剩下的两个元素是B ,C,由于B比C先入,因此对于队列来说应该先删除B,刚刚好B位于stack2的栈顶,满足要求,弹出B后,stack2只含有元素{C}。
从上面的分析我们可以总结出删除一个元素的步骤是:当stack2不为空时,在stack2栈顶的元素是先进入队列的没可以弹出,当stack2为空时,我们把stack1中的元素逐个的弹出并压入stack2,由于进入队列的元素被压入stack1的栈底。经过弹出和压入操作之后就位于stack2的顶端,又可以被直接弹出
接下来我们再考虑插入一个元素D,我们还是把它压入stack1,这样会不会有问题呢?我们考虑下一次删除队列的头部stack2不为空,直接弹出他的栈顶元素C,而C确实比D先进入队列,应该在D之前删除,因此不会出现矛盾。
综合上诉总结:
入队:
当stack1和stack2都为空时,直接入队stack1
当stack1为空,stack2不为空时,把stack2的元素都倒回stack1,然后再入队stack1
出队:
当stack2不为空时,直接出队stack2
当stack2为空且stack1不为空时,把stack1的元素都倒进stack2,然后出队stack2
代码:
typedef struct {
stack<int>s1; //负责入队列
stack<int>s2; //负责出队列
}SQueue;
//判断队列是否为空
bool IsEmpty(SQueue &q) {
if ((q.s1.empty()) && (q.s2.empty())) {
return true;
}
return false;
}
// 入队列
void EnQueue(SQueue &q, ElemType e) {
q.s1.push(e);
}
// 队列大小
int GetQueueSize(SQueue &q) {
return q.s1.size() + q.s2.size();
}
//出队列
void DeQueue(SQueue &q) {
if (q.s2.empty()) {
while (!q.s1.empty()) {
q.s2.push(q.s1.top());
q.s1.pop();
}
}
if (!q.s2.empty()) { //队空
q.s2.pop(); //出队列
}
}
// 取队首先元素
int GetFront(SQueue &q) {
if (q.s2.empty()) {
while (!q.s1.empty()) {
q.s2.push(q.s1.top());
q.s1.pop();
}
}
if (q.s2.empty()) { //队空
throw;
}
return q.s2.top();
}
以上,欢迎留言交流~