iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++ STL中的容器适配器实现
  • 444
分享到

C++ STL中的容器适配器实现

2024-04-02 19:04:59 444人浏览 泡泡鱼
摘要

1 stack 1.1 stack 介绍  stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入与提取操作。

1 stack

1.1 stack 介绍

  •  stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入与提取操作。
  • stack是作为容器适配器被实现的,容器适配器即是对特定类封装作为其底层的容器,并提供一组特定的成员函数来访问其元素,将特定类作为其底层的,元素特定容器的尾部(即栈顶)被压入和弹出。
  • stack的底层容器可以是任何标准的容器类模板或者一些其他特定的容器类,这些容器类应该支持以下操作:empty:判空操作、back:获取尾部元素操作、push_back:尾部插入元素操作、pop_back:尾部删除元素操作
  • 标准容器vector、deque、list均符合这些需求,默认情况下,如果没有为stack指定特定的底层容器,默认情况下使用deque。

在这里插入图片描述

1.2 stack 使用

接口说明

在这里插入图片描述

1.3 stack 模拟实现


namespace czh
{
	template<class T, class Container = deque<T>>
	// template<class T, class Container = list<T>>
	// template<class T, class Container = vector<T>>
	class stack
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}

		void pop()
		{
			_con.pop_back();
		}
        T& top()
		{
			return _con.back();
		}
		const T& top() const
		{
			return _con.back();
		}

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

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

	private:
		Container _con;
	};
}

1.4 deque 的简单介绍

原理

1、deque(双端队列):是一种双开口的"连续"空间的数据结构,注意和 queue 没有关系双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率比较高。
2、deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个动态的二维数组

在这里插入图片描述

3、双端队列底层是一段假象的连续空间,实际是分段连续的,为了维护其“整体连续”以及随机访问的假象,落在了deque的迭代器身上,因此deque的迭代器设计就比较复杂,如下图所示:

在这里插入图片描述

缺陷

与vector比较,deque的优势是:头部插入和删除时,不需要搬移元素,效率特别高,而且在扩容时,也不需要搬移大量的元素,因此其效率是比 vector 高的。

与list比较,其底层是连续空间,空间利用率比较高,不需要存储额外字段。

但是,deque有一个致命缺陷:不适合遍历,因为在遍历时,deque的迭代器要频繁的去检测其是否移动到某段小空间的边界,导致效率低下,而序列式场景中,可能需要经常遍历,因此在实际中,需要线性结构时,大多数情况下优先考虑vector和list,deque的应用并不多,而目前能看到的一个应用就是,STL用其作为stack和queue的底层数据结构。

为何作为stack 和 queue的 默认 实现

stack是一种后进先出的特殊线性数据结构,因此只要具有push_back()pop_back()操作的线性结构,都可以作为stack的底层容器,比如vector和list都可以;queue是先进先出的特殊线性数据结构,只要具有push_backpop_front操作的线性结构,都可以作为queue的底层容器,比如list。

但是STL中对stack和queue默认选择deque作为其底层容器,主要是因为:

stack 和 queue 不需要遍历(因此stack 和 queue没有迭代器),只需要在固定的一段或者两端进行操作。

在 stack 中元素增长时,deque 比 vector 的效率高(扩容时候不需要搬移大量数据);queue 中的元素增长时,deque 不仅效率高,而且内存使用率也高。

所以结合了deque的优点,完美递避开了其缺陷

2 queue

2.1 queue 介绍

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

2.2 queue 使用

接口介绍

在这里插入图片描述

2.3 queue 模拟实现

因为queue的接口中存在头删和尾插,因此使用vector来封装效率太低,故可以借助list 和 deque 来模拟实现queue


namespace czh
{
	// 设计模式 -- 适配器模式(配接器)
	template<class T, class Container = deque<T>>
	class queue
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}

		void pop()
		{
			_con.pop_front();
		}
        T& front()
		{
			return _con.front();
		}
		const T& front() const
		{
			return _con.front();
		}
		T& back()
		{
			return _con.back();
		}
		const T& back() const
		{
			return _con.back();
		}

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

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

	private:
		Container _con;
	};
}

3 priority_queue

3.1 priority_queue 介绍

优先级队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的那一个。
内部实现其实是堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先级队列中位于顶部的元素)。
底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭代器访问,并支持以下操作:empty():检测容器是否为空、size():返回容器中有效元素个数、front():返回容器中第一个元素的引用、push_back():在容器尾部插入元素、pop_back():删除容器尾部元素
标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector。
需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数,make_heap、push_heap和pop_heap来自动完成此操作。

3.2 priority_queue 使用

优先级队列默认使用 vector 作为其底层存储数据的容器,在 vector 上又使用了堆算法将 vector 中元素构成堆的结构,因此 priority_queue 就是堆,所以所有需要用到堆的位置,都可以考虑使用priority_queue。注意:默认priority_queue 是大堆。通过仿函数可以改变其为小堆。


