﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-The Coder-文章分类-STL和标准函数库</title><link>http://www.cppblog.com/bch515/category/1876.html</link><description>I am a humble coder.</description><language>zh-cn</language><lastBuildDate>Wed, 21 May 2008 00:07:14 GMT</lastBuildDate><pubDate>Wed, 21 May 2008 00:07:14 GMT</pubDate><ttl>60</ttl><item><title>reverse算法扩充</title><link>http://www.cppblog.com/bch515/articles/8186.html</link><dc:creator>TH</dc:creator><author>TH</author><pubDate>Mon, 05 Jun 2006 11:38:00 GMT</pubDate><guid>http://www.cppblog.com/bch515/articles/8186.html</guid><wfw:comment>http://www.cppblog.com/bch515/comments/8186.html</wfw:comment><comments>http://www.cppblog.com/bch515/articles/8186.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/bch515/comments/commentRss/8186.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/bch515/services/trackbacks/8186.html</trackback:ping><description><![CDATA[
		<p>
				<font size="2">                                  </font>
				<font face="Courier New" size="2">reverse算法扩充<br />                         <font size="1">内容来源：TCPL和TCPL题解</font><br />在TCPL中的19.1习题，有对reverse算法的设计。<br />template&lt;typename Bi&gt; void reverse(Bi begin, Bi end)<br />从STL的定义来看，参数输入的迭代器是双向迭代器(Bidirectional iterator)。设计起来也是比较容易的。<br />namespace{<br /> template&lt;typename Bi&gt;<br /> inline void reverse(Bi begin, Bi end){<br />  while(begin != end)<br />   iter_swap(begin++, --end);<br /> }<br />}</font>
		</p>
		<p>
				<font face="Courier New" size="2">而在TCPL的题解里面提到了输入参数是向前迭代器的情况（Forward iterator）。这样reverse算法得重新设计。<br />算法概述：<br />    1.反转一个向前序列，可以首先将序列分成大致一样长的两半。然后用std::swap_ranges算法交换着两个半长序列。<br />    2.递归地反转这个两个半长序列。<br />[注意一下序列元素的个数（奇偶数）]<br />template&lt;typename For&gt;<br />void forward_reverse(For begin1, int len)<br />{<br /> if(len &gt; 1){<br />  int half_len = len / 2;<br />  For end1 = begin1;<br />  advance(end1, hal_len);<br />  For begin2 = end1;<br />  if(len % 2 != 0) //序列个数为奇数<br />   ++begin2;</font>
		</p>
		<p>
				<font face="Courier New" size="2">  std::swap_ranges(begin1, end1, begin2);<br />  forward_reverse(begin1, half_len);<br />  forward_reverse(begin2, half_len);<br /> }<br />}</font>
		</p>
		<p>
				<font face="Courier New" size="2">再为forward_reverse函数和reverse（bidirection）函数提供一个统一的借口。<br />template&lt;typename It&gt;<br />inline void flex_reverse(It begin, It end)<br />{<br /> using std::iterator_traits;<br /> tagged_reverse(begin, end, iterator_traits&lt;It&gt;::iterator_category());<br />}</font>
		</p>
		<p>
				<font face="Courier New" size="2">tagged_reverse()函数是通过函数重载和迭代器特征类（萃取技术）的结合来完成下面两个函数的自动选择。</font>
		</p>
		<p>
				<font face="Courier New" size="2">template&lt;typename For&gt;  //forward_reverse封装<br />inline void tagged_reverse(For begin, For end, std::forward_iterator_tag)<br />{<br /> forward_reverse(begin, distance(begin, end));<br />}</font>
		</p>
		<p>
				<font face="Courier New" size="2">template&lt;typename For&gt;  //reverse封装<br />inline void tagged_reverse(For begin, For end, std::bidirectional_iterator_tag)<br />{<br /> reverse(begin, end);<br />}</font>
		</p>
		<p>
				<br />
				<font face="Courier New" size="2">后来我发现好像把Forward_iterator的容器并不多见。<br />STL容器：1、双向迭代器（Bidirectional iterator）<br />            list、set、multiset、map、multimap<br />        2、随机存取迭代器（Random access iterator）<br />            vector、deque、string</font>
		</p>
		<p>
				<font face="Courier New" size="2">附：iterator_traits模板类中的一组声明描述：<br />template&lt;class Iter&gt; struct iterator_traits<br />{<br /> typedef typename Iter::iterator_category iterator_category;<br /> typedef typename Iter::value_type value_type;<br /> typedef typename Iter::difference_type difference_type;<br /> typedef typename Iter::pointer pointer;<br /> typedef typename Iter::reference reference;<br />};</font>
		</p>
		<p>
				<font face="Courier New" size="2">
				</font> </p>
