C++栈和队列(容器适配器)

目录

1.什么是适配器?

2.栈(stack)

3.队列(queue)

4.双端队列(deque) 

5.优先级队列(priority_queue)

1.什么是仿函数?

2.仿函数有什么用?

3.优先级队列(priority_queue)


1.什么是适配器?

我们之前实现栈和队列,都是我们自己去实现相应的功能,那么今天我们可以使用容器适配器来实现我们的栈和队列,那么什么是适配器呢?

我们日常生活中所见到的电源充电器,就是一种适配器,当我们使用的时候,会跟我们的插座相匹配,从而供我们使用。

2.栈(stack)

那么在栈和队列的实现中,我们该怎样使用相应的容器适配器呢?我们都知道,栈是一种后进先出的结构,它在一定程度上和我们的vector很相似,那么有什么办法可以用vector来模拟出一个栈呢?答案是可以的:

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[_con.size() - 1];
	}
	const T& top()const
	{
		return _con[_con.size() - 1];
	}

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

	size_t size()const
	{
		return _con.size();
	}
private:
	Container _con;
};

这里在模板参数中,我们多了一个Container的模板参数,它的默认模板为vector模板,因为我们学习过vector和stack的使用, 因此用vector模拟一个stack还是非常简单的,本质上都是vector的调用,只不过我们在使用栈的时候,底层是vector而已。

3.队列(queue)

对于队列来说,我们要实现的是先进先出的结构,此时我们发现,vector是模拟实现不了queue的,所以我们想到了list:

template<class T, class Container = list<T>>
class queue
{
public:
	void push(const T& x)
	{
		_con.push_back(x);
	}
	void pop()
	{
		_con.pop_front();
	}
	T& back()
	{
		return _con.back();
	}

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

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

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

private:
	Container _con;
};

这里的使用还是调用的list的功能,对于queue来说先进先出即可,我们看起来使用的是queue,实际上是用list来模拟的。

4.双端队列(deque) 

双端队列从名字就能看出来,它好像前后都可以快速插入和删除。实际上确实如此,双端队列类似vector和list的结合体,取精华去糟粕,它的底层是用指针数组来存储一小段连续的空间,但每个小段又是不连续的,因此它整体的空间其实是不连续的。相比于vector 和 list,deque的两端插入和删除效率都是不错的,但是其在中间插入的效率却很低。

它的使用与vector 和 list类似,这里我们看一下就知道该如何使用了,这里提到双端队列想要说的是,我们在模拟栈和队列的时候,可以把Container 默认都改为deque,因为栈和队列不涉及在中间段插入删除数据,只有在一端插入和删除,因此使用deque效率更优。

5.优先级队列(priority_queue)

优先级队列在插入和删除过程中需要满足一个优先级,优先级大的数据将被优先服务,这也就意味着当我们在插入和删除数据时,并不时按照队列那样先进先出的概念。

priority_queue的基础模拟实现:

template<class T, class Container = vector<int>, class Compare = less<T>>
class priority_queue
{
public:

private:
	Container _con;
	Compare com;
};

这里我们看到,我们的模板参数多了一个Compare = less<T> ,这是什么东西呢?那么我们就先来了解一下仿函数的概念:

1.什么是仿函数?

template<class T>
class less
{
public:
    bool operator()(const T& v1, const T& v2)
    {
        return v1 < v2;
    }
};

template<class T>
class greater
{
public:
    bool operator()(const T& v1, const T& v2)
    {
        return v1 > v2;
    }
};

仿函数本质上是一个类,它的使用就像是一个函数,它的里面必须要有operator() (括号)的重载,以上两个less 和 greater就是两个仿函数,里面有着判断数据大小的功能,也就是重载了() operator() 。

2.仿函数有什么用?

我们在使用库里面的sort函数的时候默认是升序,此时就可以使用仿函数来改变为降序:

这里就是仿函数的使用,它可以改变我们的比较方式,从而改变我们的排序是升序还是降序,来达到我们的使用要求。 

3.优先级队列(priority_queue)

那么再来回头看看我们的优先级队列,我们已经说过,优先级队列在插入和删除的时候要遵循优先级大的先被服务,因此就少不了仿函数来随时的改变数据的优先级。

template<class T, class Container = vector<int>, class Compare = less<T>>
class priority_queue
{
public:
	template <class InputIterator>
	priority_queue(InputIterator first, InputIterator last)
	{
		while (first != last)
		{
			_con.push_back(*first);
			first++;
			AdjustUp(_con.size() - 1);
		}
	}
	void AdjustUp(size_t child)
	{
		size_t parent = (child - 1) / 2;
		while (child > 0)
		{
			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;
		while (child < _con.size())
		{
			if (child + 1 < _con.size() && com(_con[child], _con[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);
	}
	T& top()
	{
		return _con[0];
	}

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

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

	size_t size()
	{
		return _con.size();
	}
private:
	Container _con;
	Compare com;
};

我们这里的优先级队列实质上是用vector容器来模拟了堆的实现,在push和pop(插入和删除)的时候使用了向上调整和向下调整,并且两种调整函数中的比较逻辑使用了仿函数,方便我们在使用的过程中修改优先级比较逻辑。

以上就是C++中栈、队列的基础知识,如有错误欢迎批评指正!

  • 16
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值