#include <iOStream>
#include <vector>
#include <queue>
#include <functional> // greater算法的头文件
void TestPriorityQueue()
{
 // 默认情况下,创建的是大堆,其底层按照小于号比较
 vector<int> v{3,2,7,6,0,4,1,9,8,5};
 priority_queue<int> q1;
 for (auto& e : v)
 q1.push(e);
 cout << q1.top() << endl;
 // 如果要创建小堆,将第三个模板参数换成greater比较方式
 priority_queue<int, vector<int>, greater<int>> q2(v.begin(), v.end());
 cout << q2.top() << endl; 
 
 }

3.3 仿函数的引入

仿函数准确来说是一个类,这个类重载了operator(),这个类的对象调用 operator(),可以像函数一样去使用,在优先级队列中的使用可以控制创建的优先级队列中是大堆还是小堆使其可以像水龙头的开关一样可以去控制热水还是凉水。在 STL库中中的两个仿函数的实现如下:

STL 中的优先级队列

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

举例说明仿函数的应用

比如我们想买个手机,在京东上搜索手机,可以按照价格、销量等标签排序,那么我们可以利用仿函数简单实现,写一个商品类代表手机我们用排序算法 sort 对其排序,但是我们不可以在类的内部重载 > < 运算符,因为我们并不知道如何排序,按照什么标准排序,为了更好说明问题,来盘代码。

在这里插入图片描述


#include <iostream>
#include "priority_queue.h"
#include <alGorithm>
#include <vector>

using namespace std;

//仿函数的应用
struct Phone{
	int saleNum;
	int price;
	//.....
};
struct LessPhonePrice{
	bool operator()(const Phone& p1, const Phone& p2)
	{
		return p1.price < p2.price;
	}
};
struct LessPhoneSaleNum{
	bool operator()(const Phone& p1, const Phone& p2)
	{
		return p1.saleNum < p2.saleNum;
	}
};
void TestSort()
{
	vector <Phone> gv = { { 1, 3 }, { 5, 2 }, { 2, 10 } };
	sort(gv.begin(), gv.end(),LessPhoneSaleNum());//匿名对象会在STL中调用我自己写的比较方法
	sort(gv.begin(), gv.end(), LessPhonePrice());

}
int main()
{
	TestSort();
	return 0;
}

在这里插入图片描述

在这里插入图片描述

3.4 priority_queue 模拟实现

因为优先级队列的底层结构就是堆所以对 vector 进行适当封装就可以了,如果不知道堆的知识请参考我的另外一篇文章 https://www.jb51.net/article/210171.htm


#pragma once

//仿函数
template<class T>
class Less{
public:
	bool operator()(const T& t1, const T& t2) const
	{
		return t1 < t2;
	}
};

template<class T>
class Greater{
public:
	bool operator()(const T& t1, const T& t2) const
	{
		return t1 > t2;
	}
};
namespace czh{

	template<class T, class Container = vector<T>, class Compare = Greater<T>>
	class priority_queue {

	public:
		priority_queue() = default;
		

		template<class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
			:_con(first, last)
		{
			//利用向下调整算法,从下到上建堆
			
			利用向上调整算法,从上到下调整
			for (size_t i = 1; i < _con.size(); i++)
			{
				AdjustUp(i);
			}
		}
		void push(const T& data)
		{
			_con.push_back(data);
			// 向上调整
			AdjustUp(_con.size() - 1);
		}
		void pop()
		{
			if (empty()) return;

			swap(_con.front(),_con.back());
			_con.pop_back();
			AdjustDown(0);
		}
		size_t size() const
		{
			return _con.size();
		}
		const T& top() const
		{ 
			return _con.front();
		}
		bool empty() const
		{
			return _con.empty();
		}
	private:
		//向上调整算法
		void AdjustUp(int child)
		{
			Compare com;
			int parent = (child - 1) >> 1;
			while (child > 0)
			{
				
				if (com(_con[child], _con[parent]))
				{
					swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) >> 1;
				}
				else
				{
					break;
				}
			}
		}
		void AdjustDown(int parent)
		{
			Compare com;
			size_t child = 2 * parent + 1;
			while (child < _con.size())
			{
				
				if (child + 1 < _con.size() && com(_con[child + 1], _con[child]))
				{
					child++;
				}
				
				if (com(_con[child], _con[parent]))
				{
					swap(_con[child], _con[parent]);
					parent = child;
					child = 2 * parent + 1;
				}
				else
				{
					break;
				}
			}
		}
		//向下调整算法
		Container _con;
	};
}

4 容器适配器模式

适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该种模式是将一个类的接口转换成客户希望的另外一个接口。
上面介绍的3种数据结构都是容器适配器(container adapter)。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

到此这篇关于c++ STL中的容器适配器实现的文章就介绍到这了,更多相关C++ STL容器适配器内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C++ STL中的容器适配器实现

