目录
前言:
栈和队列都是动态集合,在栈中,被删除的是最后插入的元素:实现的是一种后进先出(last-in,first-out,LIFO)策略。类似地,在队列中,被删去的总是最先进入的那个元素:实现的是一种先进先出(first-in,first-out,FIFO)策略。本文将介绍用栈实现队列的方法。
提示:以下是本篇文章正文内容,代码注释较为详细,可供参考
一、用栈实现队列的方法
由于要实现先进先出的策略,所以可以让一个栈(m_hold)用来存储数据。在需要完成出列的操作时,将存储数据的栈重新放入一个新的栈(m_out),这样便能时最先存入的数据成为新栈的最后存入的数据。再让新栈完成一次出栈操作,便将最先存入的数据先输出,从而实现先进先出的策略。
可用下图简略表示用双栈实现出列这一过程:
二、代码实现
1.创建结点
关于结点的建立就不赘述了,这里要注意的是后面要用到的类模板Stack以及Queue要先提前声明,否则在Node类里声明友元时会报错。
2.创建栈
入栈出栈清空都是基本的写法,不多赘述。
template<class T>
class Stack {
private:
Node<T>* m_top = nullptr;//栈顶指针
public:
Stack() = default;//默认构造
Stack(const Stack&) = delete;//禁止复制
Stack& operator=(const Stack&) = delete;//禁止赋值
~Stack() {
clear();
};//析构
void clear();//清空栈
void push(const T& val);//入栈
void pop();//出栈
bool empty()const {
return this->m_top == nullptr;
}//判断是否为空
const T& top() {
return this->m_top->m_data;
}//取出栈顶元素
friend class Queue<T>;//声明友元
};
(1)入栈函数
template<class T>
void Stack<T>::push(const T& val) {
Node<T>* node = new Node<T>(val);
node->m_next = this->m_top;
this->m_top = node;
}
(2)出栈函数
template<class T>
void Stack<T>::pop() {
if (empty()) {
return;
}
Node<T>* p = this->m_top;
this->m_top = this->m_top->m_next;
delete p;
}
(3)清空函数
template<class T>
void Stack<T>::clear() {
Node<T>* p = nullptr;
while (this->m_top != nullptr) {
p = this->m_top;
this->m_top = this->m_top->m_next;
delete p;
}
}
3.创建队列(私有成员为栈)
其中私有成员栈m_hold用来存储数据,栈m_out用来出列以及打印数据,类定义如下:
template<class T>
class Queue {
private:
Stack<T> m_hold, m_out;//设置两个栈,hold用来完成入列操作(后进排在后面),out用来出列(先进先出)
public:
Queue() = default;//默认构造
Queue(const Queue&) = delete;//禁止复制
~Queue() {
clear();
};//析构
void push(const T &val);//入列
void pop();//出列
void clear();//清空
void show();//打印队列元素
void exchange();//将存有数据的栈内元素逐个出栈给另一个空栈(传完后为倒序)
bool empty()const {
return (this->m_hold.m_top == nullptr) && (this->m_out.m_top == nullptr);
}//判断是否为空
};
(1)入列函数
在入列时,要先判断此时数据存储在哪个栈内,如果在m_out内则需先放入m_hold内,否则会出现乱序,然后直接调用Stack内的push()成员函数即可。
template<class T>
void Queue<T>::push(const T &val) {
if (this->m_out.m_top == nullptr) {
this->m_hold.push(val);
}
else {
this->exchange();//如果此时数据存储在m_out栈则先将元素放回m_hold
this->m_hold.push(val);
}
}
(2)出列函数
在出列时要将数据存入m_out内再对m_out出栈即可实现先进先出,原理及图示在上文已呈现,不再复述。
template<class T>
void Queue<T>::pop() {
if (this->empty()) {
return;
}
if (this->m_out.m_top == nullptr && this->m_hold.m_top != nullptr) {
this->exchange();
this->m_out.pop();
}//如果此时数据存储在m_hold,则先将数据放入m_out,以便倒序实现先进先出
else {
this->m_out.pop();
}
}
(3)清空函数
简单粗暴,不为空直接out,Stack out!
template<class T>
void Queue<T>::clear() {
if (this->m_hold.m_top != nullptr) {
this->m_hold.clear();
}
if (this->m_out.m_top != nullptr) {
this->m_out.clear();
}
}//将两个栈都清空
(4)打印函数
遍历并输出Stack里Node的数据域m_data。
template<class T>
void Queue<T>::show() {
if (this->empty()) {
return;
}
if (this->m_hold.m_top != nullptr) {
this->exchange();
}//将数据放在m_out内打印出来,这样的顺序为先进先打印
Node<T>* p = this->m_out.m_top;
while (p != nullptr) {
cout << p->m_data << " ";
p = p->m_next;
}//遍历
cout << endl;
}
(5)交换函数
其实就是将一个栈的所有元素依次出栈然后入到另外一个栈。
//执行此函数时 if判断哪个为空就将另一个依次出栈然后入栈到为空的栈
template<class T>
void Queue<T>::exchange() {
if (this->empty()) {
return;
}//都为空直接返回,换不了一点
else if (this->m_out.m_top == nullptr && this->m_hold.m_top != nullptr) {
Node<T>* p = nullptr;
while (this->m_hold.m_top != nullptr) {
p = this->m_hold.m_top;
this->m_out.push(p->m_data);
this->m_hold.m_top = this->m_hold.m_top->m_next;
delete p;
}//while遍历栈,直到栈底指针为空
}
else {
Node<T>* p = nullptr;
while (this->m_out.m_top != nullptr) {
p = this->m_out.m_top;
this->m_hold.push(p->m_data);
this->m_out.m_top = this->m_out.m_top->m_next;
delete p;
}//while遍历栈,直到栈底指针为空
}
}
(6)main函数
其实就是测试,可以随意测,对于类对象应该也可以,不过前提是你要在类里重载<<运算符,或者在show( )函数里实例化此情况,否则必报错。
int main()
{
Queue<int> q1;
for (int i = 0; i < 10; i++) {
q1.push(i);
}
q1.show();
q1.pop();
q1.show();
q1.clear();
for (int i = 5; i < 10; i++) {
q1.push(i);
}
q1.show();
Queue<string> q2;
q2.push("first");
q2.push("second");
q2.push("third");
q2.pop();
q2.show();
}
三、完整代码
以下是完整代码展示,由于个人水平有限,如有错误/不严谨的地方敬请指正。
#include <iostream>
#include <string>
using namespace std;
template<class T>class Stack;//向前声明
template<class T>class Queue;//向前声明
template<class T>
class Node {
private:
T m_data;//数据域
Node* m_next;//指针域
public:
Node(const T& val) {
this->m_data = val;
}//有参构造
Node& operator=(const Node& rhs) = delete;//禁止赋值
friend class Stack<T>;//声明友元
friend class Queue<T>;//同上
};
template<class T>
class Stack {
private:
Node<T>* m_top = nullptr;//栈顶指针
public:
Stack() = default;//默认构造
Stack(const Stack&) = delete;//禁止复制
Stack& operator=(const Stack&) = delete;//禁止赋值
~Stack() {
clear();
};//析构
void clear();//清空栈
void push(const T& val);//入栈
void pop();//出栈
bool empty()const {
return this->m_top == nullptr;
}//判断是否为空
const T& top() {
return this->m_top->m_data;
}//取出栈顶元素
friend class Queue<T>;//声明友元
};
template<class T>
void Stack<T>::push(const T& val) {
Node<T>* node = new Node<T>(val);
node->m_next = this->m_top;
this->m_top = node;
}
template<class T>
void Stack<T>::pop() {
if (empty()) {
return;
}
Node<T>* p = this->m_top;
this->m_top = this->m_top->m_next;
delete p;
}
template<class T>
void Stack<T>::clear() {
Node<T>* p = nullptr;
while (this->m_top != nullptr) {
p = this->m_top;
this->m_top = this->m_top->m_next;
delete p;
}
}
template<class T>
class Queue {
private:
Stack<T> m_hold, m_out;//设置两个栈,hold用来完成入列操作(后进排在后面),out用来出列(先进先出)
public:
Queue() = default;//默认构造
Queue(const Queue&) = delete;//禁止复制
~Queue() {
clear();
};//析构
void push(const T &val);//入列
void pop();//出列
void clear();//清空
void show();//打印队列元素
void exchange();//将存有数据的栈内元素逐个出栈给另一个空栈(传完后为倒序)
bool empty()const {
return (this->m_hold.m_top == nullptr) && (this->m_out.m_top == nullptr);
}//判断是否为空
};
template<class T>
void Queue<T>::push(const T &val) {
if (this->m_out.m_top == nullptr) {
this->m_hold.push(val);
}
else {
this->exchange();//如果此时数据存储在m_out栈则先将元素放回m_hold
this->m_hold.push(val);
}
}
template<class T>
void Queue<T>::pop() {
if (this->empty()) {
return;
}
if (this->m_out.m_top == nullptr && this->m_hold.m_top != nullptr) {
this->exchange();
this->m_out.pop();
}//如果此时数据存储在m_hold,则先将数据放入m_out,以便倒序实现先进先出
else {
this->m_out.pop();
}
}
template<class T>
void Queue<T>::clear() {
if (this->m_hold.m_top != nullptr) {
this->m_hold.clear();
}
if (this->m_out.m_top != nullptr) {
this->m_out.clear();
}
}//将两个栈都清空
template<class T>
void Queue<T>::show() {
if (this->empty()) {
return;
}
if (this->m_hold.m_top != nullptr) {
this->exchange();
}//将数据放在m_out内打印出来,这样的顺序为先进先打印
Node<T>* p = this->m_out.m_top;
while (p != nullptr) {
cout << p->m_data << " ";
p = p->m_next;
}
cout << endl;
}
//执行此函数时 if判断哪个为空就将另一个依次出栈然后入栈到为空的栈
template<class T>
void Queue<T>::exchange() {
if (this->empty()) {
return;
}
else if (this->m_out.m_top == nullptr && this->m_hold.m_top != nullptr) {
Node<T>* p = nullptr;
while (this->m_hold.m_top != nullptr) {
p = this->m_hold.m_top;
this->m_out.push(p->m_data);
this->m_hold.m_top = this->m_hold.m_top->m_next;
delete p;
}//while遍历栈,直到栈底指针为空
}
else {
Node<T>* p = nullptr;
while (this->m_out.m_top != nullptr) {
p = this->m_out.m_top;
this->m_hold.push(p->m_data);
this->m_out.m_top = this->m_out.m_top->m_next;
delete p;
}//while遍历栈,直到栈底指针为空
}
}
int main()
{
Queue<int> q1;
for (int i = 0; i < 10; i++) {
q1.push(i);
}
q1.show();
q1.pop();
q1.show();
q1.clear();
for (int i = 5; i < 10; i++) {
q1.push(i);
}
q1.show();
Queue<string> q2;
q2.push("first");
q2.push("second");
q2.push("third");
q2.pop();
q2.show();
}