IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++ queue的使用及模拟实现 -> 正文阅读

[C++知识库]C++ queue的使用及模拟实现

? ? ? ?

目录

queue的简单介绍

queue的使用

queue()

push()

pop()

empty()

size()

front()?

back()

swap()

queue的模拟实现

成员变量

成员函数

bool empty() const

size_t size() const

const T& front() const

T& front()?

const T& back() const

T& back()

void push(const T& x)

void pop()

完整代码

queue.h

测试代码

总结?


queue的简单介绍

以前我用c语言模拟实现过queue,也写过相关的博客,在这里不给各位老铁回顾queue的特征了~

队列的模拟实现(单链链表模拟)_暴走的橙子~的博客-CSDN博客

在这里我们来翻译一下C++文档来了解一下:

1. 队列是一种容器适配器,专门用于在FIFO上下文(先进先出)中操作,其中从容器一端插入元素,另一端提取元素。(尾插,头删)
2. 队列作为容器适配器实现,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从队尾入队列,从队头出队列。
3. 底层容器可以是标准容器类模板之一,也可以是其他专门设计的容器类。该底层容器应至少支持以下操作:
empty:检测队列是否为空
size:返回队列中有效元素的个数
front:返回队头元素的引用
back:返回队尾元素的引用
push_back:在队列尾部入队列
pop_front:在队列头部出队列
4. 标准容器类deque和list满足了这些要求。默认情况下,如果没有为queue实例化指定容器类,则使用标准容器deque。?

queue的使用

queue()

?构造空的队列。

const container_type& ctnr = container_type():这是一个空间适配器,我们只需要知道有了它就可以高效申请释放空间就可以了。

举个栗子:

int main()
{
	queue<int> q;
	return 0;
}

我们来调试一下看看情况:

通过调试我们发现无参构造的对象q,是一个空队列,里面没有数据。

queue<int> q:我们在构造对象时,要在queue后面加一个<类型>,在这里指定类型是int,说明该队列里面存放的是int类型的数据。?注意:q后面不能加()

push()

?将元素val插入到队尾。

举个栗子:

int main()
{
	queue<int> q;
	q.push(1);
	q.push(2);
	q.push(3);
	return 0;
}

我们来调试一下看看情况:

通过数组下标我们发现数据1 2 3依次从队尾插入进去了。?

我们画图来展示一下这个过程:

pop()

?将队头的元素val进行删除(哨兵位头结点除外)。

举个栗子:

int main()
{
	queue<int> q;
	q.push(1);
	q.push(2);
	q.push(3);
	q.pop();
	q.pop();
	return 0;
}

我们调试一下看看这个过程:

我们发现,每次pop(),就把队头的数据删除了,第一次pop(),删除了数据1,第二次pop()删除了数据2。

我们画图来展示一下这个过程:

empty()

判断队列是否为空。如果为空就返回真(1),如果不为空就返回假(0)。?

举个栗子:

int main()
{
	queue<int> q1;
	q1.push(1);
	q1.push(2);
	q1.push(3);
	cout << q1.empty() << endl;

	queue<int> q2;
	cout << q2.empty() << endl;
	return 0;
}

运行结果:

我们发现q1队列中有数据,所以就返回假。q2是一个空队列,于是就返回真。?

size()

返回队列中元素的个数。?

举个栗子:

int main()
{
	queue<int> q1;
	q1.push(1);
	q1.push(2);
	q1.push(3);
	cout << q1.size() << endl;

	queue<int> q2;
	cout << q2.size() << endl;
	return 0;
}

运行结果:

front()?

返回队列中队头元素的引用。?

举个栗子:

int main()
{
	queue<int> q1;
	q1.push(1);
	q1.push(2);
	q1.push(3);
	cout << q1.front() << endl;

	int& p = q1.front();
	p = 10;
	cout << q1.front() << endl;
	return 0;
}

运行结果:

我们发现第一次输出是取到了队头的数据。

并且我们知道返回的是队头数据的引用,那么是否可以修改呢??

我们通过int& p来接收返回值并修改,发现对头的数据的确被修改了!

注意:如果我们将来用引用变量接收了队头的返回值,我们为防止误操作把队头数据修改了,我们最好用const int& p来修饰。

back()

返回队尾中数据的引用。?

举个栗子:

int main()
{
	queue<int> q1;
	q1.push(1);
	q1.push(2);
	q1.push(3);
	cout << q1.back() << endl;

	int& p = q1.back();
	p = 30;
	cout << q1.back() << endl;
	return 0;
}

运行结果:

?我们发现第一次输出是取到了队尾的数据。

并且我们知道返回的是队尾数据的引用,那么是否可以修改呢??

我们通过int& p来接收返回值并修改,发现对头的数据的确被修改了!

注意:如果我们将来用引用变量接收了队尾的返回值,我们为防止误操作把队尾数据修改了,我们最好用const int& p来修饰。

swap()

交换两个队列中的数据。

举个栗子:

int main()
{
	queue<int> q1;
	q1.push(1);
	q1.push(2);
	q1.push(3);

	queue<int> q2;
	q2.push(10);
	q2.push(20);
	q2.push(30);

	q1.swap(q2);

	while (!q1.empty())
	{
		cout << q1.front() << " ";
		q1.pop();
	}
	cout << endl;
	while (!q2.empty())
	{
		cout << q2.front() << " ";
		q2.pop();
	}
	return 0;
}

运行结果:

我们发现q1原来的数据时1 2 3;q2原来的数据是10 20 30。

经过q1.swap(q2)后我们发现q1里面的数据是10 20 30。q2里面的数据是1 2 3?

注意:这里的swap不是算法库里面的,而是queue里面的成员函数~

queue的模拟实现

成员变量

template<class T,class Container = deque<T>>
private:
Container _con;

//第二个模板参数给一个缺省值(缺省值从右往左给)

template<class T,class Container = deque<T>>:Container是一个容器适配器,在这里我们默认使用deque<T>这样的容器。

_con:构造的指定容器的一个对象。模板参数是直接用,不可以Container<T>这样来操作。

? ? ? ? 这里的容器适配器也可以使用list<T>来代替。适配的容器只要支持queue内部实现方法对应的接口即可。

成员函数

bool empty() const

bool empty() const
{
	return _con.empty();
}

bool empty() const //判断队列是否为空
{
?? ?return _con.empty();//调用适配的容器的empty()的函数接口。
}

size_t size() const

size_t size() const
{
	return _con.size();
}

size_t size() const?
{
?? ?return _con.size(); //调用_con容器的size()的函数接口。
}

const T& front() const

const T& front() const
{
	return _con.front();
}

const T& front() const? //返回头部数据的引用,由于被const修饰,所以不能被修改
{
?? ?return _con.front(); //调用适配的容器的front()接口。_con适配的容器一定要有支持这样的接口。
}

T& front()?

T& front() 
{
	return _con.front();
}

T& front()? //与上面的函数构成函数重载,在这里返回的val值可以被修改
{
?? ?return _con.front();
}

const T& back() const

const T& back() const
{
	return _con.back();
}

const T& back() const?//返回尾部数据的引用,由于被const修饰,所以不能被修改
{
?? ?return _con.back();//调用适配的容器的back()接口。_con适配的容器一定要有支持这样的接口。
}

T& back()

T& back()
{
	return _con.back();
}

T& back()?//与上面的函数构成函数重载,在这里返回的val值可以被修改
{
?? ?return _con.back();
}

void push(const T& x)

void push(const T& x)
{
	_con.push_back(x);
}

void push(const T& x)?
{
?? ?_con.push_back(x);//往尾部插入数据,适配的容器要支持push_back()这样的函数接口
}

void pop()

void pop()
{
	_con.pop_front();
}

void pop()
{
?? ?_con.pop_front(); //删除头部数据,_con容器要支持头删这样的函数接口。像list就可以。

注意:vector不支持pop_front()、push_front(),所以不能当queue适配的容器。
}

完整代码

queue.h

#pragma once
#include<deque>
#include<iostream>
using namespace std;

namespace cyq
{
	template<class T,class Container = deque<T>>
	class queue
	{
	public:
		bool empty() const
		{
			return _con.empty();
		}
		size_t size() const
		{
			return _con.size();
		}
		const T& front() const
		{
			return _con.front();
		}
		T& front() 
		{
			return _con.front();
		}
		const T& back() const
		{
			return _con.back();
		}
		T& back()
		{
			return _con.back();
		}
		void push(const T& x)
		{
			_con.push_back(x);
		}
		void pop()
		{
			_con.pop_front();
		}
	private:
		Container _con;
	};
}

测试代码

int main()
{
	cyq::queue<int> q;
	q.push(1);
	q.push(2);
	q.push(3);
	q.push(4);
	q.push(5);

	cout << q.size() << endl;
	cout << "队尾数据:" << q.back() << endl;
	while (!q.empty())
	{
		cout << q.front() << " ";
		q.pop();
	}
	cout << endl;
	return 0;
}

运行结果:

总结?

? ? ? ? 我们发现C++中stack和queue的模拟实现都使用了容器适配器,很好地体现了复用的原则。通过模板可以让编译器自动推导存储的数据类型,这体现了泛型编程的特点。

可以通过与C语言中模拟实现队列来进行比较,看看其中代码的差距体现。在最上面有博客的链接~

1、queue是先进先出的规则,它不支持迭代器!所以也就不支持范围for(语法糖),和stack一样。

2、我们可以构造的方式:

queue<int,deque<int>> q; //使用deque容器

queue<int,list<int>> q; //使用list容器

3、我们发现我们模拟实现的queue没有自己实现构造函数,这样可以吗?答案是可以的。这里我们不需要自己显示实现构造函数,使用编译器默认生成的就可以。因为编译器默认生成的构造函数会自动调用适配的容器里面的构造函数(调用自定义类型的构造函数)。如果老铁们对这个知识点不理解,可以看一下我之前写的C++关于类和对象博客~ stack也是同理~

看到这里,给博主支持一下吧~

? ? ?

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-29 11:55:13  更:2022-04-29 11:57:01 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 21:50:51-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码