本文链接: https://www.lsjlt.com/news/124107.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C++ STL中的容器适配器实现
    1 stack 1.1 stack 介绍  stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入与提取操作。 ...
    99+
    2024-04-02
  • C++ STL中容器适配器怎么实现
    这篇文章给大家分享的是有关C++ STL中容器适配器怎么实现的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1 stack1.1 stack 介绍 stack是一种容器适配器,专门用在具有后进先出操作的上...
    99+
    2023-06-14
  • C++ STL容器适配器使用指南
    目录适配器stack容器适配器✒️stack的介绍✏️stack的使用✏️stack的模拟实现queue✒️queue的介绍✏️queue的使用✏️queue的模拟实现deque容器...
    99+
    2024-04-02
  • C++实现STL容器的示例
    各大容器的特点: 1.可以用下标访问的容器有(既可以插入也可以赋值):vector、deque、map; 特别要注意一下,vector和deque如果没有预先指定大小,是不能用下标法...
    99+
    2024-04-02
  • C++如何实现STL容器
    这篇文章给大家分享的是有关C++如何实现STL容器的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。各大容器的特点:可以用下标访问的容器有(既可以插入也可以赋值):vector、deque、map;特别要注意一下,v...
    99+
    2023-06-29
  • 怎么用C++模拟实现STL容器
    这篇文章主要介绍了怎么用C++模拟实现STL容器的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇怎么用C++模拟实现STL容器文章都会有所收获,下面我们一起来看看吧。一、list的介绍列表是一种顺序容器,它允许在...
    99+
    2023-07-04
  • 利用C++模拟实现STL容器:list
    目录一、list的介绍二、list的排序三、迭代器1、list的迭代器失效问题2、迭代器的功能分类3、list迭代器的模拟实现4、迭代器价值5、迭代器operator->的重载...
    99+
    2022-12-08
    C++实现STL容器list C++ STL容器list C++ STL容器
  • C++STL中vector容器的使用
    目录一、vector(1)区分size()和capacity()(2)迭代器失效(3)区分const_iterator和const iterator(4)区分reserve()和re...
    99+
    2024-04-02
  • C++ 容器适配器priority_queue的使用及实现代码
    优先级队列(Priority Queue) 队列是一种特征为FIFO的数据结构,每次从队列中取出的是最早加入队列中的元素。但是,许多应用需要另一种队列,每次从队列中取出的应是具有最...
    99+
    2024-04-02
  • c++中stl容器干什么用的
    stl 容器在 c++ 中的作用是存储和管理各种类型的数据,从而提供数据组织、内存管理、通用性、效率和可扩展性等优势。 STL 容器在 C++ 中的作用 STL(标准模板库)容器是包含...
    99+
    2024-05-06
    c++ 标准库
  • C++STL容器中string类怎么用
    这篇文章将为大家详细讲解有关C++STL容器中string类怎么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。前言为什么学习string类:在C语言中,字符串是以'\0'结尾的集合,为了...
    99+
    2023-06-29
  • C++ STL 序列式容器与配接器的简单使用
    目录容器概述序列式容器 array vector list deque forward_list Adapter(配接器) stack queue priority_queue 容器...
    99+
    2024-04-02
  • C++ STL反向迭代器的实现
    反向迭代器其实就行对正向迭代器进行封装,源生迭代器,为了实现运算符的结果不同,正向迭代器也对源生迭代器进行了封装。 反向迭代器的适配器,就是 Iterator是哪个容器的迭代器,re...
    99+
    2024-04-02
  • C++ 容器适配器priority_queue怎么用
    这篇文章给大家分享的是有关C++ 容器适配器priority_queue怎么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。优先级队列(Priority Queue)队列是一种特征为FIFO的数据结构,每次从队列...
    99+
    2023-06-14
  • 如何在C++中使用 STL 顺序容器
    今天就跟大家聊聊有关如何在C++中使用 STL 顺序容器,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。C++ 标准模板库 STL 顺序容器容器数据结构顺序性重复性支持迭代器vecto...
    99+
    2023-06-15
  • C++中STL的vector扩容机制
    目录 前言发生扩容扩容机制size()和capacity()reserve()和resize() 前言 前阵子面试的时候,被问到往vector中插入一个数据可能会发生什么? ...
    99+
    2023-08-31
    c++ java 面试
  • C++容器适配器的概念与示例
    目录一. 什么是适配器与容器适配器二. 理解容器适配器stack的模拟实现queue的模拟实现一. 什么是适配器与容器适配器 适配器是一种设计模式(设计模式是一套被反复使用的,多数人...
    99+
    2023-01-14
    C++容器适配器 C++适配器
  • C++浅析STL 迭代器 容器的使用
    目录STL定义STL六大组件vectorvector嵌套容器STL定义 STL(Standard Template Library 标准模板库)STL从广义上分为:容器(contai...
    99+
    2024-04-02
  • C++ STL容器详解之红黑树部分模拟实现
    目录一、红黑树的概念二、红黑树的性质三、红黑树节点的定义四、红黑树结构 五、 红黑树的插入操作六、代码总结一、红黑树的概念 红黑树(Red Black Tree),是在计算机科学中用...
    99+
    2024-04-02
  • C++ STL容器中红黑树部分模拟实现的示例分析
    这篇文章主要介绍了C++ STL容器中红黑树部分模拟实现的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、红黑树的概念红黑树(Red Black Tree...
    99+
    2023-06-21
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作