您的位置:首页 > 其它

STL容器适配器

2015-07-28 12:25 351 查看
首先,我们要明白适配器是干什么的?其实就是一个接口转换装置,是得我们能用特定的方法去操作一些我们本来无法操作的东西。举一个例子,比如你的一个设备支持串口线,而你的电脑支持的是usb口,这时候,我们没有必要重新买一个支持usb的设备,只需要一根串口转usb口的小玩意,让你的设备能够连接到usb插口上,而它就是适配器。

那么C++中的容器适配器是干什么的呢?可以做一个类比,我们已有的容器(比如vector、list、deque)就是设备,这个设备支持的操作很多,比如插入,删除,迭代器访问等等。而我们希望这个容器表现出来的是栈的样子:先进后出,入栈出栈等等,此时,我们没有必要重新动手写一个新的数据结构,而是把原来的容器重新封装一下,改变它的接口,就能把它当做栈使用了。

言归正传,理解了什么是适配器以后,其实问题就很简单的。C++中定义了3种容器适配器,它们让容器提供的接口变成了我们常用的的3种数据结构:栈(先进后出)队列(先进先出)和优先级队列(按照优先级(“<”号)排序,而不是按照到来的顺序排序)。

至于具体是怎么变的,我们可以先了解一个大概:默认情况下,栈和队列都是基于deque实现的,而优先级队列则是基于vector实现的。当然,我们也可以指定自己的实现方式。但是由于数据结构的关系,我们也不能胡乱指定。栈的特点是后进先出,所以它关联的基本容器可以是任意一种顺序容器,因为这些容器类型结构都可以提供栈的操作有求,它们都提供了push_back、pop_back和back操作。 队列queue的特点是先进先出,适配器要求其关联的基础容器必须提供pop_front操作,因此其不能建立在vector容器上;对于优先级队列,由于它要求支持随机访问的功能,所以可以建立在vector或者deque上,不能建立在list上。

让我们看看这三种关联容器提供的接口:

栈支持的操作有:

1.empty() 堆栈为空则返回真

2.pop() 移除栈顶元素

3.push() 在栈顶增加元素

4.size() 返回栈中元素数目

5.top() 返回栈顶元素

队列支持的操作有:

1.back() 返回一个引用,指向最后一个元素

2.empty() 如果队列空则返回真

3.front() 返回第一个元素

4.pop() 删除第一个元素

5.push() 在末尾加入一个元素

6.size() 返回队列中元素的个数

优先级队列支持的操作有:

1.empty() 如果优先队列为空,则返回真

2.pop() 删除第一个元素

3.push() 加入一个元素

4.size() 返回优先队列中拥有的元素的个数

5.top() 返回优先队列中有最高优先级的元素

举个例子:

[cpp] view
plaincopy

int main()

{

const stack<int>::size_type stk_size = 10;

//创建一个空栈

stack<int> intStack;

//改变栈的实现方式为vector

//stack<int,vector<int> > intStack;

int ix = 0;

while(intStack.size() != stk_size)

intStack.push(ix++);

int error_cnt = 0;

while(intStack.empty() == false)

{

//top操作返回栈顶元素,但并不删除

int value = intStack.top();

if(value != --ix)

{

cout<<"opps! expected "<<ix<<" received "<<value<<endl;

++error_cnt;

}

//删除栈顶元素

intStack.pop();

}

cout<<"our program ran with "<<error_cnt<<" errors! "<<endl;

return 0;

}

最后我们可以窥探一下stl中的源码:

[cpp] view
plaincopy

template<class _Ty,

class _Container = deque<_Ty> >

class stack

{ // LIFO queue implemented with a container

public:

typedef stack<_Ty, _Container> _Myt;

typedef _Container container_type;

typedef typename _Container::value_type value_type;

typedef typename _Container::size_type size_type;

typedef typename _Container::reference reference;

typedef typename _Container::const_reference const_reference;

stack()

: c()

{ // construct with empty container

}

stack(const _Myt& _Right)

: c(_Right.c)

{ // construct by copying _Right

}

explicit stack(const _Container& _Cont)

: c(_Cont)

{ // construct by copying specified container

}

_Myt& operator=(const _Myt& _Right)

{ // assign by copying _Right

c = _Right.c;

return (*this);

}

stack(_Myt&& _Right)

: c(_STD move(_Right.c))

{ // construct by moving _Right

}

explicit stack(_Container&& _Cont)

: c(_STD move(_Cont))

{ // construct by copying specified container

}

_Myt& operator=(_Myt&& _Right)

{ // assign by moving _Right

c = _STD move(_Right.c);

return (*this);

}

void push(value_type&& _Val)

{ // insert element at beginning

c.push_back(_STD move(_Val));

}

template<class _Valty>

void emplace(_Valty&& _Val)

{ // insert element at beginning

c.emplace_back(_STD forward<_Valty>(_Val));

}

void swap(_Myt&& _Right)

{ // exchange contents with movable _Right

c.swap(_STD move(_Right.c));

}

bool empty() const

{ // test if stack is empty

return (c.empty());

}

size_type size() const

{ // test length of stack

return (c.size());

}

reference top()

{ // return last element of mutable stack

return (c.back());

}

const_reference top() const

{ // return last element of nonmutable stack

return (c.back());

}

void push(const value_type& _Val)

{ // insert element at end

c.push_back(_Val);

}

void pop()

{ // erase last element

c.pop_back();

}

const _Container& _Get_container() const

{ // get reference to container

return (c);

}

void swap(_Myt& _Right)

{ // exchange contents with _Right

c.swap(_Right.c);

}

protected:

_Container c; // the underlying container

};

从中我们可以清楚的看到:栈在默认情况下,是基于deque实现的,它使用封装的顺序容器的操作来实现的自己的操作。相信里面的大部分内容我们都能看懂个大概。这里就不做过多解释了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: