deque和优先级队列

咱学完栈和队列之后,又了解到了vector和list,更深入的了解到了它们各自的优势,那么有没有可能结合它们的优点摒弃弱点呢,其实是有人这么试过的,不过咱还在学vector和list就证明他可能没成功,不过并不影响我们理解它。

deque

deque的结构大概是这样的,它外部是一个指针数组,一般称为中控数组,每个位置存一个指针,的地址,指针指向一块相同大小的空间。而他把指针又做了一些处理,first指向数据的起始位置,last指向数据的结束位置,cur指向当前数据位置,node则指向它在中控数组的位置,这样我们想访问某一个位置只需要 / 就可以知道它在中控数组哪个位置,再 % 就可以知道它的具体位置。

而插入数据则分为头插尾插,如果是尾插,那么我们的cur指向最后一个数据,如果它不等于last,那么代表没满,直接插入即可,如果满了就扩容。而头插,上图是满了的情况,实际情况是从最后开始往前插的,只要cur不等于first,那就可以一直插入。这也是为什么中控数组从中间开始逐渐往两边,头插如果满了则node-- ,就可以往前,尾插如果满了node++,就可以往后。如果满了中控数组无非扩容一下,而中控数组的扩容代价很低,拷贝点地址罢了,同时头插尾插效率也很高。它头插的底层其实是你要插入的位置 n + (cur - first) 这样很巧妙的计算出了它的位置。

不过上面的优点说完,它一定有致命缺陷才导致他无法替代vector和list。那就是如果中间插入,那么涉及到移动数据以及扩容的问题,如果扩容,有两种方法解决,一种是直接增加数组的长度,但是这样会导致中控数组里的各个数组大小不同意,就不能用 / 和 % 快速找到位置了。而另一种方法就是插入位置之后的数据都往后移,这两种方法无疑是效率很低的,而它的头插尾插效率又很高,所以我们在特殊情况下才使用deque。

优先级队列  priority_queue

当初我们学排序的时候应该感受到了一个堆排序的优秀,不是最强,但是速度很稳定,但是我们使用的时候又分向上调整和向下调整的建堆,这让我们很苦恼,有时候写完以后因为某些需求又要改,实在麻烦,所以产生了一个叫仿函数的东西。

仿函数

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

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

仿函数其实就是看着调用像一个函数,但是实际上它是个类,我们只是重载了函数调用里的()而已。

我们想建哪个堆,判断条件用哪个就好。

void Adjustup(int child)
		{
			compar com;
			int 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)
		{
			size_t chiled = parent * 2 + 1;
			compar com;
			while (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;
				}
			}
		}

这样我们给个我们自己设定的判断条件就可以灵活变通了(如果只是比大小,系统有自带的less和greater)。




template <class T,class Container = vector<T>, class compar = less<T>>
//这里传less或者greater就可以灵活改变我们要的排序方式,比我们直接改><要方便和有智慧的多

那么讲到这里,想必应该看到优先级队列的默认类型是vector了,它使用vector来存取建好堆的数据,再用堆的方式插入删除。

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);
		}

当然它作为用vector的,必不可少的还是得有。

const T& top()
		{
			return _con[0];
		}
		size_t size()const
		{
			return _con.size();
		}
		size_t empty() const
		{
			return _con.empty();
		}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值