栈和队列&优先级队列&适配器原理

栈和队列接口函数

stack 栈接口函数

因为栈的结构限制,栈只能栈顶push和栈顶pop,

所以接口略少

queue 队列接口函数

队列只比栈多了一个接口:back
队列的front相当于栈的top

适配器

栈的类模板

其中第二个参数是Container,

且缺省参数为deque<T>

到这就可以引入一个概念:适配器

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

可以类比为

在数据结构的栈中,这种适配器是什么?

在C语言阶段实现栈时,我们
使用的底层是顺序表来实现,也就是
把顺序表做了一层封装和限制,让它
的功能变得和栈一样,C++这里也是一样!

实现栈时不用再去写一个顺序表
而是直接调用库中的vector!

队列的类模板

其中第二个参数是Container,

且缺省参数为deque<T>

和stack是一样的

栈和队列模拟实现

namespace wr
{
	template<class T, class Container>
		class stack
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}
		void pop()
		{
			_con.pop_back();
		}
		const T& top()
		{
			return _con.back();
		}
		bool empty()
		{
			return _con.empty();
		}
		size_t size()
		{
			return _con.size();
		}
	private:
		Container _con;
	};
}

队列

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

}

我们和库中的缺省值保持一致,使用deque

这样实现栈十分方便,因为此时的栈就好像继承家业一样,

不用再去写构造和析构函数,默认生成的构造析构函数

会去调用内嵌类型的构造或析构,

在基础上实现接口函数就可以了。

deque基本介绍

deque也是STL库中的一个容器:

deque又被称为双端队列是一种双开口的"连续"空间的数据结构,双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素,与list比较,空间利用率比较高(啥都能干,啥都干的不是特别好,既支持头插头删也有尾插尾删,也支持[]

接口函数

deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个动态的二维数组,其底层结构如下图所示:

deque通过一个叫中控数组的来控制(map箭头指向的数组)

deque扩容是直接另外开辟一份空间
再让中控数组指向新开辟的空间
再将原先空间的内容拷贝至新空间

优先级队列

优先级队列:priority_queue

它也是一个容量适配器

优先级队列默认是大堆

它的底层适配器默认是vector

优先级队列默认有三个类模板,第三个
模板就是决定此优先级队列是大堆还是小堆
它是仿函数,默认的less是大堆
我们显示传参greater时是小堆!

优先级队列的接口函数:

如果你想使用小堆,就要将前两个
模板参数实例化后才能实例化第三个
当less变成greater时,就是小堆

如果要改变大小堆,需要将参数补全,vector<int>也需要写上

优先级队列的模拟实现

由于优先级队列实际上就是个堆
所以在插入,删除之后.都需要做一件事
那就是向上调整或向下调整!所以插入和
删除的关键其实就在于向上/下调整!

向上调整:

		void up(size_t child)
		{
			size_t parent = (child - 1) / 2;
			while (child > 0)
			{
				if (_con[child] > _con[parent])
				{
					std::swap(_con[child], _con[parent]);
					child = parent;
					parent = (parent - 1) / 2;
				}
				else
					break;
			}
		}

向下调整:

		void down(size_t parent)
		{
			size_t child = parent * 2 + 1;
			while (child < _con.size())
			{
				if (child + 1 < _con.size() && _con[child + 1] > _con[child])
				{
					++child;

				}
				if (_con[child] > _con[parent])
				{
					std::swap(_con[child], _con[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
					break;
			}
		}

全部代码:

namespace wr2 
{
	template<class T,class Container=std::vector<T>>
	class priority 
	{
	public:		
		size_t size()
		{
			return _con.size();
		}
		void up(size_t child)
		{
			size_t parent = (child - 1) / 2;
			while (child > 0)
			{
				if (_con[child] > _con[parent])
				{
					std::swap(_con[child], _con[parent]);
					child = parent;
					parent = (parent - 1) / 2;
				}
				else
					break;
			}
		}
		void down(size_t parent)
		{
			size_t child = parent * 2 + 1;
			while (child < _con.size())
			{
				if (child + 1 < _con.size() && _con[child + 1] > _con[child])
				{
					++child;

				}
				if (_con[child] > _con[parent])
				{
					std::swap(_con[child], _con[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
					break;
			}
		}

		void push(const T& x)
		{
			_con.push_back(x);
			up(_con.size() - 1);
		}
		void pop()
		{
			std::swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			down(0);
		}
		const T& top()
		{
			return _con[0];
		}
		bool empty()
		{
			return _con.empty();
		}

	private:
		Container _con;
	};

}

总结

通过前面的容器学习,栈和队列学习起来也更加得心应手,

不仅仅是模拟实现,可以复用以前的容器,

连使用方法和函数接口都和之前一样,

而deque更像一个”六边形战士“,

不过各项能力都不出众。

相关推荐

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-11 21:54:09       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-11 21:54:09       100 阅读
  3. 在Django里面运行非项目文件

    2024-06-11 21:54:09       82 阅读
  4. Python语言-面向对象

    2024-06-11 21:54:09       91 阅读

热门阅读

  1. 【React】useCallback和useMemo使用指南

    2024-06-11 21:54:09       35 阅读
  2. 常见的vue指令

    2024-06-11 21:54:09       25 阅读
  3. Ubuntu系统的基本使用教程

    2024-06-11 21:54:09       25 阅读
  4. C++日期类的实现

    2024-06-11 21:54:09       41 阅读
  5. python数据处理分析库(二)

    2024-06-11 21:54:09       28 阅读
  6. 目前常用的后端技术

    2024-06-11 21:54:09       31 阅读
  7. 每天一个数据分析题(三百五十四)-分析报表

    2024-06-11 21:54:09       35 阅读
  8. leetcode67:二进制求和

    2024-06-11 21:54:09       30 阅读
  9. GPS原理与接收机设计

    2024-06-11 21:54:09       25 阅读
  10. vue 之 h() 函数

    2024-06-11 21:54:09       33 阅读