stack_queue | priority_queue | 仿函数

这篇具有很好参考价值的文章主要介绍了stack_queue | priority_queue | 仿函数。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. stack 的使用

stack_queue | priority_queue | 仿函数,c++,算法,c语言

栈不在是一个容器,而是一个容器适配器 ,
stack的模板中第二个deque暂时不知道干什么的,后面会说


stack_queue | priority_queue | 仿函数,c++,算法,c语言

说明stack是一个容器适配器,并且为了保证严格的先进后出,所以不存在迭代器


stack_queue | priority_queue | 仿函数,c++,算法,c语言
#include<iostream>
#include<stack>
using namespace std;


int main()
{
	stack<int>v;
	v.push(1);
	v.push(2);
	v.push(3);
	v.push(4);
	while (!v.empty())//后进先出的原则
	{
		cout << v.top() << " ";//4 3 2 1
		v.pop();
	}
	return 0;
}

2. stack的模拟实现

#include<iostream>
#include<vector>
#include<list>
#include<stack>
#include<queue>
using namespace std;
namespace yzq
{
	//适配器模式
	template<class T, class Container = deque<T>>//给与缺省值
	//deque 作为一个双端队列,可以非常适用与大量 头插 头删 尾插 尾删 的情况
	class stack
	{
	public:
		void push(const T& x)//插入
		{
			_con.push_back(x);//尾插
		}
		void pop()//删除栈顶元素
		{
			_con.pop_back();  
		}
		const T& top()//栈顶
		{
			return _con.back();
		}
		size_t size()//大小
		{
			return _con.size();
		}
		bool empty()//判空
		{
			return _con.empty();
		}
	private:
		Container _con;//Container 是一个符合要求的容器

	};//适配器模式
	void test()
	{
		yzq::stack<int>v;
		v.push(1);
		v.push(2);
		v.push(3);
		v.push(4);

		while (!v.empty())
		{
			cout << v.top() << " ";
			v.pop();
		}
		cout << endl;
	}
	
	
}



这里假设我们不认识 deque,那么如果stack频繁使用pop尾删,将vector< T >设置成缺省值也是非常适合的

3. queue的使用

stack_queue | priority_queue | 仿函数,c++,算法,c语言

队列同样不在是一个容器,而是一个容器适配器


stack_queue | priority_queue | 仿函数,c++,算法,c语言

说明queue为了保证严格的先进先出,所以不存在迭代器


stack_queue | priority_queue | 仿函数,c++,算法,c语言
#include<iostream>
#include<stack>
#include<queue>
using namespace std;



int main()
{
	queue<int>v;
	v.push(1);
	v.push(2);
	v.push(3);
	v.push(4);
	while (!v.empty())//符合先进先出的原则
	{
		cout << v.front() << " ";//1 2 3 4
		v.pop();
	}
	return 0;
}

4. queue的模拟实现

#pragma once
namespace yzq
{
	template<class T, class Container=deque<T>>//给与缺省值,默认使用list<T>
	class queue
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}
		void pop()
		{
			_con.pop_front();  //vector没有头删,强行使用erase 效率太低
		}
		const T& front()
		{
			return _con.front();
		}
		const T& back()
		{
			return _con.back();
		}
		size_t size()
		{
			return _con.size();
		}
		bool empty()
		{
			return _con.empty();
		}
	private:
		Container _con;//Container 是一个符合要求的容器
		
	};
}

这里假设我们不认识 deque,那么如果stack频繁使用pop头删,将 list< T >设置成缺省值也是非常适合的

5. deque ——双端队列

stack_queue | priority_queue | 仿函数,c++,算法,c语言


可以在头尾双端进行插入和删除的操作,且时间复杂度为O(1),与vetcor比较,头插效率高,不需要移动元素,
与list比较,空间利用比较高


stack_queue | priority_queue | 仿函数,c++,算法,c语言


而deque就是要综合两者的优点 (想法很美好)
deque并不是真正的连续的空间,而是由一段段连续的小空间拼接而成的
一段段的小数组,若满了不扩容,在开辟一块空间,通过中控(指针数组)的方式将一个个小数组管理起来
第一个buf数组,开的是中控指针数组中间的位置

头插:

stack_queue | priority_queue | 仿函数,c++,算法,c语言

尾插:

stack_queue | priority_queue | 仿函数,c++,算法,c语言

若中控满了,就要扩容,但是扩容代价低
若为vector,本来为100个int空间,需要200个空间,就需要扩容2倍
而 中控是一个指针数组,里面都是指针,可能只需要20个指针就搞定了,所以扩容代价相对于低一些


deque优缺点

优点:
1.相比于vector,扩容代价低
2. 头插 头删,尾插尾删效率高
3. 支持随机访问


缺点:
1.中间插入删除很难搞
若中间插入删除效率高,会影响随机访问的效率,牺牲中间插入删除的效率,随机访问效率就变高了
2.没有vector和list优点极致
deque你说它跟vector比随机访问,速度不如vector,跟list比任意位置插入删除,效率没list高 ,这种就搞的很难啦,哪一项都不突出,但是都会一点


栈和队列都是需要大量的头插头删,尾插尾删的,而deque在这个场景下效率很高,所以deque被当作栈和队列的默认适配容器

6. priority_queue ——优先级队列

1. priority_queue的使用

stack_queue | priority_queue | 仿函数,c++,算法,c语言

底层是一个堆,默认容器使用vector, 最后一个模板参数代表仿函数 默认使用 less 代表小于 (后面会讲)


stack_queue | priority_queue | 仿函数,c++,算法,c语言
#include<iostream>
#include<queue>
#include<functional>
using namespace std;
int main()
{
	priority_queue<int, vector<int>>v;
	//默认为大堆,数据大的优先级高
	v.push(4);
	v.push(8);
	v.push(6);
	v.push(2);
	while (!v.empty())
	{
		cout << v.top() << " "; //8 6 4 2
		v.pop();
	}
	return 0;
}

正常来说,默认建立大堆,所以数据大的优先级高


#include<iostream>
#include<queue>
#include<functional>
int main()
{
	priority_queue<int,vector<int>,greater<int>>v;//greater作为仿函数
	//设置小堆,让小的优先级高
	v.push(4);
	v.push(8);
	v.push(6);
	v.push(2);
	while (!v.empty())
	{
		cout << v.top() << " "; //2 4 6 8
		v.pop();
	}
	return 0;
}

但若加入仿函数 greater 后,则会建立小堆,所以数据小的优先级高

2. priority_queue的模拟实现

由于是自己实现的所以要加上命名空间,避免冲突

push——插入
void adjustup(int child)//向上调整算法
		{
			Compare com;
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				//建大堆
				if (com(_con[parent] ,_con[child]))
				{
					swap(_con[parent], _con[child]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}
void push(const T&x)
		{
			_con.push_back(x);
			adjustup(_con.size() - 1);//向上调整算法
		}

由于是堆的插入,而堆本身也是由数组的数据构成的,所以数组加入一个数据相当于在堆最后插入一个数据,在通过向上调整算法依次交换, 不懂向上调整算法的点击这里

pop ——删除
void adjustdown(int parent)//向下调整算法
		{
			Compare com;
			int child = parent * 2+1;//假设为左孩子
			while (child<_con.size())
			{
				//建大堆
				if (child+1 < _con.size()&&com(_con[child],_con[child + 1]))
					//child+1是防止右孩子不存在导致越界
				{
					child++;
				}
				if (com(_con[parent] ,_con[child]))//将两者换一种说法,使之能=能够调用<即可
				{
					swap(_con[parent], _con[child]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}
void pop()
		{
			swap(_con[0], _con[_con.size() - 1]);//首尾交换
			_con.pop_back();//尾删
			adjustdown(0);//向下调整算法
		}

由于要删除堆顶的数据,所以交换堆尾与堆顶数据,在删除堆尾数据,默认容器为vector,所以有pop_back 尾删的功能,而此时堆顶的数据不符合当前的位置,所以需要借助向下调整算法把该数据调整到合适的位置 不懂向下调整算法的点击这里

top —— 堆顶
const T& top()
		{
			return _con[0];
		}

堆是借助数组来实现的,所以堆顶的数据就是当前的第一个数据

仿函数问题
template <class T>
	struct Less
	{
		bool operator()(const T& x, const T& y)
		{
			return x < y;
		}
	};
	template <class T>
	struct greater
	{
		bool operator()(const T& x, const T& y)
		{
			return x > y;
		}
	};

仿函数主要是借助两个类 来重载 运算符 ( ) ,
而 Less ( x<y) 用于 建立大堆 ,greater (x>y) 用于建立小堆


stack_queue | priority_queue | 仿函数,c++,算法,c语言

Less / greater 分别都是类名 ,而模板参数 Compare 需要类型
所以 都需要加上 ,即 Less< T> / greater < T >


通过该类型在向上/向下调整算法中分别建立对象,通过对象调用对应类less/greater的重载()从而达到目的

stack_queue | priority_queue | 仿函数,c++,算法,c语言
若为默认类型Less,则调用x <y ,从而建大堆


stack_queue | priority_queue | 仿函数,c++,算法,c语言

当传入greater< T >类型后,调用对象,找到对应greater类型的重载() ,调用 x >y ,从而建小堆文章来源地址https://www.toymoban.com/news/detail-792529.html

完整代码实现
#include<iostream>
#include<queue>
using namespace std;
namespace yzq
{
	template <class T>
	struct Less
	{
		bool operator()(const T& x, const T& y)
		{
			return x < y;
		}
	};
	template <class T>
	struct greater
	{
		bool operator()(const T& x, const T& y)
		{
			return x > y;
		}
	};
	template<class T, class Container=vector<T>,class Compare=Less<T> >
	class priority_queue//优先级队列
	{
	public:
		void adjustup(int child)//向上调整算法
		{
			Compare com;
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				//建大堆
				if (com(_con[parent] ,_con[child]))
				{
					swap(_con[parent], _con[child]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}
		void adjustdown(int parent)//向下调整算法
		{
			Compare com;
			int child = parent * 2+1;//假设为左孩子
			while (child<_con.size())
			{
				//建大堆
				if (child+1 < _con.size()&&com(_con[child],_con[child + 1]))
					//child+1是防止右孩子不存在导致越界
				{
					child++;
				}
				if (com(_con[parent] ,_con[child]))//将两者换一种说法,使之能=能够调用<即可
				{
					swap(_con[parent], _con[child]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}
		void push(const T&x)
		{
			_con.push_back(x);
			adjustup(_con.size() - 1);//向上调整算法
		}
		void pop()
		{
			swap(_con[0], _con[_con.size() - 1]);//首尾交换
			_con.pop_back();//尾删
			adjustdown(0);//向下调整算法
		}
		const T& top()
		{
			return _con[0];
		}
		size_t size()
		{
			return _con.size();
		}
		bool empty()
		{
			return _con.empty();
		}
	private:
		Container _con;//使用vector实现
	};
}

int main()
{
	//yzq::priority_queue<int>v;
	yzq::priority_queue<int,deque<int>,greater<int>>v;
	v.push(1);
	v.push(5);
	v.push(8);
	v.push(4);
	while (!v.empty())
	{
		cout << v.top() << " ";
		v.pop();
	}
	return 0;
}

到了这里,关于stack_queue | priority_queue | 仿函数的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++】STL中的容器适配器 stack queue 和 priority_queue 的模拟实现

    适配器是一种设计模式 (设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该种模式是将一个类的接口转换成客户希望的另外一个接口。 例如我们常见的充电器就是一种适配器,它将我们常用的220V交流电压转化为4,5V (或者其他更高的电

    2023年04月26日
    浏览(48)
  • 容器适配器---deque和STL ---stack queue priority_queue的模拟实现 C++

    目录 一、容器适配器 deque原理 deque的缺陷 deque的优势 二、stack的模拟实现  三、queue的模拟实现 四、优先级队列的模拟实现 适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该种模式是将一个类的接口转换成客户

    2024年02月02日
    浏览(43)
  • 从C语言到C++_20(仿函数+优先级队列priority_queue的模拟实现+反向迭代器)

    目录 1. priority_queue的模拟实现 1.1 未完全的priority_queue 1.2 迭代器区间构造和无参构造 1.3 仿函数的介绍和使用 1.4 完整priority_queue代码: 1.5 相关笔试选择题 答案: 2. 反向迭代器 2.1 反向迭代器的普通实现 reverse_iterator.h(不对称版) 2.2 反向迭代器的对称实现 reverse_iterator.

    2024年02月10日
    浏览(38)
  • C++ | 仿函数与priority_queue

    目录 前言 一、初始仿函数 1、仿函数是什么 2、仿函数的使用  二、优先级队列 1、 优先级队列的基本概念 2、堆的储存结构与结点之前关系 3、堆的使用 4、堆的模拟实现         本文主要介绍优先级队列与仿函数,优先级队列实际上是我们在数据结构中学的堆;在介绍

    2024年02月15日
    浏览(29)
  • STL之priority_queue与仿函数

    1.介绍 函数对象,又称仿函数,是可以像函数一样使用的对象,其原理就是重载了函数调用符: () 因此在此类中,一定有 operator() 的成员函数。 2.示例 如果T是内置类型,则直接进行比较。如果T是自定义类型,则会调用其operator()。 先创建一个_less类型的对象smaller,对于sma

    2024年02月10日
    浏览(27)
  • 【C++】容器适配器之priority_queue & 仿函数

    我们和学习之前的容器一样,可以使用cplusplus官网进行学习:priority_queue文档介绍 priority_queue(优先级队列)是一种容器适配器,它 和queue使用同一个头文件,其底层结构是一个堆,并且默认情况下是一个大根堆,此外,priority_queue也不支持迭代器,这是为了不破坏堆的结构使用

    2024年02月01日
    浏览(32)
  • C++ sort()函数和priority_queue容器中比较函数的区别

    普通的queue是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除。 priority_queue中元素被赋予优先级。在创建的时候根据优先级进行了按照从大到小或者从小到大进行了自动排列(大顶堆or小顶堆)。可以以O(log n) 的效率查找一个队列中的最大值或者最小值; 虽然两

    2023年04月09日
    浏览(30)
  • 【C++】详解priority_queue(优先级队列)与函数对象

    目录 一、priority_queue 的介绍和使用 1.1priority_queue 的介绍 2.2priority_queue 的使用 二、仿函数 2.1什么是仿函数 2.2仿函数的作用 三、函数对象的特点(知识点多) 3.1分析特点5(比较普通函数与函数对象) 3.1.1利用普通函数传递参数 拓展之:深度剖析函数利用模板的本质 3.1.2利用

    2024年02月08日
    浏览(30)
  • 【C++初阶】仿函数和priority_queue的模拟实现(附源码)

    仿函数,顾名思义就是 模仿函数,它其实是一个类,类里面重载了运算符() ,在调用这个重载的运算符时,让我们感觉是调用函数一样,可以说相当于C语言里的函数指针一样,但是函数指针的可读性不好,不如仿函数。 1.仿函数即使定义相同,也可能有不同的类型; 2.仿

    2024年02月16日
    浏览(24)
  • 【C++】STL使用仿函数控制优先级队列priority_queue

    本文章讲解C++STL的容器适配器:priority_queue的实现,并实现仿函数控制priority_queue底层。 priority_queue叫做优先级队列,它的底层结构是堆,在库中,默认生成的是大堆 在库的实现中,使用vector作为该优先级队列的适配容器。 由于priority_queue也是一个适配器,所以它的接口函数

    2024年02月16日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包