容器适配器stack,queue和priority_queue

Posted 两片空白

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了容器适配器stack,queue和priority_queue相关的知识,希望对你有一定的参考价值。

目录

一.什么是容器适配器

二.stack栈

2.1 stack的介绍

 2.2 stack的使用

 2.3 stack的模拟实现

三.queue队列

3.1 queue介绍

 3.2 queue的使用

 3.3queue的模拟实现

四.priority_queue优先队列

4.1priority_queue介绍

4.2 priority_queue使用

4.3优先队列的模拟实现


一.什么是容器适配器

        容器适配器是一个封装了序列容器的一个类模板,它在一般的序列容器的基础上提供了一些不同的功能。之所以称为容器适配器,是因为它是适配容器来提供其它不一样的功能。通过对应的容器和成员函数来实现我们需要的功能。

        下面介绍了三个容器适配器:statk<T>,queue<T>,priority_queue<T>。

        注意:容器适配器都不存在迭代器。

二.stack栈

2.1 stack的介绍

  1. stack是一种后进先出特点的容器适配器。其删除和插入操作只能在容器的一端进行。即只能在栈顶插入和弹出。
  2. stack的底层容器可以是任何标准的容器类模板或者其它特定的类容器(你设计的容器),但是这些容器必须支持以下操作:empty(判空),back(获取尾部元素),push_back(尾插),pop_back(尾删),size(获取元素大小)。
  3. vector,list,deque皆可作为stack的底层容器,默认情况下,如果没有为stack指定容器,默认使用deque作为默认容器。

 2.2 stack的使用

函数名称功能
stack()构造一个空栈
empty()判断栈是否为空,空返回true,非空返回false
size()返回栈元素个数
top()返回栈顶元素的引用
push()在栈顶插入元素
pop()将stack栈顶元素弹出

 使用stack需要包含头文件#include<stack>,stack不存在迭代器。

 2.3 stack的模拟实现

#include<iostream>
#include<deque>
#include<vector>
#include<list>
using namespace std;

namespace my{
	template<class T,class Container=deque<T>>

	class stack{
	public:
		bool empty(){
			return _con.empty();
		}
		size_t size(){
			return _con.size();
		}
		T& top(){
			return _con.back();
		}
		const T& top()const{
			return back();
		}
		void push(const T& val){
			_con.push_back(val);

		}
		void pop(){
			_con.pop_back();
		}
	private:
		Container _con;

	};

