1.传统模拟方式
namespace jxy
{
template<class T>
class stack
{
//...
private:
T* _a;
size_t _size;
size_t _capacity;
};
}
2.适配器方式模拟
namespace jxy
{
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;
};
}
这种方式叫做适配器方式
所以栈是容器适配器,它可以去适配
传顺序表数组,可以使用顺序表适配出需要的栈
传链表,也可以适配出需要的栈
它可以通过模板参数来控制底层容器是什么
不管这个底层容器是什么,都可以适配出后进先出的栈
template<class T,class Container>
class stack
{
//...
private:
Container _con;
};
//使用时
jxy::stack<int, vector<int>> st;
jxy::stack<int, list<int>> st;
3.deque
deque:双端队列,一种容器
注意:它不是队列,不要求先进先出,两端都可以操作,适合在两端进行插入、删除等
那么有没有中间一点的方案、结构,可以把它们的优点融合一下?
答案是有的,deque就是融合了它们的优点。
3.1对比deque和vector的[]效率
void test_op()
{
srand(time(0));
const int N = 100000;
deque<int> dq;
vector<int> v;
for (int i = 0; i < N; ++i)
{
auto e = rand();
dq.push_back(e);
v.push_back(e);
}
//1.deque的sort
int begin1 = clock();
sort(dq.begin(), dq.end());
int end1 = clock();
//2.vector的sort
int begin2 = clock();
sort(v.begin(), v.end());
int end2 = clock();
printf("deque[] sort:%d\n", end1 - begin1);
printf("vector[] sort:%d\n", end2 - begin2);
//排序底层会大量访问数据,所以这里其实就是在拿它们的[]进行对比
//因为算法是一样的,唯一区别就是[]不一样
}
显然vector的 [] 效率更高
3.2第二种对比方式
void test_op1()
{
srand(time(0));
const int N = 100000;
deque<int> dq1;
deque<int> dq2;
for (int i = 0; i < N; ++i)
{
auto e = rand();
dq1.push_back(e);
dq2.push_back(e);
}
//1.de1的sort
int begin1 = clock();
sort(dq1.begin(), dq1.end());
int end1 = clock();
//2.dq2的sort
int begin2 = clock();
//拷贝到vector
vector<int> v(dq2.begin(), dq2.end());
sort(v.begin(), v.end());
//赋值回去
dq2.assign(v.begin(), v.end());
int end2 = clock();
printf("deque sort:%d\n", end1 - begin1);
printf("deque copy vector sort,copy back deque sort:%d\n", end2 - begin2);
}
哪怕是把deque的数据拷贝给vector去排序,都比自身的效率高,只能说deque是小丑中的小丑。
同时也说明,拷贝的消耗不是很大
3.3总结
实际上,deque并不常用
下标的随机访问,还是vector更强
头、尾的插入删除方面,deque还不错,略优于vector和list并且相对于list它的CPU高速缓存更好
它 头、尾的插入、删除效率 > [] > 中间位置的插入、删除
4.模拟实现queue
queue的模拟实现与stack同理
namespace jxy
{
//注意:队列是队尾插入、队头删除,所以vector不能适配queue
//如果使用了就会报错
template<class T, class Container = 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;
};
};
void test_queue()
{
jxy::queue<int> q;
q.push(1);
q.push(2);
q.push(3);
q.push(4);
q.push(5);
while (!q.empty())
{
cout << q.front() << " ";
q.pop();
}
cout << endl;
}