【C++数据结构】用双栈实现队列(类模板)

目录

前言:

一、用栈实现队列的方法

二、代码实现

1.创建结点

2.创建栈

(1)入栈函数

(2)出栈函数定

(3)清空函数

3.创建队列(私有成员为栈)

(1)入列函数

(2)出列函数

(3)清空函数

(4)打印函数

(5)交换函数

(6)main函数

三、完整代码


前言:

        队列都是动态集合,在栈中,被删除的是最后插入的元素:实现的是一种后进先出(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)打印函数

        遍历并输出StackNode的数据域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();
}

  • 18
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值