<img src ="http://www.cppblog.com/bch515/aggbug/8186.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/bch515/" target="_blank">TH</a> 2006-06-05 19:38 <a href="http://www.cppblog.com/bch515/articles/8186.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>避免把不同序列的迭代器当成同一序列使用的一种机制</title><link>http://www.cppblog.com/bch515/articles/8098.html</link><dc:creator>TH</dc:creator><author>TH</author><pubDate>Fri, 02 Jun 2006 14:25:00 GMT</pubDate><guid>http://www.cppblog.com/bch515/articles/8098.html</guid><wfw:comment>http://www.cppblog.com/bch515/comments/8098.html</wfw:comment><comments>http://www.cppblog.com/bch515/articles/8098.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/bch515/comments/commentRss/8098.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/bch515/services/trackbacks/8098.html</trackback:ping><description><![CDATA[
		<p>在调用算法函数的时候，有时候会把不同序列的迭代器当成同一序列使用。<br />下面提供避免这样错误的一种机制。<br />本内容来自TCPL（特别版）</p>
		<p>有时候，我们会犯这样的错误，把两个不同序列的迭代器去构成一个序列了。比如：<br /></p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> f(list</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #0000ff">string</span>
				<span style="COLOR: #000000">&gt;&amp;</span>
				<span style="COLOR: #000000"> fruit, list</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #0000ff">string</span>
				<span style="COLOR: #000000">&gt;&amp;</span>
				<span style="COLOR: #000000"> citrus)<br />{<br /> typedef list</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #0000ff">string</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">::const_iterator LI;<br /><br /> LI p1 </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> find(fruit.begin(), citrus.end(), </span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">apple</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">); </span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000"> error, 不在同一序列</span>
				<span style="COLOR: #008000">
						<br />
				</span>
				<span style="COLOR: #000000"> LI p2 </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> find(fruit.begin(), fruit.end(), </span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">apple</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">);<br /> LI p3 </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> find(citrus.begin(), citrus.end(), </span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">pear</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">);<br /> LI p4 </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> find(p2, p3, </span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">peach</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">); </span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000"> 这个更加隐蔽。</span>
				<span style="COLOR: #008000">
						<br />
				</span>
				<span style="COLOR: #000000">}<br /><br /></span>
		</div>
		<p>这里Bjarne Stroustrup给出一个解决问题的途径。其关键就是用整个容器代替x.begin, x.end()的输入。<br />这样，我们要封装两个东西，1、find()函数。 2、begin(),end()</p>
		<p>利用重载，封装find函数。<br /></p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #000000">template</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> In, </span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> T</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000"> <br />In find(Iseq</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">In</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000"> r, </span>
				<span style="COLOR: #0000ff">const</span>
				<span style="COLOR: #000000"> T</span>
				<span style="COLOR: #000000">&amp;</span>
				<span style="COLOR: #000000"> v)  </span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000">通过重载机制，得到这个find的扩充版本。</span>
				<span style="COLOR: #008000">
						<br />
				</span>
				<span style="COLOR: #000000">{<br />    </span>
				<span style="COLOR: #0000ff">return</span>
				<span style="COLOR: #000000"> find(r.first, r.second, v); </span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000">标准库中的find</span>
				<span style="COLOR: #008000">
						<br />
				</span>
				<span style="COLOR: #000000">};</span>
		</div>
		<p> </p>
		<p>利用对偶，封装迭代器。<br />首先，我们构造一个Iseq以保证迭代器是统一序列成对输入的。</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #000000">template</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> In</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #0000ff">struct</span>
				<span style="COLOR: #000000"> Iseq: </span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> pair</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">In, In</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">{<br />    Iseq(In i1, In i2): pair</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">In, In</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">(i1, i2){}<br />};<br /></span>
		</div>
		<p> </p>
		<p>接着构造一个协助函数，直接传递容器。</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #000000">template</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> C</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">Iseq</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">typename C::iterator</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000"> iiseq(C</span>
				<span style="COLOR: #000000">&amp;</span>
				<span style="COLOR: #000000"> c) </span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000">C为容器</span>
				<span style="COLOR: #008000">
						<br />
				</span>
				<span style="COLOR: #000000">{<br />    </span>
				<span style="COLOR: #0000ff">return</span>
				<span style="COLOR: #000000"> Iseq</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">typename C::iterator</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">(c.begin(), c.end());<br />}</span>
		</div>
		<p>
				<br />这样，我们可以利用上面的机制，来避免所提出的错误。</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> f(list</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #0000ff">string</span>
				<span style="COLOR: #000000">&gt;&amp;</span>
				<span style="COLOR: #000000"> fruit, list</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #0000ff">string</span>
				<span style="COLOR: #000000">&gt;&amp;</span>
				<span style="COLOR: #000000"> citrus)<br />{<br /> typedef list</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #0000ff">string</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">::const_iterator LI;<br /><br /> LI p1 </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> find(iiseq(fruit), </span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">apple</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">); <br /> LI p2 </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> find(iiseq(citrus), </span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">apple</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">);<br /> LI p3 </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> find(citrus.begin(), citrus.end(), </span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">pear</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">); </span>
				<span style="COLOR: #008000">//<br /></span>
				<span style="COLOR: #000000">}<br /></span>
		</div>
		<p> </p>
		<p>下面我们仔细分析整个机制的几个细节。<br />先让我们来看看pair的样子。</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #000000">template</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> T1, </span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> T2</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #0000ff">struct</span>
				<span style="COLOR: #000000"> std::pair{ </span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000">这里用struct来定义</span>
				<span style="COLOR: #008000">
						<br />
				</span>
				<span style="COLOR: #000000">    typedef T1 first_type;<br />    typedef T2 second_type;<br /><br />    T1 first;<br />    T2 second;<br /><br />    pair(): first(T1()), second(T2()){}<br />    pair(</span>
				<span style="COLOR: #0000ff">const</span>
				<span style="COLOR: #000000"> T1</span>
				<span style="COLOR: #000000">&amp;</span>
				<span style="COLOR: #000000"> x, </span>
				<span style="COLOR: #0000ff">const</span>
				<span style="COLOR: #000000"> T2</span>
				<span style="COLOR: #000000">&amp;</span>
				<span style="COLOR: #000000"> y): first(x), second(y){}<br />    template</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> U, </span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> v</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">
						<br />        pair(</span>
				<span style="COLOR: #0000ff">const</span>
				<span style="COLOR: #000000"> pair</span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">U, V</span>
				<span style="COLOR: #000000">&gt;&amp;</span>
				<span style="COLOR: #000000"> p): first(p.first), second(p.second){}<br />    </span>
				<span style="COLOR: #008000">//</span>
				<span style="COLOR: #008000">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span style="COLOR: #008000">
						<br />
				</span>
				<span style="COLOR: #000000">};<br /></span>
		</div>
		<p>注意pair的两个数据成员first, second都是public的，所以Iseq继承pair之后可以直接访问。</p>
		<p>考察find()函数的重载版本<br />find(Iseq&lt;In&gt; r, const T&amp; v) <br />注意“Iseq&lt;In&gt; r”使用值传递，而不用引用传递（Iseq&lt;In&gt;&amp; r）。<br />这是因为iiseq协助函数返回一个临时对象，所以在find中，不能用引用传递。<br />template&lt;class C&gt;Iseq&lt;typename C::iterator&gt; iiseq(C&amp; c) //C为容器<br />{<br /> return Iseq&lt;typename C::iterator&gt;(c.begin(), c.end());<br />}<br />大家可能会考虑到效率问题，觉得值传递可能不妥。其实不然，我们可以发现，Iseq里面的数据成员是两个Iterator，一般来说不是很大（有时，就是两个指针），在效率上不会产生很大的影响。</p>
		<p>还有这里代码中出现typename,(如return Iseq&lt;typename C::iterator&gt;(c.begin(), c.end());) 可能对初学者来说有些生疏。为什么不直接写： Iseq&lt;C::iterator&gt;(c.begin(), c.end())。这是由于编译器不能直接认出C::iterator是一种类型，所以我们加上修饰符号typename告诉编译器C::iterator使用一种类型。</p>
		<p>
				<br /> </p>
<img src ="http://www.cppblog.com/bch515/aggbug/8098.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/bch515/" target="_blank">TH</a> 2006-06-02 22:25 <a href="http://www.cppblog.com/bch515/articles/8098.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>