`
aspnetwinform
  • 浏览: 84333 次
  • 性别: Icon_minigender_2
  • 来自: 武汉
社区版块
存档分类
最新评论

从零开始学C++之STL(十一):容器适配器(stack、 queue 、priority_queue)源码浅析与使用示例

 
阅读更多

一、容器适配器
stack
queue
priority_queue


stack、queue、priority_queue 都不支持任一种迭代器,它们都是容器适配器类型,stack是vector/deque/list对象创建了一个先进后出容器;queue是用deque或list对象创建了一个先进先出容器;priority_queue是用vector/deque创建了一个排序队列,内部用二叉堆实现。


(一)、stack

首先来看示例代码:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br></nobr>
#include<iostream>
#include<vector>
#include<list>
#include<stack>

usingnamespacestd;

intmain(void)
{
stack<int,list<int>>s;
for(inti=0;i<5;i++)
{
s.push(i);
}

//for(size_ti=0;i<s.size();i++)
//{
//cout<<s.top()<<'';Error:size()一直在变化
//s.pop();
//}

while(!s.empty())
{
cout<<s.top()<<'';
s.pop();
}
cout<<endl;
return0;
}

再看stack 的源码:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br> 37<br> 38<br> 39<br> 40<br> 41<br> 42<br> 43<br> 44<br> 45<br> 46<br> 47<br> 48<br> 49<br> 50<br> 51<br> 52<br> 53<br> 54<br> 55<br> 56<br> 57<br> 58<br> 59<br> 60<br> 61<br> 62<br> 63<br> 64<br> 65<br> 66<br> 67<br> 68<br> 69<br> 70<br></nobr>
//TEMPLATECLASSstack
template<class_Ty,
class_Container=deque<_Ty>>
classstack
{
//LIFOqueueimplementedwithacontainer
public:
typedef_Containercontainer_type;
typedeftypename_Container::value_typevalue_type;
typedeftypename_Container::size_typesize_type;
typedeftypename_Container::referencereference;
typedeftypename_Container::const_referenceconst_reference;

stack()
:c()
{
//constructwithemptycontainer
}

explicitstack(const_Container&_Cont)
:c(_Cont)
{
//constructbycopyingspecifiedcontainer
}

boolempty()const
{
//testifstackisempty
return(c.empty());
}

size_typesize()const
{
//testlengthofstack
return(c.size());
}

referencetop()
{
//returnlastelementofmutablestack
return(c.back());
}

const_referencetop()const
{
//returnlastelementofnonmutablestack
return(c.back());
}

voidpush(constvalue_type&_Val)
{
//insertelementatend
c.push_back(_Val);
}

voidpop()
{
//eraselastelement
c.pop_back();
}

const_Container&_Get_container()const
{
//getreferencetocontainer
return(c);
}

protected:
_Containerc;//theunderlyingcontainer
};

即有一个_Container 成员,默认是deque<_Ty> ,当然也可以传递vector, list 进去,只要支持push_back,pop_back 等接口。内部的函数实现

都借助了容器的函数,跟以前实现过的Stack 很像。


(二)、queue

先来看示例代码:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br></nobr>
#include<iostream>
#include<vector>
#include<list>
#include<stack>
#include<queue>

usingnamespacestd;

intmain(void)
{
//inta[]={1,2,3,4,5};
//vector<int>v(a,a+5);

queue<int,list<int>>q;
for(inti=0;i<5;i++)
{
q.push(i);
}

while(!q.empty())
{
cout<<q.front()<<'';
q.pop();
}

cout<<endl;

return0;
}

再来看queue 源码:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br> 37<br> 38<br> 39<br> 40<br> 41<br> 42<br> 43<br> 44<br> 45<br> 46<br> 47<br> 48<br> 49<br> 50<br> 51<br> 52<br> 53<br> 54<br> 55<br> 56<br> 57<br> 58<br> 59<br> 60<br> 61<br> 62<br> 63<br> 64<br> 65<br> 66<br> 67<br> 68<br> 69<br> 70<br> 71<br> 72<br> 73<br> 74<br> 75<br> 76<br> 77<br> 78<br> 79<br> 80<br> 81<br> 82<br></nobr>
//TEMPLATECLASSqueue
template<class_Ty,
class_Container=deque<_Ty>>
classqueue
{
//FIFOqueueimplementedwithacontainer
public:
typedef_Containercontainer_type;
typedeftypename_Container::value_typevalue_type;
typedeftypename_Container::size_typesize_type;
typedeftypename_Container::referencereference;
typedeftypename_Container::const_referenceconst_reference;

queue()
:c()
{
//constructwithemptycontainer
}

explicitqueue(const_Container&_Cont)
:c(_Cont)
{
//constructbycopyingspecifiedcontainer
}

boolempty()const
{
//testifqueueisempty
return(c.empty());
}

size_typesize()const
{
//returnlengthofqueue
return(c.size());
}

referencefront()
{
//returnfirstelementofmutablequeue
return(c.front());
}

const_referencefront()const
{
//returnfirstelementofnonmutablequeue
return(c.front());
}

referenceback()
{
//returnlastelementofmutablequeue
return(c.back());
}

const_referenceback()const
{
//returnlastelementofnonmutablequeue
return(c.back());
}

voidpush(constvalue_type&_Val)
{
//insertelementatbeginning
c.push_back(_Val);
}

voidpop()
{
//eraseelementatend
c.pop_front();
}

const_Container&_Get_container()const
{
//getreferencetocontainer
return(c);
}

protected:
_Containerc;//theunderlyingcontainer
};

实现跟stack 是很类似的,只是queue不能用vector 实现,因为没有pop_front 接口。


(三)、priority_queue

先来看示例代码:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br></nobr>
#include<iostream>
#include<functional>
#include<vector>
#include<list>
#include<stack>
#include<queue>

usingnamespacestd;

intmain(void)
{
inta[]={5,1,2,4,3};
priority_queue<int,vector<int>,greater<int>>q(a,a+5);

while(!q.empty())
{
cout<<q.top()<<'';
q.pop();
}

cout<<endl;

return0;
}

再来看priority_queue 的源码:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br> 37<br> 38<br> 39<br> 40<br> 41<br> 42<br> 43<br> 44<br> 45<br> 46<br> 47<br> 48<br> 49<br> 50<br> 51<br> 52<br> 53<br> 54<br> 55<br> 56<br> 57<br> 58<br> 59<br> 60<br> 61<br> 62<br> 63<br> 64<br> 65<br> 66<br> 67<br> 68<br> 69<br> 70<br> 71<br> 72<br> 73<br> 74<br> 75<br> 76<br> 77<br> 78<br> 79<br> 80<br> 81<br> 82<br> 83<br> 84<br> 85<br> 86<br> 87<br> 88<br> 89<br> 90<br> 91<br> 92<br> 93<br> 94<br> 95<br> 96<br> 97<br> 98<br> 99<br> 100<br> 101<br></nobr>
//TEMPLATECLASSpriority_queue
template<class_Ty,
class_Container=vector<_Ty>,
class_Pr=less<typename_Container::value_type>>
classpriority_queue
{
//priorityqueueimplementedwitha_Container
public:
typedef_Containercontainer_type;
typedeftypename_Container::value_typevalue_type;
typedeftypename_Container::size_typesize_type;
typedeftypename_Container::referencereference;
typedeftypename_Container::const_referenceconst_reference;

priority_queue()
:c(),comp()
{
//constructwithemptycontainer,defaultcomparator
}

explicitpriority_queue(const_Pr&_Pred)
:c(),comp(_Pred)
{
//constructwithemptycontainer,specifiedcomparator
}

priority_queue(const_Pr&_Pred,const_Container&_Cont)
:c(_Cont),comp(_Pred)
{
//constructbycopyingspecifiedcontainer,comparator
make_heap(c.begin(),c.end(),comp);
}

template<class_Iter>
priority_queue(_Iter_First,_Iter_Last)
:c(_First,_Last),comp()
{
//constructbycopying[_First,_Last),defaultcomparator
make_heap(c.begin(),c.end(),comp);
}

template<class_Iter>
priority_queue(_Iter_First,_Iter_Last,const_Pr&_Pred)
:c(_First,_Last),comp(_Pred)
{
//constructbycopying[_First,_Last),specifiedcomparator
make_heap(c.begin(),c.end(),comp);
}

template<class_Iter>
priority_queue(_Iter_First,_Iter_Last,const_Pr&_Pred,
const_Container&_Cont)
:c(_Cont),comp(_Pred)
{
//constructbycopying[_First,_Last),container,andcomparator
c.insert(c.end(),_First,_Last);
make_heap(c.begin(),c.end(),comp);
}

boolempty()const
{
//testifqueueisempty
return(c.empty());
}

size_typesize()const
{
//returnlengthofqueue
return(c.size());
}

const_referencetop()const
{
//returnhighest-priorityelement
return(c.front());
}

referencetop()
{
//returnmutablehighest-priorityelement(retained)
return(c.front());
}

voidpush(constvalue_type&_Pred)
{
//insertvalueinpriorityorder
c.push_back(_Pred);
push_heap(c.begin(),c.end(),comp);
}

voidpop()
{
//erasehighest-priorityelement
pop_heap(c.begin(),c.end(),comp);
c.pop_back();
}

protected:
_Containerc;//theunderlyingcontainer
_Prcomp;//thecomparatorfunctor
};


priority_queue 的实现稍微复杂一点,可以传递3个参数,而且有两个成员,comp 即自定义比较逻辑,默认是less<value_type>,在构造函数中

调用make_heap函数构造二叉堆,comp 主要是用于构造二叉堆时的判别,如果是less 则构造大堆,如果传递greater 则构造小堆.

注意,priority_queue 不能用list 实现,因为list 只支持双向迭代器,而不支持随机迭代器。


下面举个例子说明make_heap 函数的用法:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br></nobr>
#include<iostream>
#include<functional>
#include<vector>
#include<list>
#include<stack>
#include<queue>

usingnamespacestd;

intmain(void)
{
inta[]={5,1,2,4,3};
make_heap(a,a+5,less<int>());

copy(a,a+5,ostream_iterator<int>(cout,""));
cout<<endl;

sort(a,a+5);
//sort_heap(a,a+5,less<int>());
copy(a,a+5,ostream_iterator<int>(cout,""));
cout<<endl;

return0;
}

输出:

5 4 2 1 3

1 2 3 4 5

make_heap() 将容器的元素构造成二叉堆,传递的是less,即构造的是大堆,把大堆层序遍历的结果存入数组,再调用sort() 进行排序,内部调用

的实际算法不一定,可以是堆排序、插入排序、选择排序等等,跟踪进去发现调用的是插入排序;当然也可以直接指定使用堆排序 sort_heap(调用

者必须已经是堆了,也就是前面已经先调用了make_heap,而且大小堆类型得匹配),与make_heap 一样,第三个参数传递的都是函数对象的用

法。sort 和 sort_heap 默认都是从小到大排序,除非重载的版本传递了第三个参数,如下,第三个参数可以是函数指针,也可以是函数对象:

C++ Code
<nobr>1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br></nobr>
//orderheapbyrepeatedlypopping,usingoperator<
template<class_RanIt>inline
voidsort_heap(_RanIt_First,_RanIt_Last);

//orderheapbyrepeatedlypopping,using_Pred
template<class_RanIt,
class_Pr>inline
voidsort_heap(_RanIt_First,_RanIt_Last,_Pr_Pred);

传递greater 构造的是小堆,如下图所示:



参考:

C++ primer 第四版
Effective C++ 3rd
C++编程规范


分享到:
评论

相关推荐

    C++ STL开发技术导引(第5章)

    第三篇 C++ STL容器技术 第6章 vector向量容器 92 6.1 vector技术原理 92 6.2 vector应用基础 94 6.3 本章小结 101 第7章 deque双端队列容器 102 7.1 deque技术原理 102 7.2 deque应用基础 108 7.3 ...

    STL 源码剖析(侯捷先生译著)

    内容简介回到顶部↑这本书不适合C++ 初学者,不适合 Genericity(泛型技术)初学者,或 STL 初学者。这本书也不适合带领你学习面向对象(Object Oriented)技术 — 是的,STL 与面向对象没有太多关连。本书前言清楚...

    STL源码剖析.pdg

    3.7 sgi stl的私房菜:__type_traits 103 第4章 序列式容器(sequence containers) 113 4.1 容器概观与分类 113 4.1.1 序列式容器(sequence containers) 114 4.2 vector 115 4.2.1 vector 概述 115 4.2.2 ...

    cpp-learn.tar.gz

    记录学习C++。 文件: class_template.cpp deque_learn.cpp exception.cpp fun_template.cpp fun_template2.cpp inhire_learn.cpp list_learn.cpp map_learn.cpp multimap_learn.cpp multiset_learn.cpp my_vector....

    C++容器类的简单介绍.doc

    1、STL标准容器类简介 标准容器类 说明 顺序性容器 vector 相当与数组,从后面快速的插入与删除,直接访问任何元素 deque 双队列,从前面或后面快速的插入与删除,直接访问任何元素 list 双链表,从任何地方快速...

    MyStl:自己实现STL

    顺序容器适配器:stack,queue 关联容器:set,map,multiset,multimap 无序关联容器:unordered_set,unordered_map,unordered_multiset,unordered_multimap 容器均支持列表初始化,重载了相关迭代器的bool类型...

    C++ STL 开发技术导引(第6章)

    第三篇 C++ STL容器技术 第6章 vector向量容器 92 6.1 vector技术原理 92 6.2 vector应用基础 94 6.3 本章小结 101 第7章 deque双端队列容器 102 7.1 deque技术原理 102 7.2 deque应用基础 108 7.3 ...

    C++ STL开发技术导引(第3章)

    第三篇 C++ STL容器技术 第6章 vector向量容器 92 6.1 vector技术原理 92 6.2 vector应用基础 94 6.3 本章小结 101 第7章 deque双端队列容器 102 7.1 deque技术原理 102 7.2 deque应用基础 108 7.3 ...

    stl-views.gdb

    # The following STL containers are currently supported: # # std::vector&lt;T&gt; -- via pvector command # std::list&lt;T&gt; -- via plist or plist_member command # std::map,T&gt; -- via pmap or pmap_member command #...

    传智播客扫地僧视频讲义源码

    本教程共分为5个部分,第一部分是C语言提高部分,第二部分为C++基础部分,第三部分为C++进阶部分,第四部分为C、C++及数据结构基础部分,第五部分为C_C++与设计模式基础,内容非常详细. 第一部分 C语言提高部分目录...

    C++_STL范例大全(一)

    丰富的范例程序 Sample of STL STL 范例(一) 容器部分 Vector-------------------------------------------1 Deque---------------------------------...Priority_queue------------------------------------------139

    stl详解 包括各种实例代码

    STL介绍 3 1、STL简介 3 2、算法 3 3、容器 3 4、迭代器 4 5、使用注意 4 一、stack 堆栈 5 成员函数: 5 实例程序: 5 二、queue 队列 6 成员函数: 6 实例程序: 6 三、Priority Queues 优先队列 7 成员函数: 7 ...

    C++标准程序库STL的架构

    10.3 Priority Queue 128 10.3.1 核心接口 128 10.3.2 运用实例 128 10.4 Bitset 129 10.4.1 Bitset运用实例 129 11 Strings 131 11.1 动机 131 11.1.1 示例:引出一个临时文件名 131 11.1.2 例二:引出一段文字并...

    C++进阶课程讲义_v1.0.4.pdf

    9.3.2C++文件的打开与关闭 67 9.3.3C++对ASCII文件的读写操作 69 9.3.4 C++对二进制文件的读写操作 74 9.4作业练习 75 10、STL实用技术专题 79 10.1 STL(标准模板库)理论基础 79 10.1.1基本概念 79 10.1.2容器 80 ...

    C++STL程序员开发指南【可搜索+可编辑】

    1-1 C++与C 语言的区别................................................... 4 1-1-1 文件扩展名的改变,.............................................. 4 1-1-2 简化输入/输出手段...............................

    STL容器 算法 函数表

    该篇分为十一部分,分别是:vector类的主要成员...stack类的主要成员、queue类的主要成员、priority_queue类的组要成员、set类的主要成员、multiset类的主要成员、map类的主要成员、multimap类的主要成员、STL算法函数

    C++大学教程,一本适合初学者的入门教材(part1)

    1.13 C++与本书的一般说明 1.14 C++编程简介 1.15 简单程序:打印一行文本 1.16 简单程序:两个整数相加 1.17 内存的概念 1.18 算术运算 1.19 判断:相等与关系运算符 1.20 新型头文件与名字空间 1.21 有关...

    C++大学教程,一本适合初学者的入门教材(part2)

    1.13 C++与本书的一般说明 1.14 C++编程简介 1.15 简单程序:打印一行文本 1.16 简单程序:两个整数相加 1.17 内存的概念 1.18 算术运算 1.19 判断:相等与关系运算符 1.20 新型头文件与名字空间 1.21 有关...

    go-web:后端开发指南(笔记)

    priority_queue set unordered_set multiset unordered_multiset map multimap unordered_map unordered_multimap algorithm 其它 实现自定义排序规则 Python 攻略 基本数据类型 生成器 文件操作 并发 三方库 jieba ...

    LightSTL:STL的子集和超集

    LightSTLLightSTL是STL的一个子集和一个超集,是我在分析STL源码后结合自己的理解进行编写的主要目的在于提高数据结构与算法和C++编程LightSTL开发进度底层配置和主要容器iterator_traits(100%)type_traits(100%)...

Global site tag (gtag.js) - Google Analytics