	void test_stack(){
		stack<int> s;

		s.push(1);
		s.push(2);
		s.push(3);
		s.push(4);

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

	void test_stack1(){
		stack<int,list<int>> s;

		s.push(1);
		s.push(2);
		s.push(3);
		s.push(4);

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

三.queue队列

3.1 queue介绍

        

  1.  队列是一种先进先出容器适配器,其中从容器的一段插入,另一端提取元素。在队尾插入,在对头弹出元素。
  2. 底层容器是标准容器类模板之一,也可以只用你专门设计的容器类,该容器必须支持empty(判空),front(获取队头元素的引用),back(获取队尾元素引用),push_back(尾插),pop_front(头删),size(获取元素大小)。
  3. vector,list和deque满足这些要求。默认情况下,没显示给出queue指定容器,默认使用deque。

 3.2 queue的使用

函数声明功能介绍
queue()构造空队列
size()返回队列中的元素个数
empty()判断队列是否为空
back()返回队尾元素引用
front()返回队头元素引用
push()在对尾插入元素
pop()将队头元素弹出

 使用queue需要包含头文件#include<queue>,queue容器适配器没有迭代器

 3.3queue的模拟实现

因为queue存在头删和尾插,因此使用vector容器来封装效率太低,头删需要挪动数据,并且vector并没有提供pop_front(),因为效率太低。

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

namespace my{
	template<class T, class Container = deque<T>>
	class queue{
	public:
        //会调用容器构造函数
		queue(){};
        //注意有隐含this指针
		size_t size()const{
			return _con.size();
		}
		bool empty()const{
			return _con.empty();
		}
		T& back(){
			return _con.back();
		}
		T& front(){
			return _con.front();
		}
		const T& back()const{
			return _con.back();
		}
		const T& front()const{
			return _con.front();
		}
		void push(const T& val){
			_con.push_back(val);
		}
		void pop()
		{
			_con.pop_front();
		}
	private:
		Container _con;
	};

	void test_queue1(){
		queue<int> q;
		q.push(1);
		q.push(2);
		q.push(3);
		q.push(4);

		cout << q.size() << endl;
		cout << q.back() << endl;
		cout << q.front() << endl;

		while (!q.empty()){
			cout << q.front() << " ";
			q.pop();
		}
		cout << endl;

	}
}

四.priority_queue优先队列

4.1priority_queue介绍

  1.  优先队列是容器适配器,根据若排序标准,它的第一个元素总是它所包含的元素中优先级最高的。(或许值是最大的,或许是最小的),就像数据结构里的
  2. 优先队列默认形成大堆
  3. 优先队列的元素从顶部弹出,顶部是优先级最高的。
  4. 底层容器可以是任何容器的类模板,也可以是其他特定设计的容器类(自己设计的),容器支持的功能:随机访问operator[],empty,size,front,push_back,pop_front。
  5. 标准容器vector和deque都可以满足这些需求,没显示定义容器模板时,优先队列默认使用vector。
  6. 优先队列使用仿函数来控制生成大根堆还是生成小根堆。

简单介绍一下仿函数:

        仿函数(Functor)又称为函数对象(Function Object)是一个能行使函数功能的类。仿函数的语法几乎和我们普通的函数调用一样,不过作为仿函数的类,都必须重载 operator() 运算符。因为调用仿函数,实际上就是通过类对象调用重载后的 operator() 运算符。仿函数是一个类,只是使用起来像函数。等下模拟实现时就知道了。

4.2 priority_queue使用

优先队列默认使用vector作为存储数据的容器,在容器的基础上使用堆算法,将vector中的元素调整成一个堆结构。

注意:优先队列就是一个堆,在使用堆的地方都可以使用优先队列。默认生成大根堆,头文件也是#include<queue>

函数功能
priority_queue()建立一个空优先队列
priority_queue(first,last)将迭代器first到last之间的元素建堆
top返回优先级队列中优先级最高元素,即堆顶元素
size返回优先队列里的元素个数
empty判断优先队列是否为空
push往优先队列中插入元素
pop删除优先级队列中优先级最高元素,即堆顶元素

 注意:如果在priority_queue中放自定义类型的数据,即在存储数据的容器中放自定义类型数据需要将操作符<和>重载,因为要进行调整称堆。

4.3优先队列的模拟实现

        回顾一下堆的插入与删除操作。

        堆的插入:在堆尾插入数据,再向上调整成堆。

        堆的删除:将堆顶元素和对尾元素交换,再向下调整成堆。

不带仿函数:

        调整函数:

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

namespace my{
	template<class T,class Container = vector<T>>
	class priority_queue{
	public:
		priority_queue(){};
		template<class inputiterator>
		priority_queue(inputiterator first, inputiterator last){
			while (first != last){
				push(*first);
				first++;
			}
		}
		bool empty(){
			return _con.empty();
		}
		size_t size(){
			return _con.size();
		}
		T& top(){
			return _con.front();
		}
		const T& top()const{
			return _con.front();
		}
		void push(const T& val){
			_con.push_back(val);
			Adjustup(_con.size() - 1);
		}
		void pop(){
			swap(_con[0], _con[_con.size() - 1]);
			//少一个元素是size减减,交换后,直接删除最后一个元素
			_con.pop_back();
			Adjustdown(0);
		}
	private:
		void Adjustup(int child){
			int parent = (child - 1) / 2;
			while (child > 0){
				if (_con[child] > _con[parent]){
					swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else{
					break;
				}
			}
		}

		void Adjustdown(int parent){
			int child = parent * 2 + 1;
			//不能减1,如果没有元素size()为0,类型size_t,减1就是最大的数(正数),会进入循环
			while ((size_t)child < _con. size() ){
				if (child + 1 < _con.size() && _con[child + 1] > _con[child]){
					child++;
				}
				if (_con[child]>_con[parent]){
					swap(_con[child], _con[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else{
					break;
				}
			}
		}

		Container _con;
	};

	void test_priority_queue(){
		int array[] = { 8, 4, 6, 2, 10 };
		priority_queue<int> pq(array, array + sizeof(array) / sizeof(int));
		cout << pq.size() << endl;

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

	}
}

仿函数:优先队列通过仿函数来实现建立大根堆还是小根堆。

调整建立大根堆还是小根堆,只需要改变调整函数。父亲结点与孩子结点比较时的大于小于号。怎么通过仿函数来实现呢?

调整函数怎么修改:

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

namespace my{
	template<class T>
	struct less{
		bool operator()(const T& left,const T& right){
			return left < right;
		}
	};
	template<class T>
	struct greater{
		bool operator()(const T& left, const T& right){
			return left>right;
		}
	};


	template<class T,class Container = vector<T>,class Compare=less<T>>
	class priority_queue{
	public:
		priority_queue(){};
		template<class inputiterator>
		priority_queue(inputiterator first, inputiterator last){
			while (first != last){
				push(*first);
				first++;
			}
		}
		bool empty(){
			return _con.empty();
		}
		size_t size(){
			return _con.size();
		}
		T& top(){
			return _con.front();
		}
		const T& top()const{
			return _con.front();
		}
		void push(const T& val){
			_con.push_back(val);
			Adjustup(_con.size() - 1);
		}
		void pop(){
			swap(_con[0], _con[_con.size() - 1]);
			//少一个元素是size减减,交换后,直接删除最后一个元素
			_con.pop_back();
			Adjustdown(0);
		}
	private:
		void Adjustup(int child){
			int parent = (child - 1) / 2;
			Compare com;
			while (child){
				if (com(_con[parent],_con[child])){
					swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else{
					break;
				}
			}
		}

		void Adjustdown(int parent){
			int child = parent * 2 + 1;
			//定义一个对象
			Compare com;
			//不能减1,如果没有元素size()为0,类型size_t,减1就是最大的数(正数),会进入循环
			while ((size_t)child < _con. size() ){
				
				if (child + 1 < _con.size() && com(_con[child], _con[child + 1])){
					child++;
				}
				if (com(_con[parent], _con[child])){
					swap(_con[child], _con[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else{
					break;
				}
			}
		}

		Container _con;
	};

	void test_priority_queue(){
		int array[] = { 8, 4, 6, 2, 10 };
		priority_queue<int,vector<int>,greater<int>> pq(array, array + sizeof(array) / sizeof(int));
		cout << pq.size() << endl;

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

	}
}

        


 

        

        

以上是关于容器适配器stack,queue和priority_queue的主要内容,如果未能解决你的问题,请参考以下文章

C++入门stack和queue适配器介绍+ priority_queue的模拟实现仿函数基本概念提及

stl——容器适配器

[C/C++]详解STL容器3--stackqueue和priority_queue的功能和模拟实现,deque和容器适配器的介绍

C++stack和queue及适配器的学习使用

C++stack&queue(栈队列优先级队列)

C++stack&queue(栈队列优先级队列)