
目录
stack的模拟实现
Queue模拟实现
deque双端队列(了解)
原理介绍
优先级队列priority_queue
优先级队列的模拟实现
仿函数
stack的模拟实现
栈的实现可以放在链表中,也可以放在数组中等等,对于C++的栈,我们没必要像C语言一样,用什么容器就把什么容器实现出来,这样成本太高,我们可以用一个容器模板,在私有成员定义一个容器类的成员变量,相当于实例化了这个容器,再去实现一系列的函数。
template
class stack
{
public:
bool empty() const
{
return _con.empty();
}
size_t size() const
{
return _con.size();
}
const T& top() const
{
return _con.back();
}
void push(const T& x)
{
_con.push_back(x);
}
void pop()
{
_con.pop_back();
}
private:
Container _con;
};
调用一下
void test_stack1()
{
stack> s;
//stack> s;//这里报错因为要包头文件。
s.push(1);
s.push(2);
s.push(3);
s.push(4);
while (!s.empty())
{
cout << s.top() << " ";
s.pop();
}
cout << endl;
}
但是在std中调用栈的时候,并没有给到两个参数模板。
这是因为参数模板也有缺省值,std给到Container中的缺省值是deque 函数参数控制的是对象,模板参数控制的是类型。 这里传的deque是类型。 上面的例子存放string结果也是对的,但是这样是不对的,因为string里面放的是char存1个字节,而int是4字节,将int放入string中会发生截断,这里只是恰巧对了。 如果存其他对象如string对象有肯能不对。 队列的实现最好不要用vector数组,队列的性质是先进先出,如果在数组中实现,要尾插入数据,而出数据要头删,这样时间复杂度很大,最好用链表。 以下就是队列要实现的各个函数功能 以上就是适配器模式,适配了一系列容器 deque:是一种双开口“连续”空间的数据结构,它集成了vector和queue的优点。 双开口的含义是:可以在头尾两端进行插入和删除 *** 作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素。 与list相比空间利用率较高。 vector和list的优缺点 vector的优点:下标随机访问,尾插效率高 vector缺点:扩容(效率、浪费空间),不适合头插头删 list优点:按需申请释放空间。 任意位置O(1)插入删除 list缺点:不支持下标随机访问 对于这些接口,发现它既有vector的属性,又有list的属性。 所以在栈和队列中用刚刚好。 deque做默认是配容器的优势: 相较于vector而言,扩容代价不大,不需要拷贝数据,浪费空间也不多。 vector如果扩容,每次都会扩n倍,如果一个数组本来1024个大小,要存放1030个数据,还要扩容到2048,有1000多个空间浪费,,但是deque如果空间不够就扩容,他每次开的空间都很小,也不用拷贝数据,代价非常小 。 他们只需要用指针放在指针数组,如果指针数组不够再扩n倍,也不会频繁扩容。 当vector删除数据后不会释放空间,而deque删除数据后如果一个buffer删没了,那么直接将空buffer释放掉,空间浪费小。 相较于list而言,cpu高速cache命中,其次不会频繁申请小块空间。 申请和释放空间次数少代价低。 所以deque只是在栈和队列中发挥的作用比vecto和list要大,deque适合头尾的插入删除,但是如果平时在用其他数据结构中,因为deque随机插入非常麻烦,如果要对deque中的数据排序,还不如将它拷贝到数组中排序再放回来,这是《SLT源码剖析》这本书就提到的。 所以如果随机访问还是用vector,随机插入删除还是用list,这两个一直是数据结构中的王道。 文档介绍 翻译 元素从特定容器的“尾部”d出,其称为优先队列的顶部 容器应该可以通过随机访问迭代器访问,并支持以下 *** 作: 对于优先级队列,它的底层是以堆为基础的,是包含在队列这个头文件中。 那么优先级队列是从大到小排序的,还是从小到大排序的呢?通过测试我们发现,默认情况下,优先级队列是从大到小排列的,因为他给的默认缺省仿函数是Less(从大到小排列),如果要从小到大排列需要加一个参数,反函数greater使队列排序与默认相反。 仿函数会在下面提到。 而在优先级队列中要默认给到vector这个容器,它并不像栈和队列一样用deque容器,deque容器对于栈和队列的好处就是可以头插头删,而且增容代价不大,cache命中率高,所以会用到deque,而它的缺点就是不能在中间插入删除,访问下标也非常麻烦,这对于优先级队列是非常不友好的,优先级队列因为要排序,所以需要访问下表,这时vector的作用就比较大。 优先级队列的默认容器也采用vector。 因为优先级队列还是队列,所以它的push是尾插,pop是头删,这也符合了先进先出的性质。 以上是基本定义,下面来看仿函数,我们要能控制大堆小堆,比较的方式。 从用法上来看,只要大adjust_up和adjust_down中的child下标的数小于parent下标的数即可。 但是我们不能让用的人改内部的函数,所以我们可以用仿函数。 来看下面一段代码,我们在一个类中重载(),()也是一种 *** 作符。 这里只针对了int类型,如果想要管理更宽泛的类型,可以套一个类模板 ps:模板传参没有实例化,指针不明确指向的对象,引用传参,最后加一个const,为了防止传过来一个const对象。 了解了仿函数,那么如何实现变换类模板就能改变大小堆的实现呢? 写一个仿函数类,在类模板中加一个以Less为缺省值的模板参数,实例化这个参数模板,将需要改变的地方用仿函数实现 但是有的人提出疑问,为什么Less不用大于,这样不是更方便优先级队列吗?既然Less是从大到小排列,x>y不是更方便吗?其实不然,在出了优先级队列的其他函数中,Less都扮演着x 所以如果改成大于,这样更麻烦。 当我们用自定义类型来写一个优先级 当我们传一个Date的指针Date*类型,直接打印Date只会打出地址,所以我们要打印解引用的值,但是打印解引用的值就不会从大到小(从小到大)排序了,因为传的是Date* 类型,Date指针指向这块空间的地址,地址是16进制的数,他会给地址排序,给地址排好序后,解引用里面的值,可能顺序不一样。 所以我们可以再次用到仿函数,如果对应的数据类型不支持比较,或者比较的方式不是你想要的,那么可以自己实现仿函数,按照自己想要的方式去比较,控制比较逻辑 在官方写法中,最后的仿函数默认就给了less,我们也可以自定义写一些其他的来实现。 欢迎分享,转载请注明来源:内存溢出#pragma once
#include
namespace wjy
{
template
优先级队列的模拟实现
#include namespace wjy
{
templatestruct Less
{
//重载一个operator()
bool operator()(int x, int y)
{
return x < y;
}
};
struct Greater
{
bool operator()(int x, int y)
{
return x>y;
}
};
int main()
{
Less less;
cout << less(1, 2) << endl;
Greater gt;
cout << gt(1, 2) << endl;
cout << gt.operator()(1, 2) << endl;//等价于上面
return 0;
}template template
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
:_year(year)
, _month(month)
, _day(day)
{}
bool operator<(const Date& d)const
{
return (_year < d._year) ||
(_year == d._year && _month < d._month) ||
(_year == d._year && _month == d._month && _day < d._day);
}
bool operator>(const Date& d)const
{
return (_year > d._year) ||
(_year == d._year && _month > d._month) ||
(_year == d._year && _month == d._month && _day > d._day);
}
friend ostream& operator<<(ostream& _cout, const Date& d);
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& _cout, const Date& d)
{
_cout << d._year << "-" << d._month << "-" << d._day << endl;
return _cout;
}
void test_priority_queue2()
{
priority_queue
微信扫一扫
支付宝扫一扫
评论列表(0条)