<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Boulevard Of Broken Dreams &#187; 编程</title>
	<atom:link href="http://www.ray77.com/tag/%e7%bc%96%e7%a8%8b/feed" rel="self" type="application/rss+xml" />
	<link>http://www.ray77.com</link>
	<description>Walking alone ... Waiting alone ...</description>
	<lastBuildDate>Mon, 10 May 2010 14:24:39 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
<xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
		<item>
		<title>2008编程语言盘点</title>
		<link>http://www.ray77.com/make-an-inventory-of-program-language-2008.html</link>
		<comments>http://www.ray77.com/make-an-inventory-of-program-language-2008.html#comments</comments>
		<pubDate>Sat, 18 Apr 2009 05:40:00 +0000</pubDate>
		<dc:creator>Rock</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[JAVA]]></category>
		<category><![CDATA[编程]]></category>
		<category><![CDATA[语言]]></category>

		<guid isPermaLink="false">http://www.ray77.com/make-an-inventory-of-program-language-2008.html</guid>
		<description><![CDATA[　　去年最受欢迎的语言和往年一样，没有变化，仍然是：Java、C、C++、PHP、Basic。前几名的语言要在短短的一两年有变动，是不太可能的。这五个语言哪个不是占据Top 5的位置五或十年以上？估计2009年仍然是这样的局面，由这几个语言独占鳌头。
　　但C#已经在快步进逼BASIC，可能再过两年就可以进入前五名。C#上升，BASIC下降，某种程度上反映出微软的VB程序员正转换到C#语言。C#正在逐渐累积和Java抗衡的能量。
　　在2009年，最值得重视的编程语言好消息，应该就是C++了。C++ 0x的x最终被设定为9，将于2009年推出这个标准。经过十年的经验累积，许多C++既有的缺点都将在这个标准中获得改善，值得我们期待。
　　得益于Google的强力背书下，Python这几年小有斩获，现在已经变成通用型脚本语言的第一选择，Python兴起，导致Perl风华难再，两者消长的态势相当明显。而且在2008年末，大家期待已久的Python 3.0也终于推出了。
　　现今，我们生活在Web的时代，Web后端或许百家争鸣（Java、PHP、.NET、……），但Web前端还是JavaScript一枝独秀。尽管JavaScript语言存在许多为人所诟病的地方，但JavaScript的重要性仍会持续上升。

　　对Delphi来说，我承认我过去看走了眼，认为它会持续触底，但2008年显然是Delphi重新被群众拥抱的一年。Delphi曾经拥有许多高手级的使用者，甚至对Visual Basic造成威胁，但是过去这几年在Java和.NET的出现之后，以及Web应用席卷全球后，Delphi明显地被边缘化了。外患加上内忧（Borland公司内部的变动），使得Delphi的形势相当不佳，连原文书都找不到几本。在Borland将开发工具部门切割出CodeGear，接着CodeGear又被Embarcadero买下之后，Delphi好像又渐渐有起色了，但说它拨云见日还太早。
　　如果说Delphi触底反弹，那么遭遇完全相反的就是Ruby了，近期Ruby的招聘大幅降低。对于一个窜升太快的语言，需求稍微有跌落，是正常现象。Ruby长期应该仍会是缓慢上升的格局。
　　今年是Lua丰收的一年，能见度大增，除了用在游戏软件开发之外，也陆续被一些重要的商业软件商所采用（例如Adobe公司）。我看好Lua，因为在嵌入式语言领域，还没有其他语言可以与之匹敌。
说到Adobe，今年推出AIR之后，好像市场的热度还没起来，所以Adobe的官方语言ActionScript依然载浮载沉。我希望它能在2009年有更好的表现。
　　Erlang在2008年的表现不错，持续缓慢上升。Java平台上的两个语言Groovy与Scala也开始受到关注。这些新语言某些程度也相对地呼应了函数式编程（functional programming）与动态语言崛起的现实状况。
　　根据Net Applications在2009年1月的数据显示，Apple计算机的市场占有率已经达到9.63%，而且iPhone在过去这一年半的销售数字更是相当抢眼。受其影响，开发MacOS应用软件的官方语言Objective-C也大有斩获，越来越受到重视。要不是Apple的笔记本太贵我买不起，否则我早就开始学Objective-C了。
我注意到过去一年有一个奇怪的语言忽然冒出头，叫做Alice。Alice是一个3D动画的制作环境，适合用来辅助说故事。这个语言之所以叫做Alice，该不会是和“Alice&#8217;s Adventures in Wonderland（爱丽斯梦游仙境）”的故事有关？
　　分析完重点语言之后，就整体来看，我们会发现动态语言和函数式语言越来越受欢迎。我自己就是从C、C++到Java、C#，再到Erlang、REBOL，我使用的语言越来越动态、越来越偏函数式编程。
动态语言受欢迎
　　由于动态语言越来越受欢迎，.NET和Java都注意到这样的现象，试图让动态语言可以更容易地整合到自己的平台上。Java阵营的Da Vinci Machine，微软的DLR（Dynamic Language Runti-me）都是这种趋势下的产物。我们可以预期在不久的未来，动态语言会更加蓬勃发展。
动态语言势力之广，可能远远超出你的想象，下面列出常见的动态语言：D、JavaScript、ActionScript、Erlang、Groovy、Lisp、Lua、Objective-C、Perl、PHP、Python、Ruby、Scala、Smalltalk、Tcl、VBScript。
　　究竟动态语言有什么样的魅力？因为动态语言可以用更简单的方式，做到静态语言很难做到的事。我很难用三言两语介绍动态语言的特点，而且动态语言的定义也似乎见仁见智，值得写一篇专文好好地介绍。
函数式语言崭露头角
　　除了动态语言，函数式语言也是一种趋势，连微软都推出了F#。去年年中我在台湾微软讲过两场F#的讲座，听众不少，显示大家对这类编程技术相当好奇。
　　函数编程（FP）长期以来没有出现在主流的商业软件世界，真正让FP无法被接受的原因可能是“执行效率”。传统上，函数式编程语言的效率确实比命令式（imperative）编程语言来得差，这在商业系统上是不能忍受的。但是这个原因却有了变化。今天，我们有了新的衡量标准：“简单”、“快速开发”比其他因素都更重要，因为现在软件的复杂度已经到了我们无法忍受的地步，而IT产业的竞争也比以往激烈许多。
　　想要“简单”、“快速开发”，就要用比较高阶的抽象，因此函数式编程比命令式编程更适合现在的开发环境。这些年来硬件的进步，使得函数式编程的效率不再是大问题；甚至由于编译技术的进步，函数式编程语言的执行速度，现在也已经不再是吴下阿蒙。
　　近年来硬件的发展，使得局势似乎180度反转成为对FP有利的局面：多CPU、多核心、超线程（Hyper Threading）的硬件架构普及，以及分布式运算的流行，这根本就是专为滋养FP繁殖而打造的环境。
但是，大多数的程序员想从OO或者procedure式的编程方式，转到FP，难度是不小的。
语言联合国
　　当一个系统比较大的时候，使用混合语言编程是很常见的，因为：
　　每个语言都有适合使用的时机，一个大系统可以分成多个次系统或模块，每个次系统都有不同的特质，适合采用不同的语言。
　　大系统开发时，开发者的人数变多。每个人倾向于使用自己熟悉的语言和工具。
以我自己的例子来说，基于上面的考虑，我规划的系统，同时使用C++、C#、REBOL、Lua，未来可能还会加入Erlang。我们用C++进行系统编程（处理低阶的，和操作系统相关的部分），使用C#写跨平台的服务器（未来考虑用Erlang取代），使用REBOL写解析器和编译器，使用Lua作内部脚本语言。每个语言各适其所。
　　使用混合语言的开发方式，另一个好处是程序员擅长什么就用什么。学习一个语言到精通的地步，需要很长的时间。我们无法要求自己团队的程序员都能使用某个我所熟悉的语言，可以退而求其次，让他们用自己最熟悉的语言，只要开发出来的东西符合我们规定即可。
　　使用混合式语言开发，只要模块切割得当，接口定义清楚，架构设计正确，那么绝对是可行的。这是我的经验之谈。
　　但是也请注意，混合多语言可能会导致维护难度的提高。当开发某模块的人离职，且当初他所使用的语言没有其它人会，这个时候麻烦就来了。
　　混合多种语言开发系统，有可能要面对语言之间的阻抗（impedance）问题，就好像不同国家之间会有不同的文化隔阂一样。好的系统设计应该要考虑到这一点，减少模块之间的接触点，设法让语言之间的阻抗降到最低。
　　我的建议
　　如果你想培养一个全能的联合国梦幻开发团队，我的建议是要集合下面的语言人才：
　　C：进行系统开发
　　C++：进行COM与传统的微软技术开发
　　C#：进行现代的微软技术开发
　　PHP：进行Web后端开发
　　JavaScript：进行Web前端开发
　　Objective-C：进行Mac或iPh-one开发
　　Java：毕竟许多地方还是会用到Java
　　Python：进行脚本开发
　　如果有一支这样的梦幻团队，应该是任何软件都能很快地开发出来吧！我想。
　　2009年，估计全世界经济都处于低谷，这个时候，身为程序员的我们，更应该好好学习一两个语言，为未来做准备。我的建议是，如果你只会系统语言，就挑一个脚本语言学习；如果你只会脚本语言，就挑一个系统语言学习；如果你只会Procedure语言，就挑一个OO语言学习；如果你只会OO语言，就挑一个函数式语言学习；如果你只会静态语言，就挑动态语言学习。如果你都会了就挑逻辑式语言（Prolog）学习。如果你是个怪胎，什么都会了，连Prolog都会了，那么就学习REBOL吧
]]></description>
			<content:encoded><![CDATA[<p>　　去年最受欢迎的语言和往年一样，没有变化，仍然是：Java、C、C++、PHP、Basic。前几名的语言要在短短的一两年有变动，是不太可能的。这五个语言哪个不是占据Top 5的位置五或十年以上？估计2009年仍然是这样的局面，由这几个语言独占鳌头。<br />
　　但C#已经在快步进逼BASIC，可能再过两年就可以进入前五名。C#上升，BASIC下降，某种程度上反映出微软的VB程序员正转换到C#语言。C#正在逐渐累积和Java抗衡的能量。<br />
　　在2009年，最值得重视的编程语言好消息，应该就是C++了。C++ 0x的x最终被设定为9，将于2009年推出这个标准。经过十年的经验累积，许多C++既有的缺点都将在这个标准中获得改善，值得我们期待。<br />
　　得益于Google的强力背书下，Python这几年小有斩获，现在已经变成通用型脚本语言的第一选择，Python兴起，导致Perl风华难再，两者消长的态势相当明显。而且在2008年末，大家期待已久的Python 3.0也终于推出了。<br />
　　现今，我们生活在Web的时代，Web后端或许百家争鸣（Java、PHP、.NET、……），但Web前端还是JavaScript一枝独秀。尽管JavaScript语言存在许多为人所诟病的地方，但JavaScript的重要性仍会持续上升。</p>
<p><span id="more-878"></span></p>
<p>　　对Delphi来说，我承认我过去看走了眼，认为它会持续触底，但2008年显然是Delphi重新被群众拥抱的一年。Delphi曾经拥有许多高手级的使用者，甚至对Visual Basic造成威胁，但是过去这几年在Java和.NET的出现之后，以及Web应用席卷全球后，Delphi明显地被边缘化了。外患加上内忧（Borland公司内部的变动），使得Delphi的形势相当不佳，连原文书都找不到几本。在Borland将开发工具部门切割出CodeGear，接着CodeGear又被Embarcadero买下之后，Delphi好像又渐渐有起色了，但说它拨云见日还太早。<br />
　　如果说Delphi触底反弹，那么遭遇完全相反的就是Ruby了，近期Ruby的招聘大幅降低。对于一个窜升太快的语言，需求稍微有跌落，是正常现象。Ruby长期应该仍会是缓慢上升的格局。<br />
　　今年是Lua丰收的一年，能见度大增，除了用在游戏软件开发之外，也陆续被一些重要的商业软件商所采用（例如Adobe公司）。我看好Lua，因为在嵌入式语言领域，还没有其他语言可以与之匹敌。<br />
说到Adobe，今年推出AIR之后，好像市场的热度还没起来，所以Adobe的官方语言ActionScript依然载浮载沉。我希望它能在2009年有更好的表现。<br />
　　Erlang在2008年的表现不错，持续缓慢上升。Java平台上的两个语言Groovy与Scala也开始受到关注。这些新语言某些程度也相对地呼应了函数式编程（functional programming）与动态语言崛起的现实状况。<br />
　　根据Net Applications在2009年1月的数据显示，Apple计算机的市场占有率已经达到9.63%，而且iPhone在过去这一年半的销售数字更是相当抢眼。受其影响，开发MacOS应用软件的官方语言Objective-C也大有斩获，越来越受到重视。要不是Apple的笔记本太贵我买不起，否则我早就开始学Objective-C了。<br />
我注意到过去一年有一个奇怪的语言忽然冒出头，叫做Alice。Alice是一个3D动画的制作环境，适合用来辅助说故事。这个语言之所以叫做Alice，该不会是和“Alice&#8217;s Adventures in Wonderland（爱丽斯梦游仙境）”的故事有关？<br />
　　分析完重点语言之后，就整体来看，我们会发现动态语言和函数式语言越来越受欢迎。我自己就是从C、C++到Java、C#，再到Erlang、REBOL，我使用的语言越来越动态、越来越偏函数式编程。</p>
<p><strong>动态语言受欢迎</strong><br />
　　由于动态语言越来越受欢迎，.NET和Java都注意到这样的现象，试图让动态语言可以更容易地整合到自己的平台上。Java阵营的Da Vinci Machine，微软的DLR（Dynamic Language Runti-me）都是这种趋势下的产物。我们可以预期在不久的未来，动态语言会更加蓬勃发展。<br />
动态语言势力之广，可能远远超出你的想象，下面列出常见的动态语言：D、JavaScript、ActionScript、Erlang、Groovy、Lisp、Lua、Objective-C、Perl、PHP、Python、Ruby、Scala、Smalltalk、Tcl、VBScript。<br />
　　究竟动态语言有什么样的魅力？因为动态语言可以用更简单的方式，做到静态语言很难做到的事。我很难用三言两语介绍动态语言的特点，而且动态语言的定义也似乎见仁见智，值得写一篇专文好好地介绍。</p>
<p><strong>函数式语言崭露头角</strong><br />
　　除了动态语言，函数式语言也是一种趋势，连微软都推出了F#。去年年中我在台湾微软讲过两场F#的讲座，听众不少，显示大家对这类编程技术相当好奇。<br />
　　函数编程（FP）长期以来没有出现在主流的商业软件世界，真正让FP无法被接受的原因可能是“执行效率”。传统上，函数式编程语言的效率确实比命令式（imperative）编程语言来得差，这在商业系统上是不能忍受的。但是这个原因却有了变化。今天，我们有了新的衡量标准：“简单”、“快速开发”比其他因素都更重要，因为现在软件的复杂度已经到了我们无法忍受的地步，而IT产业的竞争也比以往激烈许多。<br />
　　想要“简单”、“快速开发”，就要用比较高阶的抽象，因此函数式编程比命令式编程更适合现在的开发环境。这些年来硬件的进步，使得函数式编程的效率不再是大问题；甚至由于编译技术的进步，函数式编程语言的执行速度，现在也已经不再是吴下阿蒙。<br />
　　近年来硬件的发展，使得局势似乎180度反转成为对FP有利的局面：多CPU、多核心、超线程（Hyper Threading）的硬件架构普及，以及分布式运算的流行，这根本就是专为滋养FP繁殖而打造的环境。<br />
但是，大多数的程序员想从OO或者procedure式的编程方式，转到FP，难度是不小的。</p>
<p><strong>语言联合国</strong><br />
　　当一个系统比较大的时候，使用混合语言编程是很常见的，因为：<br />
　　每个语言都有适合使用的时机，一个大系统可以分成多个次系统或模块，每个次系统都有不同的特质，适合采用不同的语言。<br />
　　大系统开发时，开发者的人数变多。每个人倾向于使用自己熟悉的语言和工具。<br />
以我自己的例子来说，基于上面的考虑，我规划的系统，同时使用C++、C#、REBOL、Lua，未来可能还会加入Erlang。我们用C++进行系统编程（处理低阶的，和操作系统相关的部分），使用C#写跨平台的服务器（未来考虑用Erlang取代），使用REBOL写解析器和编译器，使用Lua作内部脚本语言。每个语言各适其所。<br />
　　使用混合语言的开发方式，另一个好处是程序员擅长什么就用什么。学习一个语言到精通的地步，需要很长的时间。我们无法要求自己团队的程序员都能使用某个我所熟悉的语言，可以退而求其次，让他们用自己最熟悉的语言，只要开发出来的东西符合我们规定即可。<br />
　　使用混合式语言开发，只要模块切割得当，接口定义清楚，架构设计正确，那么绝对是可行的。这是我的经验之谈。<br />
　　但是也请注意，混合多语言可能会导致维护难度的提高。当开发某模块的人离职，且当初他所使用的语言没有其它人会，这个时候麻烦就来了。<br />
　　混合多种语言开发系统，有可能要面对语言之间的阻抗（impedance）问题，就好像不同国家之间会有不同的文化隔阂一样。好的系统设计应该要考虑到这一点，减少模块之间的接触点，设法让语言之间的阻抗降到最低。<br />
　　我的建议<br />
　　如果你想培养一个全能的联合国梦幻开发团队，我的建议是要集合下面的语言人才：<br />
　　C：进行系统开发<br />
　　C++：进行COM与传统的微软技术开发<br />
　　C#：进行现代的微软技术开发<br />
　　PHP：进行Web后端开发<br />
　　JavaScript：进行Web前端开发<br />
　　Objective-C：进行Mac或iPh-one开发<br />
　　Java：毕竟许多地方还是会用到Java<br />
　　Python：进行脚本开发<br />
　　如果有一支这样的梦幻团队，应该是任何软件都能很快地开发出来吧！我想。<br />
　　2009年，估计全世界经济都处于低谷，这个时候，身为程序员的我们，更应该好好学习一两个语言，为未来做准备。我的建议是，如果你只会系统语言，就挑一个脚本语言学习；如果你只会脚本语言，就挑一个系统语言学习；如果你只会Procedure语言，就挑一个OO语言学习；如果你只会OO语言，就挑一个函数式语言学习；如果你只会静态语言，就挑动态语言学习。如果你都会了就挑逻辑式语言（Prolog）学习。如果你是个怪胎，什么都会了，连Prolog都会了，那么就学习REBOL吧</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ray77.com/make-an-inventory-of-program-language-2008.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>09年2月编程语言排行榜：商业编程语言的王者之争</title>
		<link>http://www.ray77.com/program-language-200902-rank.html</link>
		<comments>http://www.ray77.com/program-language-200902-rank.html#comments</comments>
		<pubDate>Sun, 22 Feb 2009 15:07:40 +0000</pubDate>
		<dc:creator>Rock</dc:creator>
				<category><![CDATA[Develop]]></category>
		<category><![CDATA[2009]]></category>
		<category><![CDATA[排行]]></category>
		<category><![CDATA[编程]]></category>
		<category><![CDATA[语言]]></category>

		<guid isPermaLink="false">http://www.ray77.com/09%e5%b9%b42%e6%9c%88%e7%bc%96%e7%a8%8b%e8%af%ad%e8%a8%80%e6%8e%92%e8%a1%8c%e6%a6%9c%ef%bc%9a%e5%95%86%e4%b8%9a%e7%bc%96%e7%a8%8b%e8%af%ad%e8%a8%80%e7%9a%84%e7%8e%8b%e8%80%85%e4%b9%8b%e4%ba%89.html</guid>
		<description><![CDATA[商业编程语言的王者之争
　　2009年2月Tiobe编程语言排行榜发布，前十位的排名没有太大变化，C语言在取得了08年年度编程语言后增势迅猛，相比去年同期增长了0.98%。本期前20名的榜单中，两种同样以商业数据处理擅长的编程语言COBOL和RPG的排名变化值得我们关注。COBOL本期跌出前20名，本期排在22位（上期排名17）；RPG语言进入前20名，排在第19位（上期排名21）。
 
　　2009年2月榜单

　　COBOL语言
　　COBOL于1960年正式发布，是一种面向数据处理的、面向文件的、面向过程(POL)的高级编程语言，是一种功能很强而又极为冗长的语言。 COBOL适合于商业及数据处理的类似英语的程序设计语言。这种语言可使商业数据处理过程精确表达。经过40多年的不断修改、丰富完善和标准化，COBOL已发展为多种版本的庞大语言，在财会工作、统计报表、计划编制、情报检索、人事管理等数据管理及商业数据处理领域，都有着广泛的应用。世界上70％的数据是用COBOL语言处理的，并且90％的ATM事务处理用的都是COBOL语言。每天在线处理的COBOL事务有300亿次，500强中有 492家（包括全部的100强）使用了COBOL语言。
　　RPG语言
　　RPG是Report Program Generator的缩写，是一种起源于用在DEC及IBM的小型机操作系统中编制报表程序的编程语言。RPG是一种完全过程化程序设计语言。其最新版本 RPG IV由IBM主要的小型机系统AS/400来支持。对中型机上的商业应用程序而言，RPG极有可能成为继COBOL后的第二个使用最多的商业程序设计语言。从本期榜单中，我们也可以看到RPG对COBOL商业编程语言王者地位的挑战。
　　前十名长期趋势

 
　　以下是排名21到50的语言

　　英文原文：http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html
]]></description>
			<content:encoded><![CDATA[<div id="attachment_715" class="wp-caption aligncenter" style="width: 604px"><img class="size-full wp-image-715" title="09年2月编程语言排行榜：商业编程语言的王者之争" src="http://www.ray77.com/wp-content/uploads/2009/02/da058.jpg" alt="da058" width="594" height="164" /><p class="wp-caption-text">商业编程语言的王者之争</p></div>
<p>　　2009年2月Tiobe编程语言排行榜发布，前十位的排名没有太大变化，C语言在取得了08年年度编程语言后增势迅猛，相比去年同期增长了0.98%。本期前20名的榜单中，两种同样以商业数据处理擅长的编程语言COBOL和RPG的排名变化值得我们关注。COBOL本期跌出前20名，本期排在22位（上期排名17）；RPG语言进入前20名，排在第19位（上期排名21）。</p>
<p><span id="more-711"></span> </p>
<p><strong>　　2009年2月榜单</strong></p>
<p style="text-align: center;"><img class="aligncenter" style="display: inline; border-width: 0px;" title="09年2月编程语言排行榜：商业编程语言的王者之争" src="http://www.ray77.com/wp-content/uploads/2009/02/tiobe090201809.jpg" border="0" alt="09年2月编程语言排行榜：商业编程语言的王者之争" width="570" height="596" /></p>
<p><strong>　　COBOL语言</strong></p>
<p>　　COBOL于1960年正式发布，是一种面向数据处理的、面向文件的、面向过程(POL)的高级编程语言，是一种功能很强而又极为冗长的语言。 COBOL适合于商业及数据处理的类似英语的程序设计语言。这种语言可使商业数据处理过程精确表达。经过40多年的不断修改、丰富完善和标准化，COBOL已发展为多种版本的庞大语言，在财会工作、统计报表、计划编制、情报检索、人事管理等数据管理及商业数据处理领域，都有着广泛的应用。世界上70％的数据是用COBOL语言处理的，并且90％的ATM事务处理用的都是COBOL语言。每天在线处理的COBOL事务有300亿次，500强中有 492家（包括全部的100强）使用了COBOL语言。</p>
<p><strong>　　RPG语言</strong></p>
<p>　　RPG是Report Program Generator的缩写，是一种起源于用在DEC及IBM的小型机操作系统中编制报表程序的编程语言。RPG是一种完全过程化程序设计语言。其最新版本 RPG IV由IBM主要的小型机系统AS/400来支持。对中型机上的商业应用程序而言，RPG极有可能成为继COBOL后的第二个使用最多的商业程序设计语言。从本期榜单中，我们也可以看到RPG对COBOL商业编程语言王者地位的挑战。</p>
<p><strong>　　前十名长期趋势</strong></p>
<p style="text-align: center;"><img class="aligncenter" style="display: block; border: 0px;" title="09年2月编程语言排行榜：商业编程语言的王者之争" src="http://www.ray77.com/wp-content/uploads/2009/02/tiobe090202.jpg" border="0" alt="09年2月编程语言排行榜：商业编程语言的王者之争" width="594" height="449" /></p>
<p> </p>
<p><strong>　　以下是排名21到50的语言</strong></p>
<p style="text-align: center;"><img class="aligncenter" style="display: block; border: 0px;" title="09年2月编程语言排行榜：商业编程语言的王者之争" src="http://www.ray77.com/wp-content/uploads/2009/02/tiobe090203.jpg" border="0" alt="09年2月编程语言排行榜：商业编程语言的王者之争" width="270" height="778" /></p>
<p><strong>　　英文原文：<a href="http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html" target="_blank">http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html</a></strong></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ray77.com/program-language-200902-rank.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>走近 STL</title>
		<link>http://www.ray77.com/into-the-stl.html</link>
		<comments>http://www.ray77.com/into-the-stl.html#comments</comments>
		<pubDate>Fri, 02 Jan 2009 12:53:21 +0000</pubDate>
		<dc:creator>Rock</dc:creator>
				<category><![CDATA[Develop]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[STL]]></category>
		<category><![CDATA[编程]]></category>

		<guid isPermaLink="false">http://www.ray77.com/?p=567</guid>
		<description><![CDATA[　　本文面向的读者：学习过C++程序设计语言（也就是说学习过Template），但是还没有接触过STL的STL的初学者。这实际上是我学习STL的一篇笔记，老鸟就不用看了。
什么是泛型程序设计
　　我们可以简单的理解为：使用模板的程序设计就是泛型程序设计。就像我们我们可以简单的理解面向对象程序设计就是使用虚函数的程序设计一样。
STL是什么
　　作为一个C++程序设计者，STL是一种不可忽视的技术。Sandard Template Library (STL)：
标准模板库,更准确的说是 C++ 程序设计语言标准模板库。学习过MFC的人知道，MFC是微软公司创建的 C++ 类库。而与之类似的是 STL 是模板库，只不过 STL 是 ANSI/ISO 标准的一部分，而 MFC 只不过是微软的一个产品而已。也就是说STL是所有C++编译器和所有操作系统平台都支持的一种库，说它是一种库是因为，虽然STL是一种标准，也就是说对所有的编译器来说，提供给C++程序设计者的接口都是一样的。也就是说同一段STL代码在不同编译器和操作系统平台上运行的结果都是相同的，但是底层实现可以是不同的。 令人兴奋的是，STL的使用者并不需要了解它的底层实现。 试想一下，如果我们有一把能打开所有锁的钥匙，那将是多么令人疯狂啊。嘎嘎。这个歪梦我做了20多年鸟。
　　STL的目的是标准化组件，这样你就不用重新开发它们了。你可以仅仅使用这些现成的组件。STL现在是C++的一部分，因此不用额外安装什么。它被内建在你的编译器之内。
为什么我们需要学习STL

STL是 C++的ANSI/ISO 标准的一部分,可以用于所有C++语言编译器和所有平台(Windows/Unix/Linux..)。STL的同一版本在任意硬件配置下都是可用的；
STL 提供了大量的可复用软件组织。例如，程序员再也不用自己设计排序，搜索算法了，这些都已经是STL的一部分了。嘎嘎，有意思吧；
使用STL 的应用程序保证了得到的实现在处理速度和内存利用方面都是高效的，因为STL设计者们已经为我们考虑好了；
使用STL编写的代码更容易修改和阅读，这是当然的鸟。因为代码更短了，很多基础工作代码已经被组件化了；
使用简单，虽然内部实现很复杂；

　　虽然，STL的优点甚多，但是STL的语法实在令初学者人头疼，许多人望而却步。可是STL是每个C++程序设计者迟早都要啃的一块骨头。因为越来越多的C++代码是用STL编写的，看不懂麻烦就大鸟。越来越多的人在用STL，不懂就无法和别人一起合作了。好事多磨嘛，早点学习早点解脱。
下面让我们来看几段代码吧：（你觉得头疼就不要看了）
//stl_cpp_1.cpp
#include &#60;iostream&#62;
double mean(double *array, size_t n)
{
    double m=0;
    for(size_t i=0; i&#60;n; ++i){
        m += array[i];
  ...]]></description>
			<content:encoded><![CDATA[<p>　　本文面向的读者：学习过C++程序设计语言（也就是说学习过Template），但是还没有接触过STL的STL的初学者。这实际上是我学习STL的一篇笔记，老鸟就不用看了。</p>
<p><strong>什么是泛型程序设计</strong><br />
　　我们可以简单的理解为：使用模板的程序设计就是泛型程序设计。就像我们我们可以简单的理解面向对象程序设计就是使用虚函数的程序设计一样。</p>
<p><strong>STL是什么</strong><br />
　　作为一个C++程序设计者，STL是一种不可忽视的技术。Sandard Template Library (STL)：<br />
标准模板库,更准确的说是 C++ 程序设计语言标准模板库。学习过MFC的人知道，MFC是微软公司创建的 C++ 类库。而与之类似的是 STL 是模板库，只不过 STL 是 ANSI/ISO 标准的一部分，而 MFC 只不过是微软的一个产品而已。也就是说STL是所有C++编译器和所有操作系统平台都支持的一种库，说它是一种库是因为，虽然STL是一种标准，也就是说对所有的编译器来说，提供给C++程序设计者的接口都是一样的。也就是说同一段STL代码在不同编译器和操作系统平台上运行的结果都是相同的，但是底层实现可以是不同的。 令人兴奋的是，STL的使用者并不需要了解它的底层实现。 试想一下，如果我们有一把能打开所有锁的钥匙，那将是多么令人疯狂啊。嘎嘎。这个歪梦我做了20多年鸟。<br />
　　STL的目的是标准化组件，这样你就不用重新开发它们了。你可以仅仅使用这些现成的组件。STL现在是C++的一部分，因此不用额外安装什么。它被内建在你的编译器之内。<span id="more-567"></span></p>
<p><strong>为什么我们需要学习STL</strong></p>
<ul>
<li>STL是 C++的ANSI/ISO 标准的一部分,可以用于所有C++语言编译器和所有平台(Windows/Unix/Linux..)。STL的同一版本在任意硬件配置下都是可用的；</li>
<li>STL 提供了大量的可复用软件组织。例如，程序员再也不用自己设计排序，搜索算法了，这些都已经是STL的一部分了。嘎嘎，有意思吧；</li>
<li>使用STL 的应用程序保证了得到的实现在处理速度和内存利用方面都是高效的，因为STL设计者们已经为我们考虑好了；</li>
<li>使用STL编写的代码更容易修改和阅读，这是当然的鸟。因为代码更短了，很多基础工作代码已经被组件化了；</li>
<li>使用简单，虽然内部实现很复杂；</li>
</ul>
<p>　　虽然，STL的优点甚多，但是STL的语法实在令初学者人头疼，许多人望而却步。可是STL是每个C++程序设计者迟早都要啃的一块骨头。因为越来越多的C++代码是用STL编写的，看不懂麻烦就大鸟。越来越多的人在用STL，不懂就无法和别人一起合作了。好事多磨嘛，早点学习早点解脱。</p>
<p>下面让我们来看几段代码吧：（你觉得头疼就不要看了）</p>
<pre>//stl_cpp_1.cpp
#include &lt;iostream&gt;
double mean(double *array, size_t n)
{
    double m=0;
    for(size_t i=0; i&lt;n; ++i){
        m += array[i];
    }
    return m/n;
}

int main(void)
{
    double a[] = {1, 2, 3, 4, 5};
    std::cout&lt;&lt;mean(a, 5)&lt;&lt;std::endl;    // will print 3
    return 0;
} </pre>
<p>好懂吧，除了那个std有点让人不舒服以外？这是一段普通的没有使用STL的C++代码。再看下面一段：</p>
<pre>//stl_cpp_2.cpp
#include &lt;vector&gt;
#include &lt;iostream&gt;

int main(void)
{
    std::vector&lt;double&gt; a;
    std::vector&lt;double&gt;::const_iterator i;
    a.push_back(1);
    a.push_back(2);
    a.push_back(3);
    a.push_back(4);
    a.push_back(5);
    for(i=a.begin(); i!=a.end(); ++i){
        std::cout&lt;&lt;(*i)&lt;&lt;std::endl;
    }
    return 0;
}</pre>
<p>　　如果你真的没有接触过STL的话，你会问，呀，vector 是啥呀？我会告诉你，那是一排美女。嘎嘎。这可不是个比喻，表想歪鸟。这是一段纯种的STL代码，看到尖括号了吧，知道那是模板了吧。看到a.push_back(5),a.begin(),a.end()你不感觉奇怪么？可是我们并没有定义这些函数啊。</p>
<pre>//stl_cpp_3.cpp
#include &lt;vector&gt;
#include &lt;iostream&gt;
int main(void)
{
    std::vector&lt;int&gt; q;
    q.push_back(10);
    q.push_back(11);
    q.push_back(12);

    std::vector&lt;int&gt; v;
    for(int i=0; i&lt;5; ++i){
        v.push_back(i);
    }
    std::vector&lt;int&gt;::iterator it = v.begin() + 1;
    it = v.insert(it, 33);
    v.insert(it, q.begin(), q.end());
    it = v.begin() + 3;
    v.insert(it, 3, -1);
    it = v.begin() + 4;
    v.erase(it);
    it = v.begin() + 1;
    v.erase(it, it + 4);
    v.clear();

    return 0;
}</pre>
<p>　　这一段你又看到了新东西了吧，iterator？？？不罗嗦了，等你看完这篇文章，回头再看就简单了。在正式介绍STL之前，我们需要花点时间来了解一下模板和命名空间。<br />
　　关于模板的其他细节，读者可以参阅《C++ Templates 中文版》（有点费脑子哦）。在这里，我只简单的介绍一下模板类和函数模板的概念。<br />
　　模板是C++中实现代码重用机制的一种工具，可以实现类型参数化，把类型定义为参数。函数模板和类模板允许用户构造模板函数和模板类。</p>
<p><img style="border: 0px;" src="http://www.vckbase.com/document/journal/vckbase42/images/stlnotesimg1.jpg" border="0" alt="" width="476" height="210" /><br />
图1</p>
<p>下面我们来看一段函数模板的例子：</p>
<pre>//stl_cpp_4.cpp
#include&lt;iostream.h&gt;
#include&lt;string.h&gt;
//定义函数模板
template&lt;class T&gt;  //template 是关键字，T 表示一种待实例化的类型
//template&lt;typename T&gt;  也是对的
T max(T a, T b)//函数模板，函数名为 max，此函数有2个T类型的参数，返回类型为T
{
  return (a&gt;b)?a:b;
}
//在此例实例化的时候，T可以是多种类型的，int,char,string…
int main(void)
{
  int x=2,y=6;
  double x1=9.123,y1=12.6543;
  cout&lt;&lt;"把T实例化为int:"&lt;&lt;max(x,y)&lt;&lt;endl;//实例化函数模板，把T实例化为int
  cout&lt;&lt;"把T实例化为double:"&lt;&lt;max(x1,y1)&lt;&lt;endl;
　//实例化函数模板，把T实例化为double
　getchar(); //这一行代码用来在dos下查看结果，也可以用cin.get();
}</pre>
<p>下面再看看，类模板：</p>
<pre>//stl_cpp_5.cpp
#include&lt;iostream.h&gt;
//定义名为ex_class的类模板
template &lt; typename T&gt;  class ex_class
{
    T value;
public:
    ex_class(T v) { value=v; }
    void set_value(T v) { value=v; }
    T get_value(void) {return value;}
};
//main()函数中测试ex_class类模板
int main(void)
{
    //测试int类型数据
    ex_class &lt;int&gt; a(5),b(10);
    cout&lt;&lt;"a.value:"&lt;&lt;a.get_value()&lt;&lt;endl;
    cout&lt;&lt;"b.value:"&lt;&lt;b.get_value()&lt;&lt;endl;
    //测试char类型数据
    ex_class &lt;char&gt; ch(''A'');
    cout&lt;&lt;"ch.value:"&lt;&lt;ch.get_value()&lt;&lt;endl;
    ch.set_value(''a'');
    cout&lt;&lt;"ch.value:"&lt;&lt;ch.get_value()&lt;&lt;endl;
    //测试double类型数据
    ex_class &lt;double&gt; x(5.5);
    cout&lt;&lt;"x.value:"&lt;&lt;x.get_value()&lt;&lt;endl;
    x.set_value(7.5);
    cout&lt;&lt;"x.value:"&lt;&lt;x.get_value()&lt;&lt;endl;
}</pre>
<p><strong>命名空间（名字空间）</strong><br />
　　命名空间是C++的一种机制，用来把单个标识符下的大量有逻辑联系的程序实体组合到一起。此标识符作为此组群的名字。命名空间用关键字namespace 来定义：</p>
<pre>//stl_cpp_6.cpp
#include &lt;iostream&gt;
using namespace std;
namespace printA
{
   print()  {cout&lt;&lt;"using namespace printA….."&lt;&lt;endl; };
}
namespace printB
{
   print()  {cout&lt;&lt;"using namespace printB….."&lt;&lt;endl; };
}
int main(void)
{
   printA::print();    //测试命名空间printA， ：：是作用域解析运算符
   printB::print();
 }
命名空间可以嵌套定义：
  namespace A
{
   functiong1(){};
   namespace B
   { }
}</pre>
<p>　　一个namespace是指一个具名的范围（named scope）。namespace被用来将相关的声明划归在一起，将不相关的代码部分隔开。命名空间只是命名了一个特殊的作用域，当程序很大，而且需要多人合作的时候，命名空间就显得特别的重要。比如2个程序员A,B 在同一个程序中定义了函数 pop(),如果没有使用命名空间，则会出错，而且这种错误难以检测出来。为了安全起见，他们可以定义不同的命名空间 A和B，在用的时候可以使用A::pop()和B::pop()来区分。<br />
　　在STL中，标准库的全部成员在预先定义的命名空间std中。如果要用类模板vector ，有两种方法：一是在程序的前面添加预处理指令：</p>
<pre>   #include &lt;vector&gt;
   using namespace std;</pre>
<p>第二种方法是：</p>
<pre>   #include &lt;vector&gt;
   using std::vector;</pre>
<p><strong>动态绑定和静态绑定</strong><br />
　　所谓绑定是指，对于参与多态行为的类型，他们具有多态行为的接口是在公共基类的设计中就预先确定的。而非绑定则对于参与多态行为的类型，他们的接口没有预先定义。<br />
　　在C++中通过继承实现的多态是动态绑定，通过模板实现的多态是静态绑定。动态绑定的接口是在运行期间（动态）完成的，静态绑定的接口是在编译期间（静态）完成的。好了，有了以上的知识我们可以来学习STL 了。</p>
<p><strong>STL 的组成</strong><br />
　　STL有三大核心部分：容器（Container）、算法（Algorithms）、迭代器（Iterator），容器适配器（container adaptor），函数对象(functor)，除此之外还有STL其他标准组件。</p>
<ul>
<li>容器：装东西的东西，装水的杯子，装咸水的大海，装人的教室……STL里的容器是可容纳一些数据的模板类；</li>
<li>算法：就是往杯子里倒水，往大海里排污，从教室里撵人……STL里的算法，就是处理容器里面数据的方法，操作；</li>
<li>迭代器：往杯子里倒水的水壶，排污的管道，撵人的那个物业管理人员……STL里的迭代器：遍历容器中数据的对象；</li>
</ul>
<p>　　对存储于容器中的数据进行处理时，迭代器能从一个成员移向另一个成员。他能按预先定义的顺序在某些容器中的成员间移动。对普通的一维数组、向量、双端队列和列表来说，迭代器是一种指针。<br />
知道了吧？嘎嘎，当然了，你猜到了，那是我在瞎扯蛋。</p>
<p>下面让我们来看看专家是怎么说的：</p>
<ul>
<li>容器（container）：容器是数据在内存中组织的方法，例如，数组、堆栈、队列、链表或二叉树（不过这些都不是STL标准容器）。STL中的容器是一种存储T（Template）类型值的有限集合的数据结构,容器的内部实现一般是类。这些值可以是对象本身，如果数据类型T代表的是Class的话。</li>
<li>算法（algorithm）：算法是应用在容器上以各种方法处理其内容的行为或功能。例如，有对容器内容排序、复制、检索和合并的算法。在STL中，算法是由模板函数表现的。这些函数不是容器类的成员函数。相反，它们是独立的函数。令人吃惊的特点之一就是其算法如此通用。不仅可以将其用于STL容器，而且可以用于普通的C＋＋数组或任何其他应用程序指定的容器。</li>
<li>迭代器(iterator)：一旦选定一种容器类型和数据行为(算法)，那么剩下唯一要他做的就是用迭代器使其相互作用。可以把达代器看作一个指向容器中元素的普通指针。可以如递增一个指针那样递增迭代器，使其依次指向容器中每一个后继的元素。迭代器是STL的一个关键部分，因为它将算法和容器连在一起。</li>
</ul>
<p>下面我将依次介绍STL的这三个主要组件。</p>
<p><strong>容器</strong><br />
　　STL中的容器有队列容器和关联容器，容器适配器（congtainer adapters：stack,queue，priority queue），位集（bit_set），串包(string_package)等等。<br />
　　在本文中，我将介绍list,vector，deque等队列容器，和set和multisets,map和multimaps等关联容器，一共7种基本容器类。<br />
　　队列容器（顺序容器）：队列容器按照线性排列来存储T类型值的集合，队列的每个成员都有自己的特有的位置。顺序容器有向量类型、双端队列类型、列表类型三种。<br />
基本容器——顺序容器<br />
　　向量（vector容器类）：＃include &lt;vector&gt;，vector是一种动态数组，是基本数组的类模板。其内部定义了很多基本操作。既然这是一个类，那么它就会有自己的构造函数。vector 类中定义了4中种构造函数：</p>
<li>默认构造函数，构造一个初始长度为0的空向量，<br />
如：vector&lt;int&gt; v1;</li>
<li>带有单个整形参数的构造函数，此参数描述了向量的初始大小。这个构造函数还有一个可选的参数，这是一个类型为T的实例，描述了各个向量种各成员的初始值；<br />
如：vector&lt;int&gt; v2(init_size,0); 如果预先定义了：int init_size;他的成员值都被初始化为0；</li>
<li>复制构造函数，构造一个新的向量，作为已存在的向量的完全复制，<br />
如：vector&lt;int&gt; v3(v2);</li>
<li>带两个常量参数的构造函数，产生初始值为一个区间的向量。区间由一个半开区间[first,last](MS word的显示可能会有问题，first前是一个左方括号，last后面是一个右圆括号)来指定。<br />
如：vector&lt;int&gt; v4（first,last）</li>
<p>下面一个例子用的是第四种构造方法，其它的方法读者可以自己试试。</p>
<pre>//stl_cpp_7.cpp
//程序：初始化演示
#include &lt;cstring&gt;
#include &lt;vector&gt;
#include &lt;iostream&gt;
using namespace std;
int ar[10] = {  12, 45, 234, 64, 12, 35, 63, 23, 12, 55  };
char* str = "Hello World";
int main(void)
{
  vector &lt;int&gt; vec1(ar, ar+10);          //first=ar,last=ar+10,不包括ar+10
  vector &lt;char&gt; vec2(str, str+strlen(str));  //first=str,last= str+strlen(str),不包括最后一个
  cout&lt;&lt;"vec1:"&lt;&lt;endl;
//打印vec1和vec2，const_iterator是迭代器，后面会讲到
//当然，也可以用for (int i=0; i&lt;vec1.size(); i++)cout &lt;&lt; vec[i];输出
//size()是vector的一个成员函数
  for(vector&lt;int&gt;::const_iterator p=vec1.begin();p!=vec1.end(); ++p)
     cout&lt;&lt;*p;
  cout&lt;&lt;''\n''&lt;&lt;"vec2:"&lt;&lt;endl;
  for(vector&lt;char&gt;::const_iterator p1=vec2.begin();p1!=vec2.end(); ++p1)
      cout&lt;&lt;*p1;
  getchar();
  return 0;
}</pre>
<p>　　为了帮助理解向量的概念，这里写了一个小例子，其中用到了vector的成员函数：begin()，end()，push_back()，assign()，front()，back()，erase()，empty()，at()，size()。</p>
<pre>//stl_cpp_8.cpp
#include &lt;iostream&gt;
#include &lt;vector&gt;
using namespace std;
typedef vector&lt;int&gt; INTVECTOR;//自定义类型INTVECTOR
//测试vector容器的功能
void main(void)
{
    //vec1对象初始为空
    INTVECTOR vec1;
    //vec2对象最初有10个值为6的元素
    INTVECTOR vec2(10,6);
    //vec3对象最初有3个值为6的元素，拷贝构造
    INTVECTOR vec3(vec2.begin(),vec2.begin()+3);
    //声明一个名为i的双向迭代器
    INTVECTOR::iterator i;
    //从前向后显示vec1中的数据
    cout&lt;&lt;"vec1.begin()--vec1.end():"&lt;&lt;endl;
    for (i =vec1.begin(); i !=vec1.end(); ++i)
        cout &lt;&lt; *i &lt;&lt; " ";
    cout &lt;&lt; endl;
    //从前向后显示vec2中的数据
    cout&lt;&lt;"vec2.begin()--vec2.end():"&lt;&lt;endl;
    for (i =vec2.begin(); i !=vec2.end(); ++i)
        cout &lt;&lt; *i &lt;&lt; " ";
    cout &lt;&lt; endl;
    //从前向后显示vec3中的数据
    cout&lt;&lt;"vec3.begin()--vec3.end():"&lt;&lt;endl;
    for (i =vec3.begin(); i !=vec3.end(); ++i)
        cout &lt;&lt; *i &lt;&lt; " ";
    cout &lt;&lt; endl;
    //测试添加和插入成员函数，vector不支持从前插入
    vec1.push_back(2);//从后面添加一个成员
    vec1.push_back(4);
vec1.insert(vec1.begin()+1,5);//在vec1第一个的位置上插入成员5
//从vec1第一的位置开始插入vec3的所有成员
vec1.insert(vec1.begin()+1,vec3.begin(),vec3.end());
cout&lt;&lt;"after push() and insert() now the vec1 is:" &lt;&lt;endl;
    for (i =vec1.begin(); i !=vec1.end(); ++i)
        cout &lt;&lt; *i &lt;&lt; " ";
    cout &lt;&lt; endl;
    //测试赋值成员函数
    vec2.assign(8,1);   // 重新给vec2赋值，8个成员的初始值都为1
    cout&lt;&lt;"vec2.assign(8,1):" &lt;&lt;endl;
    for (i =vec2.begin(); i !=vec2.end(); ++i)
        cout &lt;&lt; *i &lt;&lt; " ";
    cout &lt;&lt; endl;
    //测试引用类函数
    cout&lt;&lt;"vec1.front()="&lt;&lt;vec1.front()&lt;&lt;endl;//vec1第零个成员
    cout&lt;&lt;"vec1.back()="&lt;&lt;vec1.back()&lt;&lt;endl;//vec1的最后一个成员
    cout&lt;&lt;"vec1.at(4)="&lt;&lt;vec1.at(4)&lt;&lt;endl;//vec1的第五个成员
    cout&lt;&lt;"vec1[4]="&lt;&lt;vec1[4]&lt;&lt;endl;
    //测试移出和删除
    vec1.pop_back();//将最后一个成员移出vec1
    vec1.erase(vec1.begin()+1,vec1.end()-2);//删除成员
    cout&lt;&lt;"vec1.pop_back() and vec1.erase():" &lt;&lt;endl;
    for (i =vec1.begin(); i !=vec1.end(); ++i)
        cout &lt;&lt; *i &lt;&lt; " ";
    cout &lt;&lt; endl;
    //显示序列的状态信息
    cout&lt;&lt;"vec1.size(): "&lt;&lt;vec1.size()&lt;&lt;endl;//打印成员个数
    cout&lt;&lt;"vec1.empty(): "&lt;&lt;vec1.empty()&lt;&lt;endl;//清空
}</pre>
<p>　　push_back()是将数据放入vector（向量）或deque（双端队列）的标准函数。Insert()是一个与之类似的函数，然而它在所有容器中都可以使用，但是用法更加复杂。end()实际上是取末尾加一，以便让循环正确运行&#8211;它返回的指针指向最靠近数组界限的数据。<br />
　　在Java里面也有向量的概念。Java中的向量是对象的集合。其中，各元素可以不必同类型，元素可以增加和删除，不能直接加入原始数据类型。</p>
<p><strong>双端队列（qeque容器类）：#include &lt;deque&gt;</strong><br />
　　deque（读音：deck，意即：double queue）容器类与vector类似，支持随机访问和快速插入删除，它在容器中某一位置上的操作所花费的是线性时间。与vector不同的是，deque还支持从开始端插入数据：<br />
push_front()。此外deque也不支持与vector的capacity()、reserve()类似的操作。</p>
<pre>//stl_cpp_9.cpp
#include &lt;iostream&gt;
#include &lt;deque&gt;
using namespace std;
typedef deque&lt;int&gt; INTDEQUE;//有些人很讨厌这种定义法，呵呵
//从前向后显示deque队列的全部元素
void put_deque(INTDEQUE deque, char *name)
{
    INTDEQUE::iterator pdeque;//仍然使用迭代器输出
    cout &lt;&lt; "The contents of " &lt;&lt; name &lt;&lt; " : ";
    for(pdeque = deque.begin(); pdeque != deque.end(); pdeque++)
        cout &lt;&lt; *pdeque &lt;&lt; " ";//注意有 "*"号哦，没有"*"号的话会报错
    cout&lt;&lt;endl;
}
//测试deqtor容器的功能
void main(void)
{
	//deq1对象初始为空
    INTDEQUE deq1;
    //deq2对象最初有10个值为6的元素
    INTDEQUE deq2(10,6);
    //deq3对象最初有3个值为6的元素
    //声明一个名为i的双向迭代器变量
    INTDEQUE::iterator i;
    //从前向后显示deq1中的数据
    put_deque(deq1,"deq1");
    //从前向后显示deq2中的数据
    put_deque(deq2,"deq2");
	//从deq1序列后面添加两个元素
	deq1.push_back(2);
	deq1.push_back(4);
	cout&lt;&lt;"deq1.push_back(2) and deq1.push_back(4):"&lt;&lt;endl;
    put_deque(deq1,"deq1");
	//从deq1序列前面添加两个元素
	deq1.push_front(5);
	deq1.push_front(7);
	cout&lt;&lt;"deq1.push_front(5) and deq1.push_front(7):"&lt;&lt;endl;
    put_deque(deq1,"deq1");
	//在deq1序列中间插入数据
	deq1.insert(deq1.begin()+1,3,9);
	cout&lt;&lt;"deq1.insert(deq1.begin()+1,3,9):"&lt;&lt;endl;
    put_deque(deq1,"deq1");
	//测试引用类函数
	cout&lt;&lt;"deq1.at(4)="&lt;&lt;deq1.at(4)&lt;&lt;endl;
	cout&lt;&lt;"deq1[4]="&lt;&lt;deq1[4]&lt;&lt;endl;
	deq1.at(1)=10;
	deq1[2]=12;
	cout&lt;&lt;"deq1.at(1)=10 and deq1[2]=12 :"&lt;&lt;endl;
    put_deque(deq1,"deq1");
	//从deq1序列的前后各移去一个元素
	deq1.pop_front();
	deq1.pop_back();
	cout&lt;&lt;"deq1.pop_front() and deq1.pop_back():"&lt;&lt;endl;
    put_deque(deq1,"deq1");
	//清除deq1中的第2个元素
	deq1.erase(deq1.begin()+1);
	cout&lt;&lt;"deq1.erase(deq1.begin()+1):"&lt;&lt;endl;
    put_deque(deq1,"deq1");
	//对deq2赋值并显示
	deq2.assign(8,1);
	cout&lt;&lt;"deq2.assign(8,1):"&lt;&lt;endl;
    put_deque(deq2,"deq2");
}</pre>
<p>　　上面我们演示了deque如何进行插入删除等操作，像erase(),assign()是大多数容器都有的操作。关于deque的其他操作请参阅附录。</p>
<p><strong>表（List容器类）：#include &lt;list&gt;</strong><br />
　　 List又叫链表，是一种双线性列表，只能顺序访问（从前向后或者从后向前），图2是list的数据组织形式。与　　前面两种容器类有一个明显的区别就是：它不支持随机访问。要访问表中某个下标处的项需要从表头或表尾处（接近该下标的一端）开始循环。而且缺少下标预算符：operator[]。</p>
<p><img style="border: 0px;" src="http://www.vckbase.com/document/journal/vckbase42/images/stlnotesimg2.jpg" border="0" alt="" width="517" height="89" /><br />
图2</p>
<p>　　同时，list仍然包涵了erase(),begin(),end(),insert(),push_back(),push_front()这些基本函数，下面我们来演示一下list的其他函数功能。</p>
<p>merge()：合并两个排序列表；<br />
splice()：拼接两个列表；<br />
sort()：列表的排序；</p>
<pre>//stl_cpp_10.cpp
#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;list&gt;
using namespace std;
void PrintIt(list&lt;int&gt; n)
{
    for(list&lt;int&gt;::iterator iter=n.begin(); iter!=n.end(); ++iter)
      cout&lt;&lt;*iter&lt;&lt;" ";//用迭代器进行输出循环
    }
int main(void)
{
    list&lt;int&gt; listn1,listn2;
    //给listn1,listn2初始化
    listn1.push_back(123);
    listn1.push_back(0);
    listn1.push_back(34);
    listn1.push_back(1123);
    //now listn1:123,0,34,1123
    listn2.push_back(100);
    listn2.push_back(12);
    //now listn2:12,100
    listn1.sort();
    listn2.sort();
    //给listn1和listn2排序
    //now listn1:0,34,123,1123         listn2:12,100
    PrintIt(listn1);
    cout&lt;&lt;endl;
    PrintIt(listn2);
    listn1.merge(listn2);
    //合并两个排序列表后,listn1:0，12，34，100，123，1123
    cout&lt;&lt;endl;
    PrintIt(listn1);
    cin.get();
}</pre>
<p>　　上面并没有演示splice()函数的用法，这是一个拗口的函数。用起来有点麻烦。图3所示是splice函数的功能。将一个列表插入到另一个列表当中。list容器类定义了splice()函数的3个版本：</p>
<pre>splice(position,list_value);
splice(position,list_value,ptr);
splice(position,list_value,first,last);</pre>
<p>　　list_value是一个已存在的列表，它将被插入到源列表中，position是一个迭代参数，他当前指向的是要进行拼接的列表中的特定位置。</p>
<p><img style="border: 0px;" src="http://www.vckbase.com/document/journal/vckbase42/images/stlnotesimg3.jpg" border="0" alt="" width="503" height="138" /><br />
图3</p>
<pre>listn1:123,0,34,1123   listn2:12,100</pre>
<p>　　执行listn1.splice(find(listn1.begin(),listn1.end(),0),listn2);之后，listn1将变为：123，12，100，34，1123。即把listn2插入到listn1的0这个元素之前。其中，find()函数找到0这个元素在listn1中的位置。值得注意的是，在执行splice之后，list_value将不复存在了。这个例子中是listn2将不再存在。<br />
　　第二个版本当中的ptr是一个迭代器参数，执行的结果是把ptr所指向的值直接插入到position当前指向的位置之前.这将只向源列表中插入一个元素。<br />
　　第三个版本的first和last也是迭代器参数，并不等于list_value.begin(),list_value.end()。First指的是要插入的列的第一个元素，last指的是要插入的列的最后一个元素。</p>
<p>如果listn1:123,0,34,1123 listn2:12,43，87，100 执行完以下函数之后</p>
<pre>listn1.splice(find(listn1.begin(),listn1.end(),0),++listn2.begin(),--listn2.end());
listn1:123,43,87,0,34,1123  listn2:12,100</pre>
<p>　　以上，我们学习了vector,deque,list三种基本顺序容器，其他的顺序容器还有：slist,bit_vector等等。</p>
<p><strong>另一种容器——关联容器（有点费解哦，出去让脑子清醒一下再回来看）</strong><br />
　　与前面讲到的顺序容器相比，关联容器更注重快速和高效地检索数据的能力。这些容器是根据键值（key）来检索数据的，键可以是值也可以是容器中的某一成员。这一类中的成员在初始化后都是按一定顺序排好序的。</p>
<p><strong>集和多集（set 和multiset 容器类）：#include &lt;set&gt;</strong><br />
　　一个集合（set）是一个容器，它其中所包含的元素的值是唯一的。这在收集一个数据的具体值的时候是有用的。集合中的元素按一定的顺序排列，并被作为集合中的实例。如果你需要一个键/值对（pair）来存储数据，map（也是一个关联容器，后面将马上要讲到）是一个更好的选择。一个集合通过一个链表来组织，在插入操作和删除操作上比向量（vector）快，但查找或添加末尾的元素时会有些慢。<br />
　　在集中，所有的成员都是排列好的。如果先后往一个集中插入：12，2，3，123，5，65<br />
　　则输出该集时为：2，3，5，12，65，123<br />
　　集和多集的区别是：set支持唯一键值，set中的值都是特定的，而且只出现一次；而multiset中可以出现副本键，同一值可以出现多次。</p>
<p>Set和multiset的模板参数：</p>
<pre>template&lt;class key, class compare, class Allocator=allocator&gt;</pre>
<p>　　第一个参数key是所存储的键的类型，第二个参数是为排序值而定义的比较函数的类型，第三个参数是被实现的存储分配符的类型。在有些编译器的具体实现中，第三个参数可以省略。第二个参数使用了合适形式的迭代器为键定义了特定的关系操作符，并用来在容器中遍历值时建立顺序。集的迭代器是双向，同时也是常量的，所以迭代器在使用的时候不能修改元素的值。</p>
<p>Set定义了三个构造函数：<br />
默认构造函数：</p>
<pre>explicit set(const Compare&amp;=compare());
如：set&lt;int,less&lt;int&gt; &gt; set1;</pre>
<p>　　less&lt;int&gt;是一个标准类，用于形成降序排列函数对象。升序排列是用greater&lt;int&gt;。通过指定某一预先定义的区间来初始化set对象的构造函数：</p>
<pre>template&lt;class InputIterator&gt; set(InputIterator, InputIterator,\ const Compare&amp;=compare());
如：set&lt;int ,less&lt;int&gt; &gt;set2(vector1.begin(),vector1.end());</pre>
<p>复制构造函数：</p>
<pre>set（const set&lt;Key,Compare&amp;&gt;）;
如：set&lt;int ,less&lt;int&gt; &gt;set3(set2);</pre>
<p>下面我们来看一个简单的集和多集的插入例程：</p>
<pre>//stl_cpp_11.cpp
#include &lt;iostream&gt;
#include &lt;set&gt;
using namespace std;
int main(void)
{
    set&lt;int&gt; set1;
   for(int i=0; i&lt;10; ++i)
     set1.insert(i);
    for(set&lt;int&gt;::iterator p=set1.begin();p!=set1.end();++p)
      cout&lt;&lt;*p&lt;&lt;"";
     if(set1.insert(3).second)//把3插入到set1中
//插入成功则set1.insert(3).second返回1，否则返回0
//此例中，集中已经有3这个元素了，所以插入将失败
       cout&lt;&lt;"set insert success";
     else
       cout&lt;&lt;"set insert failed";
    int a[] = {4, 1, 1, 1, 1, 1, 0, 5, 1, 0};
    multiset&lt;int&gt; A;
A.insert(set1.begin(),set1.end());
    A.insert(a,a+10);
    cout&lt;&lt;endl;
    for(multiset&lt;int&gt;::iterator p=A.begin();p!=A.end();++p)
    cout&lt;&lt;*p&lt;&lt;" ";
   cin.get();
    return 0;
}</pre>
<p>　　在集之间可以进行并集（set_union()）、交集(set_intersection())、差集(set_diffrence())d等操作，功能强大。</p>
<p><strong>映射和多重映射（map 和multimap）：#include &lt;map&gt;</strong><br />
　　映射和多重映射基于某一类型Key的键集的存在，提供对T类型的数据进行快速和高效的检索。对map而言，键只是指存储在容器中的某一成员。Map不支持副本键，multimap支持副本键。Map和multimap对象包涵了键和各个键有关的值，键和值的数据类型是不相同的，这与set不同。set中的key和value是Key类型的，而map中的key和value是一个pair结构中的两个分量。Map支持下表运算符operator[],用访问普通数组的方式访问map，不过下标为map的键。在multimap中一个键可以对应多个不同的值。</p>
<p>下面的例程说明了map中键与值的关系。</p>
<pre> //stl_cpp_12.cpp
#include &lt;iostream&gt;
#include &lt;map&gt;
using namespace std;
int main(void)
{
   map&lt;char,int,less&lt;char&gt; &gt; map1;
   map&lt;char,int,less&lt;char&gt; &gt;::iterator mapIter;
    //char 是键的类型，int是值的类型
    //下面是初始化，与数组类似
//也可以用map1.insert(map&lt;char,int,less&lt;char&gt; &gt;::value_type(''c'',3));
map1[''c'']=3;
    map1[''d'']=4;
    map1[''a'']=1;
    map1[''b'']=2;
    for(mapIter=map1.begin();mapIter!=map1.end();++mapIter)
      cout&lt;&lt;" "&lt;&lt;(*mapIter).first&lt;&lt;": "&lt;&lt;(*mapIter).second;
   //first对应定义中的char键，second对应定义中的int值
   //检索对应于d键的值是这样做的：
   map&lt;char,int,less&lt;char&gt; &gt;::const_iterator ptr;
   ptr=map1.find(''d'');
   cout&lt;&lt;''\n''&lt;&lt;" "&lt;&lt;(*ptr).first&lt;&lt;" 键对应于值："&lt;&lt;(*ptr).second;
   cin.get();
      return 0;
}</pre>
<p>　　从以上例程中，我们可以看到map对象的行为和一般数组的行为类似。Map允许两个或多个值使用比较操作符。下面我们再看看multimap:</p>
<pre>//stl_cpp_13.cpp
#include &lt;iostream&gt;
#include &lt;map&gt;
#include &lt;string&gt;
using namespace std;
int main(void)
{
    multimap&lt;string,string,less&lt;string&gt; &gt;mulmap;
    multimap&lt;string,string,less&lt;string&gt; &gt;::iterator p;
    //初始化多重映射mulmap:
    typedef multimap&lt;string,string,less&lt;string&gt; &gt;::value_type vt;
    typedef string s;
    mulmap.insert(vt(s("Tom "),s("is a student")));
    mulmap.insert(vt(s("Tom "),s("is a boy")));
    mulmap.insert(vt(s("Tom "),s("is a bad boy of blue!")));
    mulmap.insert(vt(s("Jerry "),s("is a student")));
    mulmap.insert(vt(s("Jerry "),s("is a beatutiful girl")));
    mulmap.insert(vt(s("DJ "),s("is a student")));
    //输出初始化以后的多重映射mulmap:
    for(p=mulmap.begin();p!=mulmap.end();++p)
       cout&lt;&lt;(*p).first&lt;&lt;(*p).second&lt;&lt;endl;
    //检索并输出Jerry键所对应的所有的值
    cout&lt;&lt;"find Jerry :"&lt;&lt;endl;
    p=mulmap.find(s("Jerry "));
    while((*p).first=="Jerry ")
    {
        cout&lt;&lt;(*p).first&lt;&lt;(*p).second&lt;&lt;endl;
        ++p;
    }
    cin.get();
    return 0;
}</pre>
<p>　　在map中是不允许一个键对应多个值的，在multimap中，不支持operator[],也就是说不支持map中允许的下标操作。</p>
<p><strong>算法（algorithm）：#inlcude &lt;algorithm&gt;</strong><br />
　　STL中算法的大部分都不作为某些特定容器类的成员函数，他们是泛型的，每个算法都有处理大量不同容器类中数据的使用。值得注意的是，STL中的算法大多有多种版本，用户可以依照具体的情况选择合适版本。中在STL的泛型算法中有4类基本的算法：</p>
<ul>
<li>变序型队列算法，可以改变容器内的数据；</li>
<li>非变序型队列算法，处理容器内的数据而不改变他们；</li>
<li>排序值算法，包涵对容器中的值进行排序和合并的算法，还有二叉搜索算法 $$通用数值算法；</li>
</ul>
<p>注：STL的算法并不只是针对STL容器，对一般容器也是适用的。</p>
<p><strong>变序型队列算法（mutating algorithms）：</strong><br />
　　又叫可修改的序列算法。这类算法有复制（copy）算法、交换（swap）算法、替代（replace）算法、删除（remove）算法，移动（transfer）算法、翻转（reverse）算法等等。这些算法可以改变容器中的数据（数据值和值在容器中的位置）。下面介绍2个比较常用的算法reverse()和copy()。</p>
<pre>//stl_cpp_14.cpp
#include &lt;iostream&gt;
#include &lt;algorithm&gt;
#include &lt;iterator&gt;//下面用到了输出迭代器ostream_iterator
using namespace std;
int main(void)
{
    int arr[6]={1,12,3,2,1215,90};
	 int arr1[7];
    int arr2[6]={2,5,6,9,0,-56};
    copy(arr,(arr+6),arr1);//将数组aar复制到arr1
    cout&lt;&lt;"arr[6] copy to arr1[7],now arr1: "&lt;&lt;endl;
	for(int i=0;i&lt;7;i++)
		cout&lt;&lt;" "&lt;&lt;arr1[i];
   reverse(arr,arr+6);//将排好序的arr翻转
   cout&lt;&lt;''\n''&lt;&lt;"arr reversed ,now arr:"&lt;&lt;endl;
	copy(arr,arr+6,ostream_iterator&lt;int&gt;(cout, " "));//复制到输出迭代器
swap_ranges(arr,arr+6,arr2);//交换arr和arr2序列
	cout&lt;&lt;''\n''&lt;&lt;"arr swaped to arr2,now arr:"&lt;&lt;endl;
	copy(arr,arr+6,ostream_iterator&lt;int&gt;(cout, " "));
	cout&lt;&lt;''\n''&lt;&lt;"arr2:"&lt;&lt;endl;
	copy(arr2,arr2+6,ostream_iterator&lt;int&gt;(cout, " "));
	cin.get();
   return 0;
}</pre>
<p>revese()的功能是将一个容器内的数据顺序翻转过来，它的原型是：</p>
<pre>  template&lt;class Bidirectional &gt;
    void reverse(Bidirectional first, Bidirectional last);</pre>
<p>将first和last之间的元素翻转过来，上例中你也可以只将arr中的一部分进行翻转：</p>
<pre>   reverse(arr+3,arr+6);这也是有效的。First和last需要指定一个操作区间。</pre>
<p>Copy()是要将一个容器内的数据复制到另一个容器内，它的原型是：</p>
<pre>   Template&lt;class InputIterator ，class OutputIterator&gt;
  OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result);</pre>
<p>　　它把[first,last－1]内的队列成员复制到区间[result,result+(last-first)-1]中。泛型交换算法：Swap()操作的是单值交换，它的原型是：</p>
<pre>template&lt;class T&gt;
void swap(T&amp; a,T&amp; b);</pre>
<p>swap_ranges()操作的是两个相等大小区间中的值，它的原型是：</p>
<pre>  template&lt;class ForwardIterator1, class ForwardIterator2&gt;
  ForwardIterator2 swap_ranges(ForwardIterator1 first1,ForwardIterator1 last1, \
ForwardIterator1 first2);</pre>
<p>　　交换区间[first1,last1-1]和[first2, first2+(last1-first1)-1]之间的值，并假设这两个区间是不重叠的。</p>
<p><strong>非变序型队列算法（Non-mutating algorithm）</strong>：<br />
　　又叫不可修改的序列算法。这一类算法操作不影响其操作的容器的内容，包括搜索队列成员算法，等价性检查算法，计算队列成员个数的算法。我将用下面的例子介绍其中的find(),search(),count()：</p>
<pre>//stl_cpp_15.cpp
#include &lt;iostream&gt;
#include &lt;vector&gt;
#include &lt;algorithm&gt;
using namespace std;
int main(void)
{
    int a[10]={12,31,5,2,23,121,0,89,34,66};
    vector&lt;int&gt; v1(a,a+10);
    vector&lt;int&gt;::iterator result1,result2;//result1和result2是随机访问迭代器
    result1=find(v1.begin(),v1.end(),2);
    //在v1中找到2，result1指向v1中的2
    result2=find(v1.begin(),v1.end(),8);
    //在v1中没有找到8，result2指向的是v1.end()
    cout&lt;&lt;result1-v1.begin()&lt;&lt;endl; //3－0＝3或4－1＝3，屏幕结果是3
    cout&lt;&lt;result2-v1.end()&lt;&lt;endl;
    int b[9]={5,2,23,54,5,5,5,2,2};
    vector&lt;int&gt; v2(a+2,a+8);
    vector&lt;int&gt; v3(b,b+4);
    result1=search(v1.begin(),v1.end(),v2.begin(),v2.end());
    cout&lt;&lt;*result1&lt;&lt;endl;
    //在v1中找到了序列v2，result1指向v2在v1中开始的位置
     result1=search(v1.begin(),v1.end(),v3.begin(),v3.end());
     cout&lt;&lt;*(result1-1)&lt;&lt;endl;
    //在v1中没有找到序列v3，result指向v1.end(),屏幕打印出v1的最后一个元素66
     vector&lt;int&gt; v4(b,b+9);
     int i=count(v4.begin(),v4.end(),5);
     int j=count(v4.begin(),v4.end(),2);
     cout&lt;&lt;"there are "&lt;&lt;i&lt;&lt;" members in v4 equel to 5"&lt;&lt;endl;
     cout&lt;&lt;"there are "&lt;&lt;j&lt;&lt;" members in v4 equel to 2"&lt;&lt;endl;
     //计算v4中有多少个成员等于 5,2
    cin.get();
    return 0;
}</pre>
<p>find()的原型是：</p>
<pre>template&lt;class InputIterator，class EqualityComparable&gt;
InputIterator find(InputIterator first, InputIterator last,\
                   const EqualityComparable&amp; value);</pre>
<p>　　其功能是在序列[first,last-1]中查找value值，如果找到，就返回一个指向value在序列中第一次出现的迭代，如果没有找到，就返回一个指向last的迭代（last并不属于序列）。 search()的原型是：</p>
<pre>template &lt;class ForwardIterator1, class ForwardIterator2&gt;
ForwardIterator1 search(ForwardIterator1 first1, ForwardIterator1 last1,\
                        ForwardIterator2 first2, ForwardIterator2 last2);</pre>
<p>　　其功能是在源序列[first1,last1-1]查找目标序列[first2，last2-1]如果查找成功，就返回一个指向源序列中目标序列出现的首位置的迭代。查找失败则返回一个指向last的迭代。 Count()的原型是：</p>
<pre>template &lt;class InputIterator, class EqualityComparable&gt;
iterator_traits&lt;InputIterator&gt;::difference_type count(InputIterator first,\
InputIterator last, const EqualityComparable&amp; value);</pre>
<p>　　其功能是在序列[first,last-1]中查找出等于value的成员，返回等于value得成员的个数。</p>
<p><strong>排序算法（sort algorithm）</strong>：<br />
　　这一类算法很多，功能强大同时也相对复杂一些。这些算法依赖的是关系运算。在这里我只介绍其中比较简单的几种排序算法：sort(),merge(),includes()</p>
<pre>//stl_cpp_16.cpp
  #include &lt;iostream&gt;
#include &lt;algorithm&gt;
using namespace std;
int main(void)
{
    int a[10]={12,0,5,3,6,8,9,34,32,18};
    int b[5]={5,3,6,8,9};
    int d[15];
    sort(a,a+10);
    for(int i=0;i&lt;10;i++)
      cout&lt;&lt;" "&lt;&lt;a[i];
    sort(b,b+5);
    if(includes(a,a+10,b,b+5))
       cout&lt;&lt;''\n''&lt;&lt;"sorted b members are included in a."&lt;&lt;endl;
    else
       cout&lt;&lt;"sorted a dosn`t contain sorted b!";
     merge(a,a+10,b,b+5,d);
    for(int j=0;j&lt;15;j++)
       cout&lt;&lt;" "&lt;&lt;d[j];
    cin.get();
    return 0;
}</pre>
<p>sort()的原型是：</p>
<pre>template &lt;class RandomAccessIterator&gt;
void sort(RandomAccessIterator first, RandomAccessIterator last);</pre>
<p>　　功能是对[first,last-1]区间内的元素进行排序操作。与之类似的操作还有：partial_sort(), stable_sort()，partial_sort_copy()等等。 merge()的原型是：</p>
<pre>template &lt;class InputIterator1, class InputIterator2, class OutputIterator&gt;
OutputIterator merge(InputIterator1 first1, InputIterator1 last1,\
               InputIterator2 first2, InputIterator2 last2,OutputIterator result);</pre>
<p>　　将有序区间[first1,last1-1]和[first2,last2-1]合并到[result, result + (last1 - first1) + (last2 - first2)-1]区间内。</p>
<p>Includes()的原型是：</p>
<pre>template &lt;class InputIterator1, class InputIterator2&gt;
bool includes(InputIterator1 first1, InputIterator1 last1,\
                  InputIterator2 first2, InputIterator2 last2);</pre>
<p>　　其功能是检查有序区间[first2,last2-1]内元素是否都在[first1,last1-1]区间内，返回一个bool值。</p>
<p><strong>通用数值算法（generalized numeric algorithms）</strong><br />
　　这一类算法还不多，涉及到专业领域中有用的算术操作，独立包涵于头文件&lt;numeric&gt;中（HP版本的STL中是&lt;algo.h&gt;）。这里不作介绍。<br />
　　STL中的算法大都有多种版本，常见的版本有以下4中：</p>
<ul>
<li>默认版本，假设给出了特定操作符；</li>
<li>一般版本，使用了成员提供的操作符；</li>
<li>复制版本，对原队列的副本进行操作，常带有 _copy 后缀；</li>
<li>谓词版本，只应用于满足给定谓词的队列成员，常带有 _if 后缀；</li>
</ul>
<p>　　以上我们学习了STL容器和算法的概念，以及一些简单的STL容器和算法。在使用算法处理容器内的数据时，需要从一个数据成员移向另一个数据成员，迭代器恰好实现了这一功能。下面我们来学习STL迭代器 。</p>
<p><strong>迭代器（itertor）：#include&lt;iterator&gt;</strong><br />
　　迭代器实际上是一种泛化指针，如果一个迭代器指向了容器中的某一成员，那么迭代器将可以通过自增自减来遍历容器中的所有成员。迭代器是联系容器和算法的媒介，是算法操作容器的接口。在运用算法操作容器的时候，我们常常在不知不觉中已经使用了迭代器。<br />
STL中定义了6种迭代器：</p>
<ul>
<li>输入迭代器，在容器的连续区间内向前移动，可以读取容器内任意值；</li>
<li>输出迭代器，把值写进它所指向的队列成员中；</li>
<li>前向迭代器，读取队列中的值，并可以向前移动到下一位置（++p,p++）；</li>
<li>双向迭代器，读取队列中的值，并可以向前向后遍历容器；</li>
<li>随机访问迭代器, vector&lt;T&gt;::iterator，list&lt;T&gt;::iterator等都是这种迭代器 ；</li>
<li>流迭代器，可以直接输出、输入流中的值；</li>
</ul>
<p>　　实际上，在前面的例子中，我们不停的在用迭代器。下面我们用几个例子来帮助理解这些迭代器的用法。<br />
下面的例子用到了输入输出迭代器：</p>
<pre>// stl_cpp_17.cpp
#include &lt;iostream&gt;
#include &lt;fstream&gt;
#include &lt;iterator&gt;
#include &lt;vector&gt;
#include &lt;string&gt;
using namespace std;
int main(void)
{
    vector&lt;string&gt; v1;
    ifstream file("Text1.txt");
    if(file.fail())
    {
      cout&lt;&lt;"open file Text1.txt failed"&lt;&lt;endl;
      return 1;
    }
  copy(istream_iterator&lt;string&gt;(file),istream_iterator&lt;string&gt;(),inserter(v1,\
v1.begin()));
    copy(v1.begin(),v1.end(),ostream_iterator&lt;string&gt;(cout," "));
    cout&lt;&lt;endl;
    cin.get();
    return 0;
}</pre>
<p>　　这里用到了输入迭代器istream_iterator，输出迭代器ostream_iterator。程序完成了将一个文件输出到屏幕的功能，先将文件读入，然后通过输入迭代器把文件内容复制到类型为字符串的向量容器内，最后由输出迭代器输出。Inserter是一个输入迭代器的一个函数(迭代器适配器)，它的使用方法是：</p>
<pre>inserter (container ,pos);</pre>
<p>　　congtainer是将要用来存入数据的容器，pos是容器存入数据的开始位置。上例中，是把文件内容存入（copy()）到向量v1中。</p>
<p>现在我们已经对STL的三大基本组件有了一个大概的了解，下面让我们一起来看看STL的其他标准组件。</p>
<p><strong>函数对象（functor或者funtion objects）：#include &lt;function&gt;</strong><br />
　　函数对象又称之为仿函数。函数对象将函数封装在一个对象中，使得它可作为参数传递给合适的STL算法，从而使算法的功能得以扩展。可以把它当作函数来使用。用户也可以定义自己的函数对象。下面让我们来定义一个自己的函数对象。</p>
<pre>// stl_cpp_18.cpp
#include &lt;iostream&gt;
using namespace std;
struct int_max{
    int operator()(int x,int y){return x&gt;y?x:y; }
    };//operator() 重载了"（）"， (int x,int y)是参数列表
int main(void)
{
    cout&lt;&lt;int_max()(3,4)&lt;&lt;endl;
    cin.get();
    return 0;
}</pre>
<p>　　这里的int_max（）就是一个函数对象，struct关键字也可以用class来代替，只不过struct默认情况下是公有访问权限，而class定义的是默认私有访问权限。下面我们来定义一个STL风格的函数对象：</p>
<pre>// stl_cpp_19.cpp
#include &lt;iostream&gt;
#include &lt;vector&gt;
using namespace std;
struct adder : public unary_function&lt;double, void&gt;
    {
      adder() : sum(0) {}
      double sum;
      void operator()(double x) { sum += x; }
    };
int main(void)
{
    double a[5]={0.5644,1.1,6.6,8.8,9.9};
    vector&lt;double&gt; V(a,a+5);
    adder result = for_each(V.begin(), V.end(), adder());
    cout &lt;&lt; "The sum is " &lt;&lt; result.sum &lt;&lt; endl;
    cin.get();
    return 0;
}</pre>
<p>　　在这里，我们定义了一个函数对象adder()，这也是一个类，它的基类是unary_function函数对象。unary_function是一个空基类，不包涵任何操作或变量。只是一种格式说明，它有两个参数，第一个参数是函数对象的使用数据类型，第二个参数是它的返回类型。基于它所定义的函数对象是一元函数对象。（注：用关键字struct或者class定义的类型实际上都是&#8221;类&#8221;）<br />
　　STL内定义了各种函数对象，否定器、约束器、一元谓词、二元谓词都是常用的函数对象。函数对象对于编程来说很重要，因为他如同对象类型的抽象一样作用于操作。</p>
<p><strong>适配器（adapter）</strong>：<br />
　　适配器是用来修改其他组件接口的STL组件，是带有一个参数的类模板（这个参数是操作的值的数据类型）。STL定义了3种形式的适配器：容器适配器，迭代器适配器，函数适配器。</p>
<ul>
<li>容器适配器：包括栈（stack）、队列(queue)、优先(priority_queue)。使用容器适配器，stack就可以被实现为基本容器类型（vector,dequeue,list）的适配。可以把stack看作是某种特殊的vctor,deque或者list容器，只是其操作仍然受到stack本身属性的限制。queue和priority_queue与之类似。容器适配器的接口更为简单，只是受限比一般容器要多；</li>
<li>迭代器适配器：修改为某些基本容器定义的迭代器的接口的一种STL组件。反向迭代器和插入迭代器都属于迭代器适配器，迭代器适配器扩展了迭代器的功能；</li>
<li>函数适配器：通过转换或者修改其他函数对象使其功能得到扩展。这一类适配器有否定器（相当于&#8221;非&#8221;操作）、帮定器、函数指针适配器。</li>
</ul>
<p><strong>结束语<br />
</strong>　　如果你理解了算法、迭代器、容器，那么你几乎就了解了 STL。关于STL的其他方面，新手都是不常用的，可以暂时以理解STL的组成的编程思想为主。这篇文章里用到了19个cpp代码，每个代码都在Windows 2000+ Dev-C++ 4.9.9.0和windows 2000＋VC环境下通过编译运行。读者可以通过copy/paste到任何一款C++编译器中运行。无论你想不想学STL，先运行一下STL代码吧。编程快乐，好好学习，天天向上。</p>
<p>我是新手，欢迎高手批评，欢迎STL学习者交流： Email：taohanjunjiang@yahoo.com.cn QQ:370679790</p>
<hr />【附录】</p>
<p><strong>附录一：Dev-C++ 和VC</strong><br />
　　在Dev-C++ 4.9.9.0 +windows 2000下，不允许出现,void main(){} 而必须为 int main() {return 0;} ,或者 int main(){},奇怪的是VC对 int main(){} 的写法会提出警告，而必须为 int main() {return 0;}。建议使用标准格式 int main(void) {……return 0;}<br />
<span lang="en">　　</span>Dev-C++而且不支持头文件方式，#include &lt;iostream.h&gt;是不对的，而必须为#include &lt;iostream&gt; using namespace std; VC两种格式都支持。建议使用#include &lt;iostream&gt; using namespace std;<br />
　　如果用纯C/C++编程，建议使用比较简单的C++编译器，甚至是命令行下的编译方式。功能强大的IDE甚至会误导编程者。还要花费不少的时间来学习使用IDE开发环境。Dev比VC要简单一些，只是不适合做大型工程，而且编译时间比VC稍慢一点，纯C++编程建议使用。他有插入时间和头文件注释模板的功能，作者可以方便地插入编程、程序更改时间，方便地填写程序说明信息。<br />
　　在Dev下可以导入VC工程，而且保持原来的VC工程文件，但是Dev对VC的支持还不够，在编译的时候会遇到错误。<br />
　　在编写dos程序的时候，建议在程序的末尾return之前加上：getchar();cin.get();之类的代码，以方便看运行结果。</p>
<p><strong>附录二：中小型程序段的编辑工具</strong><br />
　　在编辑程序过程中并不一定非要在特定的IDE环境中，在有些专业化的文本编辑工具中编辑代码会更有利于代码的修改和编辑。这里介绍几种更能比较强大的文本编辑器。</p>
<ul>
<li>UltraEdit-32</li>
<li>EditPlus</li>
<li>SourceInsight</li>
<li>Vim</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.ray77.com/into-the-stl.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
