<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>roki</title>
    <description>无线搜索引擎 wap.uucun.com</description>
    <link>http://roki.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>打印时能够分页打印的CSS控制参考</title>
        <author>roki</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://roki.javaeye.com">roki</a>&nbsp;
          链接：<a href="http://roki.javaeye.com/blog/111642" style="color:red;">http://roki.javaeye.com/blog/111642</a>&nbsp;
          发表时间: 2007年08月13日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h4 class="TextColor1" id="subjcns!73C6682D4AF70DBA!393" style="MARGIN-BOTTOM: 0px">CSS 与 打印控制</h4>
<div id="msgcns!73C6682D4AF70DBA!393" twffan="done">
<div twffan="done">打印时如何控制不显示某些页面元素</div>
<div twffan="done">&lt;style&gt;<br />
@media print{<br />
INPUT {display:none}<br />
}<br />
&lt;/style&gt;</div>
<div twffan="done">打印时如何控制分页</div>
<div twffan="done">&lt;TR style=&quot;page-break-after:always;&quot;&gt;<br />
<br />
<h4 class="TextColor1" id="subjcns!73C6682D4AF70DBA!394" style="MARGIN-BOTTOM: 0px">打印时能够分页打印的CSS控制参考</h4>
<div id="msgcns!73C6682D4AF70DBA!394" twffan="done">
<div twffan="done">Pagebreak：在打印的时候强迫在样式控制的对象前后换页。
<p>Before：设置对象前出现的页分割符。设置为always时，始终在对象之前插入页分割符。相对应的CSS属性是&rdquo;page-break-before&rdquo;。 </p>
<p>After：设置对象后出现的页分割符。设置为always时，始终在对象之后插入页分割符。相对应的CSS属性是&rdquo;'&gt;。 </p>
<p>用page-break-after <br />
page-break-after版本：CSS2 兼容性：IE4+ 继承性：无 <br />
语法： <br />
page-break-after : auto | always | avoid | left | right | null <br />
取值： <br />
auto : 假如需要在对象之后插入页分割符 <br />
always : 始终在对象之后插入页分割符 <br />
avoid : 未支持。避免在对象后面插入页分割符 <br />
left : 未支持。在对象后面插入页分割符直到它到达一个空白的左页边 <br />
right : 未支持。在对象后面插入页分割符直到它到达一个空白的右页边 <br />
null : 空白字符串。取消页分割符设置 </p>
<p>说明： <br />
检索或设置对象后出现的页分割符。 <br />
此属性在打印文档时发生作用。此属性不作用于 BR 或 HR 对象。 <br />
假如在浏览器已显示的对象上此属性和 page-break-before 属性的值之间发生冲突，则导致最大数目分页的值被使用。 <br />
页分隔符不允许出现在定位对象内部。 <br />
在IE6及之前版本浏览器中， left 和 right 值的作用结果等同于 always 。 <br />
此属性对于 currentStyle 对象而言是只读的。对于其他对象而言是可读写的。 <br />
对应的脚本特性为 pageBreakAfter 。 <br />
示例： <br />
p { page-break-after: always;} </p>
</div>
</div>
</div>
</div>
          <br/>
          <span style="color:red;">
            <a href="http://roki.javaeye.com/blog/111642#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 13 Aug 2007 08:24:23 +0800</pubDate>
        <link>http://roki.javaeye.com/blog/111642</link>
        <guid>http://roki.javaeye.com/blog/111642</guid>
      </item>
      <item>
        <title>Haskell教程 (转载)</title>
        <author>roki</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://roki.javaeye.com">roki</a>&nbsp;
          链接：<a href="http://roki.javaeye.com/blog/111416" style="color:red;">http://roki.javaeye.com/blog/111416</a>&nbsp;
          发表时间: 2007年08月12日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <br />
by rufi &nbsp;2003.3.21 -- 2003.4.2 <br />
<br />
一.序 <br />
<br />
1．什么是Haskell? <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Haskell是一种函数编程语言. 1980年代以前对函数编程有很多研究, 但不同的研究者使用各自不同的语法记号, 一起交流时造成一些不便. 后来1987年的时候, 在FPCA'87会议上制定了统一的Haskell语言. Haskell吸收了各家的长处, 是一种纯粹的函数编程语言,并根据科学家Haskell B.Curry的名字命名. Haskell经过多年的发展完善, 目前使用的版本是Haskell 98. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
2．Haskell有什么特点? <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;相对Haskell来说,传统的Basic,Pascal,C++,C#,Java,Python等都是命令(imperative)编程语言, 程序语句有一定的执行次序. 函数(functional)编程语言则给出执行的内容, 关注于更高层次的&quot;做什么&quot;而不是&quot;怎么做&quot;, 这就是二者最明显的一个区别。函数编程语言的语法功能非常强，使编程的效率大幅提高。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;Haskell是世界上公认的语法最优美最简洁的一种语言。的确，Haskell语言是写给人看的，而不是写给机器看的。另一方面，这也使得的Haskell的编译技术成为一个难点。从以人为本的角度来看，程序员的时间比机器的时间更宝贵，所以Haskell是明智的选择。 <br />
<br />
3．如何获得Haskell? <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Haskell是一个公共的语言定义, 任何人都可以编写它的实现(implementation), 因而Haskell有很多解释器(比如Hugs)和编译器(比如GHC), 它们都可以在www.haskell.org上得到. 解释器的优点是便于学习和开发,程序写好后不需要编译直接就可以运行,编译器则可以将程序编译可独立执行的文件,便于发布. Haskell既能解释执行, 也能槐槐嘁? 这也是优于其他语言的一个地方. <br />
<br />
附：Hugs使用指南 <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;本文中的示例程序都将在Hugs中运行, 在这里简要介绍一下Hugs的使用方法。Hugs可以在http://www.haskell.org/hugs/下载，安装文件只有2.8M， 是学Haskell的必备工具. <br />
<br />
使用方法: <br />
<br />
1.用你自己喜欢的文本编辑器将源程序写好, 保存到文件中, 文件以扩展名 hs 结尾. <br />
<br />
2.运行Hugs, 出现提示符: Prelude&gt; ,表示Prelude库已经装载. <br />
<br />
3.输入:? 可以查看可供使用的一些命令的说明 <br />
<br />
4. 先输入:!, 然后就可以输入DOS命令并执行. 比如输入:!dir查看当前的工作目录 <br />
<br />
5. 输入:cd directory_name 将工作目录改为你保存源文件的目录 <br />
<br />
6. 输入:l file_name 将源程序载入, 提示符变为Main&gt; <br />
<br />
现在就可以在提示符后输入各种表达式以检验所定义的函数的功能, 执行所需的运算. <br />
<br />
注意: 在提示符后不可以定义新的函数, 因为Haskell中各语句不是顺序执行的, 而把整个源文件当作一个整体来处理, 在编辑器中修改源程序并保存后, 只要输入:r就重新载入, 改动就生效了. <br />
<br />
<br />
二.语法概要 <br />
<br />
1.注释有两种: 一种以&quot;--&quot;开始到行尾结束, 一种以&quot;{-&quot;开始,以&quot;-}&quot;结束,可以延续多行. <br />
<br />
2.表达式和函数都有类型,但类型声明不是必需的,有一套类型推断系统可以推断出所涉及的类型. <br />
<br />
3.函数的定义多使用模式(pattern)匹配的方法, 两个标识符(identifier)邻接就表示函数调用. <br />
<br />
4.函数变量和类型变量的标识符以小写字母开头, 类型构造和模块的标识符以大写字母开头. <br />
<br />
5.语句块以缩进区分, 从同一列开始的语句属于同一个块. <br />
<br />
6.保留字: case class data default deriving do else if import in infix infixl infixr instance let module newtype of then type where _ <br />
<br />
7.运算符可以自定义,由以下符号进行组合: <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;: # $ % &amp; * + - = . / \ &lt; &gt; ? ! @ ^ | <br />
&nbsp;预定义的运算符有: <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+ &nbsp;- &nbsp;* &nbsp;/ &nbsp;^ &nbsp;$ &nbsp;++ &nbsp;. &nbsp;&amp;&amp; &nbsp;|| &nbsp;== &nbsp;/= &lt;= &nbsp;&gt;= &nbsp;&lt; &nbsp;&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;: // &nbsp;= &nbsp;@ &nbsp;-&gt; &nbsp;=&gt; &nbsp;.. &nbsp;:: &nbsp;&lt;- &nbsp;!! <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
8.数字: 123 &nbsp;12.3 &nbsp;1.23e5 &nbsp;0o67 &nbsp;0x3A <br />
<br />
&nbsp;字符: 'a' 'A' '\n' <br />
&nbsp; <br />
&nbsp;字符串: &quot;character string&quot; <br />
&nbsp; <br />
&nbsp; <br />
三.常数 <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;在函数编程语言中, 函数是一个中心概念, 常数也可看作是常函数. 如下语句: <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f = 3 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;定义了一个常数. f 被定义为3后就不能重复定义 f=5 ,任何时候调用f, 它都返回3. 这就消除了一些边际效应,减少了出错的可能性. 以下代码在函数编程和命令编程中具有完全不同的含义: <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;a = 2 <br />
&nbsp;&nbsp;&nbsp;&nbsp;b = 4 <br />
&nbsp;&nbsp;&nbsp;&nbsp;c = a + b <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;在函数编程中解释为: 定义常数a为2, 定义b为4, 定义c为a,b之和. &nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;在命令编程中解释为: 给变量a赋值2, 给b赋值4, 求a,b之和赋给c. <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;定义和赋值的区别在于, 定义不分次序, 赋值有次序, 以上程序在Haskell中完全可以倒过来写: <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;c = a + b <br />
&nbsp;&nbsp;&nbsp;&nbsp;a = 2 <br />
&nbsp;&nbsp;&nbsp;&nbsp;b = 4 <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;另外, 定义并不计算, 比如: <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;d = 3*5 <br />
&nbsp;&nbsp;&nbsp;&nbsp;e = 1/0 <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;在命令程序中, e=1/0会引发一个错误, 在Haskell中只有当计算e时才引发错误. <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;Haskell的思维更像是人脑的思维而不是机器的思维. <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;也可以给常数加以类型说明, 比如: <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;b :: Int <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;如果没有这一类型说明, 系统自动根据 b=4 推断b的类型为: Integer <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;Int和Integer区别是Int的取值范围是有限的, Integer的大小是无限的. 因为Integer比Int更普遍,所以在没有明显说明b的类型为Int时, 就自动推断b的类型为: Integer <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;再举几个例子,在Haskell标准库Prelude中定义的常数中,有两个是: <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;pi = 4 * atan 1 <br />
&nbsp;&nbsp;&nbsp;&nbsp;otherwise = True <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
四.单变量函数 <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;如下语句: <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;f &nbsp;&nbsp;&nbsp;&nbsp;(x)=x+2 <br />
&nbsp;&nbsp;&nbsp;&nbsp;double(x)=2*x <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;就定义了两个简单的函数, 函数的类型由自变量的类型和返回值在类型决定, 用运算符&quot;-&gt;&quot;连接. <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;比如可以用以下语句说明它们的类型: <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;f &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:: Int -&gt; Int <br />
&nbsp;&nbsp;&nbsp;&nbsp;double :: Float -&gt; Float <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;表示f是从Int变量到Int变量的映射. 如果没有明显说明, 系统根据函数定义中所涉及到的运算(+),(*)推断这两个函数的类型为: &nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;Num a =&gt; a -&gt; a <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;这里a是一个类型变量, 属于一个独立的名字空间, Num是一个类, Num a =&gt; 表示类型a属于Num类. Num类中定义了(+)和(*)的运算, 继承此类的类型也支持这两种运算. 这样使用类来限定函数的类型, 使函数具有的普遍性. 把类型归为一些类, 实现了类型的多态, 也简化了编程的任务. <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;在Haskell中函数非常频繁地用到, 通常在函数的定义和使用中省去括号, 直接用两个标识符邻接表示函数作用. 所以f和double的定义可写为: <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;f x &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= x + 2 <br />
&nbsp;&nbsp;&nbsp;&nbsp;double x = 2 * x <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;调用函数的格式和定义函数的格式基本是相同的, 比如定义函数g如下: <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;g x = 2 * f x <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;函数作用的优先极高于其他所有的运算符, 所以2 * f x等价于2 * (f x), 也等价于2 * (f(x)). <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;函数作用的次序是从左向右的, 所以可以等价地定义g为: <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;g x = double (f x) <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;Prelude有一个运算符$的定义如下: <br />
&nbsp;&nbsp;&nbsp;&nbsp;infixr 0 &nbsp;$ <br />
&nbsp;&nbsp;&nbsp;&nbsp;($) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:: (a -&gt; b) -&gt; a -&gt; b <br />
&nbsp;&nbsp;&nbsp;&nbsp;f $ x &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= f x <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;可见, $也是表示函数作用的, 但它的优先级最低, 而且作用次序是从右向左的.所以还可以等价地定义g为: <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;g x = double $ f x <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;引入$, 避免了括号的使用, 尤其当$后的表达式很长有多行时使用$是很方便的. <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
五. 多变量函数 <br />
<br />
<br />
&nbsp;&nbsp;严格说来, 一个函数只能接收一个参数, 返回一个值. 但有两种方法可以实现多变量函数. <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;1.Curried函数 <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;函数接受一个参数后, 返回的也是一个函数, 这个函数对可以接受别的参数. 比如: <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;add :: Int -&gt; Int -&gt; Int <br />
&nbsp;&nbsp;add x y = x + y <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;从add类型可以看出, 有两个&quot;-&gt;&quot;, 而&quot;-&gt;&quot;的结合次序是从右向左, 所以add的类型是: <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;Int -&gt; ( Int -&gt; Int ) <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;即add接受一个Int参数, 返回一个( Int -&gt; Int )的函数, 这个函数再接受一个Int返回一个Int. <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;这样的函数就叫curried函数. <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;2.使用数组 <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;数组就是把几个变量放到一起看成是一个变量, 从而使函数可以输入和输出多个变量. 比如: <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;add :: (Int,Int) -&gt; Int <br />
&nbsp;&nbsp;add (x,y) = x+y <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;数组是Haskell中的一种数据结构, 数组中可以放不同类型的变量, 数目不限但长度固定, 数组的类型就是数组内各元素的类型组合起来构成一种类型. <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;这两种函数在使用中各有特色, 而且可以用Prelude中定义的curry和uncurry互相转换. <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;curry &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:: ((a,b) -&gt; c) -&gt; (a -&gt; b -&gt; c) <br />
&nbsp;&nbsp;curry f x y &nbsp;&nbsp;&nbsp;&nbsp;= f (x,y) <br />
<br />
&nbsp;&nbsp;uncurry &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:: (a -&gt; b -&gt; c) -&gt; ((a,b) -&gt; c) <br />
&nbsp;&nbsp;uncurry f p &nbsp;&nbsp;&nbsp;&nbsp;= f (fst p) (snd p) <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;稍作一点解释:类型说明中出现的小写a,b,c等叫类型变量, 表示任意一种类型. f (x,y)表示f接受数组为参数, curry f x y就是(curry f) x y 表示curry f可以接受两个变量为参数. 令 g=curry f, 则 g x y = f (x,y). 可见curry的转换作用, curry的类型表达更清楚和说明了这一点. uncurry也是一样的道理, 其中的fst和snd分别表示取二元数组的第一个和第二个元素.定义如下: <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;fst &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:: (a,b) -&gt; a <br />
&nbsp;&nbsp;&nbsp;fst (x,_) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= x <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;snd &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:: (a,b) -&gt; b <br />
&nbsp;&nbsp;&nbsp;snd (_,y) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= y <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&quot;_&quot;叫匿名变量, 匹配指定类型任意的输入值, 该值在&quot;=&quot;后的表达式中不会用到. <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
六. 离散函数 <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;有些函数的参变量只有有限个取值, 比如Prelude中not的定义如下: <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;not &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:: Bool -&gt; Bool <br />
&nbsp;&nbsp;&nbsp;not True &nbsp;&nbsp;&nbsp;&nbsp;= False <br />
&nbsp;&nbsp;&nbsp;not False &nbsp;&nbsp;&nbsp;= True <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;not对逻辑变量取反. <br />
<br />
&nbsp;&nbsp;&nbsp;离散的变量可以使用保留字data定义, 比如: <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;data Direction = Left|Up|Right|Down <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;这就定义了一种Direction类型的变量, 这种变量的取值只有四个值:Left,Up,Right,Down. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;data定义了一个新的类型, type则可以给一个已有的类型取一个别名.比如: <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;type Point = (Float, Float) <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;(Float, Float)是容纳两个Float变量的数组的类型, 取别名后既简化了书写, 也附加了含义. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;现在看针对离散变量的函数如何定义: <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;move :: Direction -&gt; Point -&gt; Point <br />
&nbsp;&nbsp;&nbsp;move Left &nbsp;(x,y) = (x-1,y) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;move Up &nbsp;&nbsp;&nbsp;(x,y) = (x,y-1) <br />
&nbsp;&nbsp;&nbsp;move Right (x,y) = (x+1,y) <br />
&nbsp;&nbsp;&nbsp;move Down &nbsp;(x,y) = (x,y+1) <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;即分别对应离散变量的每一个取值对函数作相应的定义. 以(x,y)表示位置, 给move输入移动的方向和当前的位置, 就输出了移动后的位置. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;再看一个例子: <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;data Thing = Paper | Stone | Scissors &nbsp;&nbsp;deriving Show <br />
<br />
&nbsp;&nbsp;&nbsp;beat :: Thing -&gt; Thing <br />
&nbsp;&nbsp;&nbsp;beat Paper &nbsp;&nbsp;&nbsp;= Scissors <br />
&nbsp;&nbsp;&nbsp;beat Stone &nbsp;&nbsp;&nbsp;= Paper <br />
&nbsp;&nbsp;&nbsp;beat Scissors = Stone <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;定义Thing类型有三个取值, deriving Show表示Thing类型继承Show类, 从而拥有的Show的method, Show类的作用是将取值转化为字符串在屏幕上显示. beat定义了三种物品,纸,石头,剪刀之间的输赢关系. <br />
&nbsp; <br />
<br />
&nbsp;&nbsp;&nbsp;自然数是离散的也是无限的, 以自然数为变量的函数通常用迭代的方法定义, 即函数自己调用自己.举个例子: <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;fac 0 = 1 <br />
&nbsp;&nbsp;&nbsp;fac n = n * fac (n-1) <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;这样计算fac n时, 先去计算fac (n-1),有fac n = n * fac (n-1)=n * (n-1) * fac (n-2),如此类推, 一直算到fac 0, 最后的结果是把从1到n的自然数全部连乘起来. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;再比如: &nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;increment,fib :: Int -&gt; Int <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;increment x=x+1 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;fib 1 = 1 <br />
&nbsp;&nbsp;&nbsp;fib 2 = 2 <br />
&nbsp;&nbsp;&nbsp;fib n = fib (n-1) + fib (n-2) <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;当计算函数时, 按照输入的参数逐一匹配所给的模式, 如果无法匹配时给出错误中断. 对于自然数模式匹配还允许用如下方式定义函数: <br />
&nbsp;&nbsp;&nbsp;foo (n+1) = n-1 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;Haskell中预定义的针对字符的函数有: <br />
&nbsp;&nbsp;&nbsp;isAscii, isLatin1, isControl, isPrint, isSpace, isUpper, isLower, <br />
&nbsp;&nbsp;&nbsp;isAlpha, isDigit, isOctDigit, isHexDigit, isAlphaNum, <br />
&nbsp;&nbsp;&nbsp;digitToInt, intToDigit, <br />
&nbsp;&nbsp;&nbsp;toUpper, toLower, <br />
&nbsp;&nbsp;&nbsp;ord, chr,等 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;ord将字母转换为数字, chr反之. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
七. 连续函数 <br />
<br />
<br />
&nbsp;&nbsp;&nbsp;Haskell中整数可以用Int和Integer表示, 实数可以用Float(单精度)和Double(双精度)来表示. 有理数还可用Rational表示, 相当于无限精度的浮点数. <br />
&nbsp;&nbsp;&nbsp;Prelude中定义了两个在数学上较基本的函数: <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;1. 常数函数 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;const &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:: a -&gt; b -&gt; a <br />
&nbsp;&nbsp;&nbsp;const k _ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= k <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;2. 单位函数 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;id &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:: a -&gt; a <br />
&nbsp;&nbsp;&nbsp;id &nbsp;&nbsp;&nbsp;x &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= x <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;当函数针对变量的不同取值范围有不同的行为时, 就要用到选择结构. 比如: <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;3. 绝对值函数 <br />
&nbsp;&nbsp;&nbsp;abs' x = if x&gt;=0 then x else -x &nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;if ... then ... else ...的结构也可以用&quot;|&quot;(guard)来表达, 上述abs'也可写成: <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;abs' x |x&gt;=0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= x <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|otherwise = -x &nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&quot;|&quot;还可用于更多的分支选择, 比如: <br />
&nbsp;&nbsp;&nbsp;4. 符号函数 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;sign x |x&gt;0 &nbsp;= 1 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|x==0 = 0 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|x&lt;0 &nbsp;= -1 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;绝对值函数和符号函数在Prelude中分别为abs和signum, 其定义是用prime函数实现的. <br />
&nbsp;&nbsp;&nbsp;下面再举几例子,以熟悉函数的定义方法. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;5. 二次方程求根函数: <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;root (a,b,c) = (x1,x2) where &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x1=(-b+d)/(2*a) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x2=(-b-d)/(2*a) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dd = b*b-4*a*c <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d | dd&gt;=0 =sqrt dd <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| dd&lt;0 &nbsp;=error &quot;No real root&quot; <br />
&nbsp;&nbsp;&nbsp;这里where引入一个内嵌的语句块, 在其中定义的函数在外部是看不到的. error函数用来提示出错的信息. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;6. 求导函数 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;diff :: (Float-&gt;Float) -&gt; (Float-&gt;Float) <br />
&nbsp;&nbsp;&nbsp;diff f = f&rsquo; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where f&rsquo; x = (f (x+h) - f x) / h <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;h = 0.0001 <br />
&nbsp;&nbsp;为了h的取值可调, 也可以把h包括在参数中: <br />
&nbsp;&nbsp;&nbsp;flexDiff h f x = (f(x+h)-f(x))/h <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;把flexDiff h sin 1的取值和cos 1的取值在h=0.001,0.0001,0.00001下比较, 取0.0001的接近程度最好. <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;7. 方程求根 <br />
&nbsp;&nbsp;利用牛顿法可定义函数为: <br />
&nbsp;&nbsp;zero :: (Float-&gt;Float) -&gt; Float <br />
&nbsp;&nbsp;zero f = until goodEnough improve 1.0 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where improve b = b - f b / diff f b <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;goodEnough b = f b ~= 0.0 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;其中until是Prelude中定义的执行循环的一个函数, 其定义如下: <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;until &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:: (a -&gt; Bool) -&gt; (a -&gt; a) -&gt; a -&gt; a <br />
&nbsp;&nbsp;until p f x &nbsp;&nbsp;&nbsp;= if p x then x else until p f (f x) <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;until的作用是看条件p x是否成立, 不成立就用f作用x, 返回值替代原来的x, 直到条件p x成立为止. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;表示约等于的运算符~=则需要自己定义. <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;8. 求逆函数 <br />
&nbsp;&nbsp;利用方程求根的结果就可以求逆: <br />
&nbsp;&nbsp;inverse :: (Float-&gt;Float) -&gt; Float -&gt; Float <br />
&nbsp;&nbsp;inverse g a = zero f <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where f x = g x - a &nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
八. 数列和数组 <br />
<br />
&nbsp;&nbsp;&nbsp;数列中元素的类型一致, 元素数目可变; 数组中元素的类型任意, 元素数目固定. 可以说数列和数组对数据的抽象做到了性能与灵活性的恰到好处, 有些语言中只提供一种容器, 元素数目可变, 类型也任意, 其结果是无法满足类型完全的需要, 也将低了运算的效率. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;数组的使用比较简单, 对于数列来说则大有文章. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;1. 数列的构造 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;数列是用[]和(:)构造的, []是一个空的数列, x:xs的含义是元素x附加到数列xs的前面组成一个更长的数列. 比如, 1:[] 等于[1], 2:3:1:[]等于[2,3,1], 运算符(:)是从右向左运算的. 所有的数列都可以看作是从[]开始, 将各元素用(:)附到上面形成的. 在实际编程中有一些简记法可以快速地构造数列. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;a. 列举法 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;将数列的元素一一列举, 比如: [1,2,3], ['A','B','d'], [[1,2], [4,5,6]]等等, 数列的类型用&quot;[元素类型]&quot;来表示, 这几个例子的类型依次为: [Int], [Char], [[Int]]. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;b. 给出变化范围 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;适用于构造等差数列, 比如: [1..5]等于[1,2,3,4,5], ['a'..'d']等于['a','b','c','d']等于&quot;abcd&quot;因为type String=[Char]. 默认的等差为1, 也可以给出前两个元素指定等差, 比如: [2,4..8]等于[2,4,6,8], [2,4..7]等于[2,4,6], [2.5,4..9.5]等于[2.5,4.0,5.5,7.0,8.5,10.0]. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;c. 描述法 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;描述法给出数列中元素取值的范围以及所满足的条件, 与数学中集合的描述法是一样的. 例如: <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;[3*x+2| x&lt;-[3,6,9]] --记号&quot;&lt;-&quot;表示属于,x依次取3,6,9,代入3*x+2,得到数列[11,20,29] <br />
&nbsp;&nbsp;&nbsp;[x*x| x&lt;-[1..9], x `rem` 3==1] --给出x的范围,还限定x除3余1 <br />
&nbsp;&nbsp;&nbsp;[(x,y)|x&lt;-[1,2,3],y&lt;-[x..3]] --等于 [(1,1),(1,2),(1,3),(2,2),(2,3),(3,3)] <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;2. 从数列中选取元素 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;head --数列的第一个元素 <br />
&nbsp;&nbsp;&nbsp;tail --除去第一个元素剩余的数列 <br />
&nbsp;&nbsp;&nbsp;last --最后一个元素 <br />
&nbsp;&nbsp;&nbsp;init --除去最后一个元素剩余的数列 <br />
&nbsp;&nbsp;&nbsp;take n --数列前n个元素 <br />
&nbsp;&nbsp;&nbsp;drop n --除去数列前n个元素剩余的数列 <br />
&nbsp;&nbsp;&nbsp;(!!)n &nbsp;--第n个元素, 索引指标从0开始 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;3. 从数列中筛选元素 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;filter p &nbsp;&nbsp;&nbsp;--把数列中所有满足条件p的元素取出来组成一个数列 <br />
&nbsp;&nbsp;&nbsp;takeWhile p --从第0个元素起, 取满足p的元素, 遇到不满足条件的元素时停止 <br />
&nbsp;&nbsp;&nbsp;dropWhile p --从第0个元素起, 去掉满足p的元素, 遇到不满足条件的元素时停止 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;条件p是一个以数列元素为自变量, 返回值为逻辑值的函数. 比如预定义的even,odd判断奇偶性. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;4. 常用数列函数 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;length lst --求数列的元素数目 <br />
&nbsp;&nbsp;&nbsp;reverse lst --将数列中元素次序反过来 <br />
&nbsp;&nbsp;&nbsp;lst1 ++ lst2 --将两个数列连成一个数列 <br />
&nbsp;&nbsp;&nbsp;concat lst &nbsp;--lst是数列的数列,concat将各子数列一个数列 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;sum lst &nbsp;--对lst中的元素求和 <br />
&nbsp;&nbsp;&nbsp;product lst &nbsp;--lst中的元素连乘 <br />
&nbsp;&nbsp;&nbsp;elem e lst --判断e是否为lst中的元素 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;or lst &nbsp;&nbsp;&nbsp;--对类型为[Bool]的lst中所有元素求或 <br />
&nbsp;&nbsp;&nbsp;and lst &nbsp;&nbsp;--对类型为[Bool]的lst中所有元素求与 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;zip <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;5. 高阶函数 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;map f lst --将lst按照函数f映射得到一个新的数列 <br />
&nbsp;&nbsp;&nbsp;map :: (a-&gt;b) -&gt; [a] -&gt; <strong><br />
&nbsp;&nbsp;&nbsp;map f [] = [] <br />
&nbsp;&nbsp;&nbsp;map f (x:xs) = f x : map f xs <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;foldr,foldl --给定一种运算和一个初值,将初值和数列中所有元素由此运算连起来计算 <br />
&nbsp;&nbsp;&nbsp;foldr :: (a-&gt;b-&gt;b) -&gt; b -&gt; [a] -&gt; b <br />
&nbsp;&nbsp;&nbsp;foldr op e [] = e <br />
&nbsp;&nbsp;&nbsp;foldr op e (x:xs) = x &lsquo;op&lsquo; foldr op e xs <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;foldl op e [] = e <br />
&nbsp;&nbsp;&nbsp;foldl op e (x:xs) = foldl op (e&lsquo;op&lsquo;x) xs &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;示例: <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;rate &nbsp;&nbsp;:: [Float]-&gt;[Float] &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;rate ls = map (/s) ls where s=sum ls &nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;--(/s)是将运算符&quot;/&quot;偏参化,并括起来当作函数使用 &nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;numDigits [] = 0 <br />
&nbsp;&nbsp;&nbsp;numDigits (c:cs) = (if (c &gt;= '0') &amp;&amp; (c &lt;= '9') then 1 else 0) + numDigits cs <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;--典型的以模式匹配和迭代的方法定义数列函数, numDigits 计算字符串中数字的个数 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
九. 无限数列 <br />
<br />
&nbsp;&nbsp;&nbsp;可以定义无限长的数列, 比如: <br />
&nbsp;&nbsp;&nbsp;from :: Int -&gt; [Int] <br />
&nbsp;&nbsp;&nbsp;from n = n : from (n+1) <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;from2 = from 2 &nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;from n得到的是一个从n开始的无限长的自然数列, 因为Haskell的lazy evaluate或non-strict的特性, 这个定义并不会引起无限次的计算. 对数列进行操作时, 有的函数要用到数列中所有的元素, 用这样的函数操作无限数列就会使计算机不停地计算, 直到内存或堆栈不够用为止; 而有的函数只用到数列的一部分元素, 这时无限数列就派上用场了. 比如: <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;take 5 from2 =&gt; [2,3,4,5,6] <br />
&nbsp;&nbsp;&nbsp;from2(!!)9 &nbsp;&nbsp;=&gt; 11 <br />
&nbsp;&nbsp;&nbsp;takeWhile (\x-&gt;x*x&lt;100) from2 =&gt; [2,3,4,5,6,7,8,9] <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;这里用&quot;=&gt;&quot;表示计算结果, (\x-&gt;x*x&lt;100) 是一个匿名函数,即用这样的格式表达了函数的输入与输出却不用给函数起名字另行定义. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;上述from函数其实可以用给出数列元素变化范围的方法直接得到数列, 比如: [2..], [1,3..] <br />
&nbsp;&nbsp;&nbsp;Prelude中定义用于生成无限数列的函数还有: <br />
&nbsp;&nbsp;&nbsp;repeat :: a -&gt; [a] <br />
&nbsp;&nbsp;&nbsp;repeat x = x : repeat x &nbsp;&nbsp;&nbsp;--对元素a无限重复 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;iterate :: (a-&gt;a) -&gt; a -&gt; [a] <br />
&nbsp;&nbsp;&nbsp;iterate f x = x : iterate f (f x) <br />
&nbsp;&nbsp;&nbsp;{- <br />
&nbsp;&nbsp;&nbsp;iterate (+1) 3 is [3, 4, 5, 6, 7, 8, . . . <br />
&nbsp;&nbsp;&nbsp;iterate (*2) 1 is [1, 2, 4, 8, 16, 32, . . . <br />
&nbsp;&nbsp;&nbsp;iterate (/10) 5678 is [5678, 567, 56, 5, 0, 0, . . . <br />
&nbsp;&nbsp;&nbsp;-} <br />
&nbsp;&nbsp;&nbsp;下面再举几个无限数列的应用的例子: <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;squares = [ x*x | x&lt;-[0..]] <br />
&nbsp;&nbsp;&nbsp;isSquare n = elem n (takeWhile (&lt;=n) squares) &nbsp;&nbsp;--判断一个数是否为平方数 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;fibs = fibgen 1 1 &nbsp;&nbsp;--Fibonacci 数列 <br />
&nbsp;&nbsp;&nbsp;fibgen n1 n2 = n1 : fibgen n2 (n1+n2) <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;primes = map head (iterate crossout [2..]) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--用筛法求素数 &nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;where &nbsp;crossout (x:xs)=filter (not.divisible x) xs <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;divisible x y = y `rem` x == 0 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;prime = sieve [2..] &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;---改进后的素数数列 <br />
&nbsp;&nbsp;sieve (x:xs) = x : sieve (filter (\y -&gt;y `rem` x /= 0) xs) <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp;有了这些定义后, take 100 prime 就是取前100个素数, prime(!!)1000 就是取第1000个素数, 因为数列的定义是无限的, 数列的计算是有限, 这样就无须为不同的需要定义不同长度的数列, Hakell处理无限数列的能力实在是令人叹服. <br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; <br />
十. 数列排序 <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Qucik Sort是对数列元素快速排序的一种算法. 初次见到的版本是: <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;qsort1 [] &nbsp;&nbsp;&nbsp;&nbsp;= [] <br />
&nbsp;&nbsp;&nbsp;&nbsp;qsort1 (x:xs) = qsort1 elts_lt_x ++ [x] ++ qsort1 elts_greq_x <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elts_lt_x &nbsp;&nbsp;= [y | y &lt;- xs, y &lt; x] <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elts_greq_x = [y | y &lt;- xs, y &gt;= x] <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;后来又有人将其写为: <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;qsort2 [] = [] <br />
&nbsp;&nbsp;&nbsp;&nbsp;qsort2 (x:xs) = qsort2 less ++ [x] ++ qsort2 more <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where less = filter &nbsp;&nbsp;(&lt;x) &nbsp;xs <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;more = filter &nbsp;&nbsp;(&gt;=x) xs <br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;可以明显地看到在比较的过程中对数列扫描的两次, 所以我就想能不能扫描一次就把比x大的和比x小的分开, 这就是我的第一个实现这一想法的程序: <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;qsort3 [] = [] <br />
&nbsp;&nbsp;&nbsp;qsort3 (x:xs) = qsort3 xl ++ [x] ++ qsort3 xr <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where &nbsp;(xl,xr,_) = until f g ([],[],xs) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f (_,_,w)=w==[] <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g (l,g,y:ys) |y&lt;=x =(y:l,g,ys) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|y&gt; x =(l,y:g,ys) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;但这个程序的效率不高, 然后就逐渐改进: <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;qsort4 []=[] <br />
&nbsp;&nbsp;&nbsp;qsort4 (x:xs)=qsort4 xl ++ [x] ++ qsort3 xr <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where (xl,xr)=split (&lt;x) xs <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;split f []=([],[]) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;split f (y:ys) |f y &nbsp;=(y:fst (split f ys),snd (split f ys)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|True =(fst (split f ys),y:snd (split f ys)) &nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;qsort5 []=[] <br />
&nbsp;&nbsp;&nbsp;qsort5 (x:xs)=qsort5 xl ++ [x] ++ qsort5 xr <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where (xl,xr)=split (&lt;x) xs <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;split f []=([],[]) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;split f (y:ys) |f y &nbsp;=(y:l,r) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|True =(l,y:r) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where (l,r)=split f ys &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;qsort6 []=[] <br />
&nbsp;&nbsp;&nbsp;qsort6 (x:xs)=qsort6 xl ++ [x] ++ qsort6 xr <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where (xl,xr)=split x xs <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;split _ [] = ([],[]) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;split e (x:xs) | e&gt;=x &nbsp;= (x:l,r) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| e&lt;x &nbsp;&nbsp;= (l,x:r) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where (l,r) = split e xs <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;qsort7 []=[] <br />
&nbsp;&nbsp;&nbsp;qsort7 (x:xs)=qsort7 xl ++ [x] ++ qsort7 xr <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where (xl,xr)=split x xs <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;split _ [] = ([],[]) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;split e (x:xs) | x&lt;e &nbsp;&nbsp;= (x:l,r) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| True &nbsp;= (l,x:r) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where (l,r) = split e xs <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;qsort8 []=[] <br />
&nbsp;&nbsp;&nbsp;qsort8 (x:xs)=qsort8 xl ++ (x: qsort8 xr) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where (xl,xr)=split x xs <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;split _ [] = ([],[]) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;split e (x:xs) | x&lt;e &nbsp;&nbsp;= (x:l,r) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| True &nbsp;= (l,x:r) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where (l,r) = split e xs &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;qsort9 ls &nbsp;= qsort' ls [] <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where &nbsp;qsort' [] &nbsp;&nbsp;&nbsp;&nbsp;acc = acc <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;qsort' (x:xs) acc = qsort' xl (x:qsort' xr acc) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where (xl,xr) = split x xs <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;split _ [] = ([],[]) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;split e (x:xs) | x&lt;e &nbsp;&nbsp;= (x:l,r) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| True &nbsp;= (l,x:r) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where (l,r) = split e xs &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;qsort10 ls = qsort' ls [] <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where &nbsp;qsort' [] &nbsp;&nbsp;&nbsp;&nbsp;acc = acc <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;qsort' (x:xs) acc = split x xs [] [] acc <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where split e [] l r acc = qsort' l (e:qsort' r acc) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;split e (x:xs) l r acc | x&lt;e &nbsp;= split e xs (x:l) r acc <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| True = split e xs l (x:r) acc &nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
<br />
&nbsp;&nbsp;&nbsp;qsort6 对算法的体现最直接, 最容易理解. 以后每一次改动都是为了提高程序运算的效率. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;尽管qsort10已经排得很快了, 但 merge sort 可以排得更快. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;msort:: Ord a =&gt; [a] -&gt; [a] <br />
&nbsp;&nbsp;&nbsp;msort = treefold merge [] . map (:[]) <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;merge:: Ord a =&gt; [a] -&gt; [a] -&gt; [a] <br />
&nbsp;&nbsp;&nbsp;merge [] b = b <br />
&nbsp;&nbsp;&nbsp;merge a [] = a <br />
&nbsp;&nbsp;&nbsp;merge (a:a's) (b:b's) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| a &lt; b = a: merge a's (b:b's) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| otherwise = b: merge (a:a's) b's <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;为了进行检验, 在源文件最开始加入: <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;import Random <br />
&nbsp;&nbsp;&nbsp;gen=mkStdGen 60 <br />
&nbsp;&nbsp;&nbsp;lst=take 100 (randomRs (1,100) gen ::[Int]) &nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;生成一个包含100个随机数的数列lst. &nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
十一. 排列组合 <br />
<br />
&nbsp;&nbsp;&nbsp;排列是把数列的元素的所有可能的排列次序都找出来. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;perms :: [a] -&gt; [[a]] <br />
&nbsp;&nbsp;&nbsp;perms [] = [ [] ] <br />
&nbsp;&nbsp;&nbsp;perms (x:xs) = concat (map (between x) (perms xs)) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where between e [] = [ [e] ] <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;between e (y:ys) = (e:y:ys) : map (y:) (between e ys) &nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;组合是从数列中取若干个元素所有可能的取法. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;combs :: Int -&gt; [a] -&gt; [[a]] <br />
&nbsp;&nbsp;&nbsp;combs 0 xs = [ [] ] <br />
&nbsp;&nbsp;&nbsp;combs (n+1) [] = [ ] <br />
&nbsp;&nbsp;&nbsp;combs (n+1) (x:xs) = map (x:) (combs n xs) ++ combs (n+1) xs <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;这两个算法都是从书上找的. 以下的程序是我自己写的: <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;maps :: [a-&gt;b]-&gt; a -&gt;<strong> <br />
&nbsp;&nbsp;&nbsp;maps [] x = [] <br />
&nbsp;&nbsp;&nbsp;maps (f:fs) x = f x : maps fs x <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;split :: Int -&gt; [a] -&gt; ([a],[a]) <br />
&nbsp;&nbsp;&nbsp;split 0 ls = ([],ls) <br />
&nbsp;&nbsp;&nbsp;split _ [] = ([],[]) <br />
&nbsp;&nbsp;&nbsp;split n (x:xs) = (x:xl,xr) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where (xl,xr)=split (n-1) xs &nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;perm :: [a]-&gt;[[a]] <br />
&nbsp;&nbsp;&nbsp;perm [] = [[]] <br />
&nbsp;&nbsp;&nbsp;perm lst = concat $ maps fs lst <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where fs = map f [0..length lst-1] <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f i lst = map (x:) (perm (xl++xs) ) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where (xl,xr)=split i lst <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(x:xs)=xr <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;maps和map的定义非常类似, 执行类似其他语言中for循环的功能, 而until执行while循环的功能. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;split将数列分成两个部分, 前半部分包括n个元素, 后半部分为剩余的元素. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;perm计算的效率虽不太高, 但是 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;perm [1,2,3] <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;输出的结果为:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] <br />
&nbsp;&nbsp;&nbsp;跟自己手工排的结果是一样的. 而 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;perms [1,2,3] <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;输出的结果为:[[1,2,3],[2,1,3],[2,3,1],[1,3,2],[3,1,2],[3,2,1]] <br />
&nbsp;&nbsp;&nbsp;看起来有点乱. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;后来对perm改进得: <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;sp xl [x] = [(xl,x,[])] &nbsp; <br />
&nbsp;&nbsp;&nbsp;sp xl (x:xr) = (xl,x,xr):sp (xl++[x]) xr <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;perm' [x]=[[x]] <br />
&nbsp;&nbsp;&nbsp;perm' ls= [x:xs|(xl,x,xr)&lt;-sp [] ls, xs&lt;-perm'(xl++xr) ] &nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;perm'同perm所用的算法和思路是一样的, 但效率已大大提高了. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
十二. 运算符 <br />
<br />
&nbsp;&nbsp;&nbsp;定义一个运算符, 要说明它的结合性和优先级. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;infixr 右结合 <br />
&nbsp;&nbsp;&nbsp;infixl 左结合 <br />
&nbsp;&nbsp;&nbsp;infix &nbsp;不结合 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;左右都可结合的运算符如 +, * 定义为左结合即可. <br />
&nbsp;&nbsp;&nbsp;优先级从0到9, 0最低, 9最高 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;已定义的运算符有: <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;level 9 . and !! <br />
&nbsp;&nbsp;&nbsp;level 8 ^ <br />
&nbsp;&nbsp;&nbsp;level 7 *, /, `div`, `rem` and `mod` <br />
&nbsp;&nbsp;&nbsp;level 6 + and - <br />
&nbsp;&nbsp;&nbsp;level 5 :, ++ and \ <br />
&nbsp;&nbsp;&nbsp;level 4 ==, /=,&lt;, &lt;=, &gt;, &gt;=, `elem` and `notElem` <br />
&nbsp;&nbsp;&nbsp;level 3 &amp;&amp; <br />
&nbsp;&nbsp;&nbsp;level 2 || <br />
&nbsp;&nbsp;&nbsp;level 1 (not used in the prelude) <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;举例: &nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;infixr 3 &nbsp;&amp;&amp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;(&amp;&amp;) &nbsp;:: Bool -&gt; Bool -&gt; Bool <br />
&nbsp;&nbsp;&nbsp;False &amp;&amp; x &nbsp;&nbsp;= False <br />
&nbsp;&nbsp;&nbsp;True &nbsp;&amp;&amp; x &nbsp;&nbsp;= x &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
<br />
&nbsp;&nbsp;&nbsp;先定义&amp;&amp;的结合性和优先级, 然后象定义函数一样定义它的功能. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;运算符用括号括起来, 可以当作函数使用, 比如: <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;map (3+) [1,2,3] <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;map (+3) [1,2,3] <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;函数名用左引号`引起来, 也可以声明为运算符, 比如: <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;fac n = product [1..n] <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;infix 5 !^!, `choose` <br />
&nbsp;&nbsp;&nbsp;(!^!), choose :: Int-&gt;Int-&gt;Int &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;n `choose` k = fac n `div` (fac k * fac (n-k)) <br />
&nbsp;&nbsp;&nbsp;n !^! k = fac n `div` (fac k * fac (n-k)) &nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;有了这些定义后, <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;choose 5 2 <br />
&nbsp;&nbsp;&nbsp;(!^!) &nbsp;5 2 <br />
&nbsp;&nbsp;&nbsp;5 &nbsp;&nbsp;!^! &nbsp;2 <br />
&nbsp;&nbsp;&nbsp;5 `choose` 2 <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;都给出答案10. &nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
十三. 复合函数 <br />
<br />
<br />
&nbsp;&nbsp;&nbsp;当一个函数的返回值的类型与另一个函数输入值的类型相同时, 这两个函数就可以复合. 在Haskell中两个函数复合用运算符(.)表示. 举几个例子: <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;f x = (x,2) <br />
&nbsp;&nbsp;&nbsp;g (x,y)=(x+y)*(x-y) <br />
&nbsp;&nbsp;&nbsp;h = g.f <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;sumaux []=[] <br />
&nbsp;&nbsp;&nbsp;sumaux (x:xs)=x+sum xs : sumaux xs <br />
&nbsp;&nbsp;&nbsp;sums =reverse.sumaux.reverse <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;函数复合也可以使用匿名函数, 比如: <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;foo=not.(\x-&gt;even x &amp;&amp; x&lt;100) <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;复合运算满足结合律: <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;f . (g . h) = (f . g) . h <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;下面看几个定理: <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;(map f . map g) xs = map (f.g) xs 即 map f . map g = map (f.g) <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;map f (xs++ys) = map f xs ++ map f ys <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;map f . concat = concat . map (map f) <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;map f . (x:) = (f x :) . map f <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;map f xs = foldr g [] ys where g x ys = f x : ys <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;concat xss = fold (++) [] xss <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;length . combs k = ( `choose` k) . length <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;sum (xs++ys) = sum xs + sum ys <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;这些定理都不难理解, 也很容易证明. 你也可以自己证明一些其他的定理. <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
十四. 小结 <br />
<br />
&nbsp;&nbsp;&nbsp;从前面各节的标题来看, Haskell根本就是在搞数学, 不象是在编程. 其实这正体现了Haskell的一个突出的优点, 它对各种数学概念提供了完美的支持, 我说Haskell是数学家的乐园. 数学是一个基础, 我认为把数学做好的编程语言才有潜力把其他事情做好. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;你在作数学题的时候, 从来也没有过把变量看作是存储器, 给变量赋值的概念, 也没有用到for,while循环语句, 而在Haskell中正好抛弃了这些概念. 用Haskell解决问题的思路与人思路非常接近, 比如相当一部分函数以数学归纳法的方式来定义, 对数据的描述性的定义等. 它掩盖了非常细节的问题, 在更高的层次上处理问题. 这样就提高了编程的效率, 提高了代码的可重用性. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;Haskell是世界上公认的语法最优美最简洁的一种语言。Haskell语言是写给人看的，而不是写给机器看的。另一方面，这也使得的Haskell的编译技术成为一个难点, 编译后的程序运行速度比C略慢一些。从以人为本的角度来看，程序员的时间比机器的时间更宝贵，所以Haskell是明智的选择。 &nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;以后各节将更多关注于Haskell编程方面的一些特性, 而不仅仅是做算术. Haskell的高效和强大将得到进一步的证实. 由于Haskell主要是在UNIX平台上发展起来的, 专门针对Windows的类库不是很多. 但Haskell的先进性是不容置疑的, 它的发展只是一个时间的问题. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;我希望你们已经意识到为什么要学函数编程语言, 欢迎来到精彩的Haskell世界--一个更好的地方. <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
十五. 输入输出 <br />
<br />
<br />
&nbsp;&nbsp;&nbsp;1.输出字符串: putChar, putStr, putStrLn, print, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;输入字符串: getChar, getLine, getContents, interact, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;2.文件操作: readFile, writeFile, appendFile, readIO, readLn &nbsp; <br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
GHC使用指南 <br />
<br />
GHC可以把Haskell程序编译为可执行文件. 操作方法如下: <br />
<br />
1.到http://www.haskell.org/ghc/下载并安装GHC. <br />
2.用cmd打开一个命令窗口. <br />
3.输入ghc --make file.hs 回车. <br />
ghc为编译器, 必要时给出ghc.exe文件所在的目录, file.hs为被编译的文件, 必要时也 <br />
给出它的目录. <br />
file.hs文件中要包含一个函数名为main的函数,运行可执行文件时这个函数被执行. <br />
4.输出文件的文件名为a.out, 将后缀名改为exe, 就可以运行了. <br />
5. 使用ghc -o foo file.hs 可以指定输出文件名, 在此例中将得到foo.exe <br />
&nbsp;&nbsp;使用ghc -O file.hs &nbsp;&nbsp;&nbsp;&nbsp;可以优化编译输出 <br />
6. 当源程序中使用了某个或多个package时,使用 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ghc -package p_name1 -package p_name2 --make file.hs <br />
&nbsp;&nbsp;加载所需的包. <br />
7. 使用ghc --interactive 可以打开ghci, 在ghci中使用:set -package name 加载包 </strong></strong>
          <br/>
          <span style="color:red;">
            <a href="http://roki.javaeye.com/blog/111416#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 12 Aug 2007 09:00:18 +0800</pubDate>
        <link>http://roki.javaeye.com/blog/111416</link>
        <guid>http://roki.javaeye.com/blog/111416</guid>
      </item>
      <item>
        <title>时代变迁</title>
        <author>roki</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://roki.javaeye.com">roki</a>&nbsp;
          链接：<a href="http://roki.javaeye.com/blog/111162" style="color:red;">http://roki.javaeye.com/blog/111162</a>&nbsp;
          发表时间: 2007年08月11日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><font face="Arial">昨天买了第七个手机，然后发现自己买过的7个手机居然都是不同牌子的，<br />
真巧。。。以下排名分先后</font></p>
<p><font face="Arial">科健 GSM<br />
西门子 GSM<br />
诺基亚 GSM<br />
普天 小灵通<br />
中兴 小灵通<br />
三星 CDMA<br />
摩托罗拉 CDMA</font></p>
<p><font face="Arial"></font>&nbsp;</p>
<font face="Arial">
<p><br />
顺便排一下自己买过的电脑， 按CPU主频排列</p>
<p>苹果PowerBook笔记本&nbsp; 16M<br />
富士通FMV笔记本&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PII233<br />
组装机&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 赛扬633<br />
组装机&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 图拉丁1G<br />
ThinkPadT30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PM1.8G<br />
组装机&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PIV2.8G</p>
<p>时代变迁啊。。。</p>
<p><br />
再顺便排一下自己使用过一段时间的程序设计语言,按时间排列<br />
名称&nbsp;使用过的时间<br />
Basic&nbsp;&nbsp; 半年<br />
Dbase&nbsp;&nbsp;&nbsp; 半年<br />
PASCAL&nbsp;&nbsp; 1年<br />
C&nbsp; 2年<br />
C++&nbsp; 3年<br />
Matlab&nbsp;&nbsp; 半年<br />
Foxfro&nbsp;&nbsp; 3个月<br />
VB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3个月<br />
Perl&nbsp;&nbsp;&nbsp;&nbsp; 3年 <br />
PHP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2年<br />
LINUX SHELL 2年<br />
爱立信汇编&nbsp; 1年<br />
JavaScript&nbsp; 1年<br />
Python&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1个月<br />
C#&nbsp;&nbsp;&nbsp;&nbsp; 3个月&nbsp;<br />
Java&nbsp;&nbsp;&nbsp;&nbsp; 2年&nbsp;<br />
IRPL (自己设计的信息采集专用语言，目前编译器和虚拟机已经开发出来，投入实际使用了) 1周</p>
<p>&nbsp;</p>
<p><br />
&nbsp; </p>
</font>
          <br/>
          <span style="color:red;">
            <a href="http://roki.javaeye.com/blog/111162#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 11 Aug 2007 06:14:43 +0800</pubDate>
        <link>http://roki.javaeye.com/blog/111162</link>
        <guid>http://roki.javaeye.com/blog/111162</guid>
      </item>
      <item>
        <title> 早上发生在银行的真实一幕，让我惭愧不已 （转载）</title>
        <author>roki</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://roki.javaeye.com">roki</a>&nbsp;
          链接：<a href="http://roki.javaeye.com/blog/104661" style="color:red;">http://roki.javaeye.com/blog/104661</a>&nbsp;
          发表时间: 2007年07月24日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <strong></strong>
<div id="textstyle_4964" onload="this.style.overflowX='auto';" style="PADDING-RIGHT: 0px; MARGIN-TOP: 10px; FONT-SIZE: 12pt; OVERFLOW-X: hidden; WIDTH: 97%; WORD-BREAK: break-all; TEXT-INDENT: 24px; LINE-HEIGHT: normal; HEIGHT: 200px; WORD-WRAP: break-word">&nbsp;&nbsp;&nbsp; 早上去了银行办一张汇款。正在大厅写汇款单的，突然一个老太婆颤微微地来到我面前，满脸皱纹，灰白头发，只见从裤袋里掏出一条尼龙薄膜袋子，又从里面掏出了两张破破烂烂的百元纸币，是现在已停止发行的老版纸钞，就是有４个国家领导人头像的那种蓝色的１００元。 <br />
　　她一边掏，一边自言自语：唉，以前省吃节用，好不容易收藏着，想不过时间长了竟这样变得破碎了，现在可怎么办呀？买东西人家都不收我。 <br />
　　我很纳闷，边上没有人，那一定是对我说的。 <br />
　　&ldquo;同志，这两百元能不能换新币呀&rdquo;她把破币摊在我的写汇款单的台桌上用双手摸了又摸，想把它抚平整一些。可我发现它不但好了少多个角了，而且也太破了，想来银行是不会兑现的。 <br />
　　难道说她想让我掏钱和她竞现？？我晕呀。不会是骗子吧。我开始不安了。可我怎么看，她都不像骗取。看年龄起码有６０岁以上了。那皱纹，那白发，那沧桑的眼神，都像极了我刚过世的奶奶。 <br />
　　我说：老奶奶，我不是工作人员，你可以到服务台上去问问。然后给她指点了方向。明知银行是不会给她好结果的，可是我也想不出更好的理由来安慰。 <br />
　　她去了那个５号窗口。结果意料之中，银行的人在解释了几遍后，早已没有耐性了，态度开始变凶说：快回家去，这破币一分不值了，拿回家扔了。别在这影响别人呀。 <br />
　　老太婆还站那边碟碟不休，她苍老单薄的影子跟银行宽大现代化的营业厅显得格格不入。很多人围观，只是和我一样爱莫能助，除了同情。 <br />
　　<br />
　　突然后面排队的人群中出来一个中年人，他从皮夹中掏出了两张新版的１００元，来到了老太婆面前：老奶奶，我这有２００元跟你换吧，你把旧版的给我吧！所有的人都吃了一惊，特别是银行那个工作人员，我看他的眼睛一下子圆了。那个老太婆也愣了，半天才反映过来：这样不好吧，同志&hellip;&hellip;我&hellip;&hellip;我&hellip;&hellip;。那个中年人打断了她：没事，这旧版我拿回家去当纪念好了。边说边伸手拿了她的两张旧版，把新版的放在老太婆的手上。然后又去后面排队了。那个老太婆离开时走到他边上说：&ldquo;你真是好人呀，阿弥陀佛，普萨会保佑你的。&rdquo;然后走出了银行。 <br />
　　我们都让这个情景所感动。都称那个中年人真是好人。他只是淡淡地笑，说没什么。 <br />
　　可这时那个银行的工作人员突然用话筒喊：你过来一下！并用手指向这个中年人。大家很纳闷。&ldquo;把刚才收到的那两张破币当然撕了，你这样做法是不符合规定的。&rdquo;那个工作人员说 <br />
　　我晕呀！这叫什么事呀？？大家议论纷纷。 <br />
　　那个中年人当着银行人员的面撕掉了那两个旧版破币。他还是这样淡淡一笑，又站在后面排队了。 <br />
　　而此时银行大厅的电子时钟正指向早上１０：３５分，而银行外面的马路上正阳光灿烂，春风妩媚！ <br />
　　<br />
　　我在想：我为什么就没有这个中年人这样行动呢？２００元对我来说也只是一个小意思。可是我为什么没这样做，最初还以为那个老太婆是个骗子？？ <br />
　　就当她是个骗子，这样大的岁数了，活在世上时间也不多了。如果能用２００元的钱，让她圆这样一个小小的梦想，又有什么不可以呢？？ <br />
　　<br />
　　损失２００元，让一个自知天命的老人得到一种幸福，这也是一种积德吧！ <br />
　　２００元，对于这样一个老人来说它早已超出了200元的价值，意义深远！！ <br />
　　<br />
　　如果下次有这样的机会，一定不会在让它错过。因为我也想当一回那个中年！</div>
          <br/>
          <span style="color:red;">
            <a href="http://roki.javaeye.com/blog/104661#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 24 Jul 2007 10:16:02 +0800</pubDate>
        <link>http://roki.javaeye.com/blog/104661</link>
        <guid>http://roki.javaeye.com/blog/104661</guid>
      </item>
      <item>
        <title>我所理解的堆排序算法 (转载)</title>
        <author>roki</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://roki.javaeye.com">roki</a>&nbsp;
          链接：<a href="http://roki.javaeye.com/blog/104515" style="color:red;">http://roki.javaeye.com/blog/104515</a>&nbsp;
          发表时间: 2007年07月23日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div align="center" twffan="done"></div>
<div twffan="done" style="WIDTH: 520px; WORD-BREAK: break-all; WORD-WRAP: break-word">
<div id="td_content" twffan="done">
<p><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 堆排序在最坏的情况下，其时间复杂度也能达到O（nlogn）。相对于快速排序来说，<br />
这是它最大的优点，此外，堆排序仅需要一个记录大小供交换用的辅助存储空间。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 堆排序的数据结构是二叉堆，二叉堆的特点有两个，一个是它是一棵完全二叉树，<br />
另一个是它的根结点小于孩子结点，所以我们很容易找到它的最小结点----根结点；当然<br />
如果你想找到最大结点的话，那就要扫描所有的叶子结点，这是很费时间的，如果你想找的<br />
是最大结点的话，你最好把它弄成一个大顶堆，即一棵根结点大于孩子结点的完全二叉树。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 二叉堆通常用数组来实现，它舍弃下标0，从下标1开始置数，则很容易满足，对于数组<br />
中任意位置i上的元素，其左儿子的位置在2i上，右儿子的位置在2i+1上，双亲的位置则在<br />
i/2上。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 堆排序的算法之一是把数组构建成二叉堆----这只要增添一个长度为n+1的辅助空间，<br />
然后把原数组的元素依次插入到二叉堆即可。然后删除二叉堆的根，把它作为排序后的数组<br />
的第一个元素,然后使二叉堆的长度减1，并通过上移使得新得到的序列仍为二叉堆，<br />
再提取新二叉堆的第一个元素到新数组。依此类推，直到提取最后一个元素，<br />
新得到的数组就是排序后的数组。<br />
template &lt;class T&gt;<br />
void Insert(T a[], int len, T x)//把x插入到原长度为len的二叉堆，注意保证新二叉堆不越界<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i=len; i/2&gt;0 &amp;&amp; a[i/2]&gt;x; i/=2)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a[i] = a[i/2];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a[i] = x;<br />
}</p>
<p>template &lt;class T&gt;<br />
T DeleteMin(T a[], int len)//删除二叉堆的根，并通过上移使得新得到的序列仍为二叉堆<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (len == 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exit(1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T min = a[1];//二叉堆的根<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T last = a[len--];//二叉堆的最后一个元素</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int c;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i=1; i*2&lt;=len; i=c)//把二叉堆的某些元素往前移，使得新得到的序列仍为二叉堆<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c = i * 2;//i的左儿子<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (c != len &amp;&amp; a[c+1] &lt; a[c])//若i有右儿子，且右儿子小于左儿子，c指向右儿子<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c++;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (last &gt; a[c])//若i的小儿子小于二叉堆的最后一个元素，把其移到i的位置<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a[i] = a[c];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a[i] = last; //把二叉堆的最后一个元素放到适当的空位，此时得到的序列仍为二叉堆</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return min;<br />
}</p>
<p>template &lt;class T&gt;<br />
void HeapSort(T a[], int len)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T *ca = new T[len+1]; //复制原数组到二叉堆<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ca[0] = 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i=0; i&lt;len; i++) //把元素依次插入到二叉堆<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Insert(ca, i+1, a[i]);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i=0; i&lt;len; i++)//依次提取二叉堆的根作为排序后的数组的元素<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a[i] = DeleteMin(ca, len-i);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a[len-1] = ca[1]; //注意不能忘了最后一个元素</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delete []ca;<br />
}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在《数据结构习题与解析》（李春葆 编著 清华大学出版社）中看到一个类似的算法，<br />
它是把原数组构建成一个大顶堆，然后把大顶堆的第一个元素与最后一个元素交换；<br />
再把前n-1个元素重新构造成一个大顶堆，把新大顶堆的第一个元素与最后一个元素交换；<br />
依此类推，直到新大顶堆只有一个元素，这样就得到了一个有序的二叉堆。<br />
算法如下：<br />
template &lt;class T&gt;<br />
void HeapSort(T a[], int len)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T *ca = new T[len+1];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ca[0] = 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i=0; i&lt;len; i++)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ca[i+1] = a[i];</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i=len/2; i&gt;0; i--) //建立初始堆<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HeapAdjust(ca, len, i);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i=len; i&gt;1; i--)//进行len-1次循环，完成堆排序<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Swap(ca[1], ca[i]); //新大顶堆的第一个元素与最后一个元素交换<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HeapAdjust(ca, i-1, 1);//筛a[1]元素，得到i-1个元素的堆<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i=0; i&lt;len; i++)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a[i] = ca[i+1];</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delete []ca;<br />
}</p>
<p>template &lt;class T&gt;<br />
void HeapAdjust(T a[], int len, int left) //将i与其小儿子交换位置<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (len == 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exit(1);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T x = a[left];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i = left;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int c = 2 * i;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (c &lt;= len)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (c &lt; len &amp;&amp; a[c+1] &gt; a[c])//若i有右儿子，且右儿子大于左儿子，c指向右儿子<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c++;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (last &lt; a[c])//若i的大儿子大于二叉堆的最后一个元素，把其移到i的位置<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a[i] = a[c];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i = c;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c = 2 * i;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a[i] = x; //把原二叉堆的第一个元素放到适当的空位<br />
}</p>
<p>template &lt;class T&gt;<br />
void Swap(T &amp; a, T &amp; b)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T t = a;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a = b;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b = t;<br />
}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 还有一种方法是每次都要重新调整大顶堆，使得父亲比儿子大，这样调整的函数较简单，<br />
但因为每次都要遍历一半的元素，时间复杂度较大。<br />
算法如下：<br />
template &lt;class T&gt;<br />
void HeapSort(T a[], int len)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T *ca = new T[len+1];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ca[0] = 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i=0; i&lt;len; i++)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ca[i+1] = a[i];</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i=len/2; i&gt;0; i--) //把原数组构建成一个大顶堆<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HeapAdjust(ca, len, i);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Swap(ca[1], ca[len]); //把大顶堆的第一个元素与最后一个元素交换<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i=len-1; i&gt;0; i--)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int j=i/2; j&gt;0; j--)//遍历长度为i的堆，得到新的大顶堆<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HeapAdjust(ca, i, j);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Swap(ca[1], ca[i]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i=0; i&lt;len; i++)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a[i] = ca[i+1];</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delete []ca;<br />
}</p>
<p>template &lt;class T&gt;<br />
void HeapAdjust(T a[], int len, int i) //将i与其小儿子交换位置<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int c = 2 * i;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (c &lt; len)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T &amp; max = (a[c] &gt; a[c+1])? a[c] : a[c+1];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (a[i] &lt; max)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Swap(a[i], max);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (a[i] &lt; a[c])<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Swap(a[i], a[c]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
}</p>
<p>template &lt;class T&gt;<br />
void Swap(T &amp; a, T &amp; b)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T t = a;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a = b;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b = t;<br />
}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 模仿构造大顶堆的方法，我们可以调用HeapAdjust()构造一个二叉堆，并提取二叉堆的根到新数组，<br />
然后把原二叉堆的最后一个元素放到根的位置，再调用HeapAdjust()构造一个新二叉堆，依此类推。<br />
算法如下：<br />
template &lt;class T&gt;<br />
void HeapSort(T a[], int len)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T *ca = new T[len+1];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ca[0] = 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i=0; i&lt;len; i++)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ca[i+1] = a[i];</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i=len/2; i&gt;0; i--) //把原数组构建成一个大顶堆<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HeapAdjust(ca, len, i);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a[0] = ca[1];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ca[1] = ca[len]; //把二叉堆的最后一个元素放到根的位置</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i=len-1; i&gt;0; i--)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int j=i/2; j&gt;0; j--)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HeapAdjust(ca, i, j);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a[len-i] = ca[1];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ca[1] = ca[i]; //把二叉堆的最后一个元素放到根的位置<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delete []ca;<br />
}</p>
<p>template &lt;class T&gt;<br />
void HeapAdjust(T a[], int len, int i)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int c = 2 * i;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (c &lt; len)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T &amp; min = (a[c] &lt; a[c+1])? a[c] : a[c+1];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (a[i] &gt; min)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Swap(a[i], min);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (a[i] &gt; a[c])<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Swap(a[i], a[c]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
}</p>
<p>template &lt;class T&gt;<br />
void Swap(T &amp; a, T &amp; b)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T t = a;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a = b;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b = t;<br />
}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 后面两种方法采用的是递归，容易理解，但时间复杂度较高，因为比前两种要慢上很多，<br />
所以不可能是O（nlogn），估计是O（n^2），但具体我也不会算，请。</p>
</div>
</div>
          <br/>
          <span style="color:red;">
            <a href="http://roki.javaeye.com/blog/104515#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 23 Jul 2007 22:48:37 +0800</pubDate>
        <link>http://roki.javaeye.com/blog/104515</link>
        <guid>http://roki.javaeye.com/blog/104515</guid>
      </item>
      <item>
        <title>lucene的MultiPhraseQuery</title>
        <author>roki</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://roki.javaeye.com">roki</a>&nbsp;
          链接：<a href="http://roki.javaeye.com/blog/104131" style="color:red;">http://roki.javaeye.com/blog/104131</a>&nbsp;
          发表时间: 2007年07月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><font face="Arial">在lucene的search包下面发现一个新的类 <font face="Arial">MultiPhraseQuery</font></font></p>
<p>大致作用，猜测可以实现以下功能：</p>
<p>本来，要实现 &quot;a (b|c|d) e&quot; 这样一个语意的Query ，我猜测需要用 &quot;a b e&quot;, &quot;a c e&quot; ,&quot;a d e&quot;三个PhraseQuery</p>
<p>来实现， 现在<font face="Arial">MultiPhraseQuery实现了这样一个方法&nbsp;<font face="Arial">&nbsp; </font></font></p>
<p><font face="Arial"><font face="Arial">public void add(Term[] terms, int position)</font></font></p>
<p>&nbsp;</p>
<p>也就是说，可以在原来的PhraseQuery中的任意位置添加更多的term</p>
<p>于是也就可以方便的实现&quot;a (b|c|d) e&quot;这样的查询语意了。&nbsp;</p>
<p>&nbsp;</p>
<p>总结： <font face="Arial">MultiPhraseQuery是个很不错的新功能</font></p>
          <br/>
          <span style="color:red;">
            <a href="http://roki.javaeye.com/blog/104131#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 22 Jul 2007 17:28:26 +0800</pubDate>
        <link>http://roki.javaeye.com/blog/104131</link>
        <guid>http://roki.javaeye.com/blog/104131</guid>
      </item>
      <item>
        <title>ImproveIndexingSpeed(加快索引速度) 转载</title>
        <author>roki</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://roki.javaeye.com">roki</a>&nbsp;
          链接：<a href="http://roki.javaeye.com/blog/103775" style="color:red;">http://roki.javaeye.com/blog/103775</a>&nbsp;
          发表时间: 2007年07月21日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><font face="Arial">原文地址 ：<font face="Arial"><a href="http://wiki.apache.org/lucene-java/ImproveIndexingSpeed">http://wiki.apache.org/lucene-java/ImproveIndexingSpeed</a>&nbsp;</font></font></p>
<p><font face="Arial"></font></p>
<p><font face="Arial"></font></p>
<p><br />
How to make indexing faster</p>
<p><font face="Arial">Here are some things to try to speed up the indexing speed of your Lucene application. Please see ImproveSearchingSpeed for how to speed up searching. </font></p>
<p><font face="Arial">Be sure you really need to speed things up. </font></p>
<p><font face="Arial">Many of the ideas here are simple to try, but others will necessarily add some complexity to your application. So be sure your indexing speed is indeed too slow and the slowness is indeed within Lucene. </font></p>
<p><font face="Arial">Make sure you are using the latest version of Lucene. </font></p>
<p><font face="Arial">Use a local filesystem. </font></p>
<p><font face="Arial">Remote filesystems are typically quite a bit slower for indexing. If your index needs to be on the remote fileysystem, consider building it first on the local filesystem and then copying it up to the remote filesystem. </font></p>
<p><font face="Arial">Get faster hardware, especially a faster IO system. </font></p>
<p><font face="Arial">Open a single writer and re-use it for the duration of your indexing session. </font></p>
<p><font face="Arial">Flush by RAM usage instead of document count. </font></p>
<p><font face="Arial">Call&nbsp; writer.ramSizeInBytes() after every added doc then call&nbsp; flush() when it's using too much RAM. This is especially good if you have small docs or highly variable doc sizes. You need to first set&nbsp; maxBufferedDocs large enough to prevent the writer from flushing based on document count. However, don't set it too large otherwise you may hit&nbsp; LUCENE-845. Somewhere around 2-3X your &quot;typical&quot; flush count should be OK. </font></p>
<p><font face="Arial">Use as much RAM as you can afford. </font></p>
<p><font face="Arial">More RAM before flushing means Lucene writes larger segments to begin with which means less merging later. Testing in&nbsp; LUCENE-843 found that around 48 MB is the sweet spot for that content set, but, your application could have a different sweet spot. </font></p>
<p><font face="Arial">Turn off compound file format. </font></p>
<p><font face="Arial">Call&nbsp; setUseCompoundFile(false). Building the compound file format takes time during indexing (7-33% in testing for&nbsp; LUCENE-888). However, note that doing this will greatly increase the number of file descriptors used by indexing and by searching, so you could run out of file descriptors if mergeFactor is also large. </font></p>
<p><font face="Arial">Re-use Document and Field instances </font></p>
<p><font face="Arial">As of Lucene 2.3 (not yet released) there are new setValue(...) methods that allow you to change the value of a Field. This allows you to re-use a single Field instance across many added documents, which can save substantial GC cost. </font></p>
<p><font face="Arial">It's best to create a single Document instance, then add multiple Field instances to it, but hold onto these Field instances and re-use them by changing their values for each added document. For example you might have an idField, bodyField, nameField, storedField1, etc. After the document is added, you then directly change the Field values (idField.setValue(...), etc), and then re-add your Document instance. </font></p>
<p><font face="Arial">Note that you cannot re-use a single Field instance within a Document, and, you should not change a Field's value until the Document containing that Field has been added to the index. See&nbsp; Field for details. </font></p>
<p><font face="Arial">Re-use a single Token instance in your analyzer </font></p>
<p><font face="Arial">Analyzers often create a new Token for each term in sequence that needs to be indexed from a Field. You can save substantial GC cost by re-using a single Token instance instead. </font></p>
<p><font face="Arial">Use the char[] API in Token instead of the String API to represent token Text </font></p>
<p><font face="Arial">As of Lucene 2.3 (not yet released), a Token can represent its text as a slice into a char array, which saves the GC cost of new'ing and then reclaiming String instances. By re-using a single Token instance and using the char[] API you can avoid new'ing any objects for each term. See&nbsp; Token for details. </font></p>
<p><font face="Arial">Use autoCommit=false when you open your IndexWriter </font></p>
<p><font face="Arial">In Lucene 2.3 (not yet released), there are substantial optimizations for Documents that use stored fields and term vectors, to save merging of these very large index files. You should see the best gains by using autoCommit=false for a single long-running session of IndexWriter. Note however that searchers will not see any of the changes flushed by this IndexWriter until it is closed; if that is important you should stick with autoCommit=true instead or periodically close and re-open the writer. </font></p>
<p><font face="Arial">Instead of indexing many small text fields, aggregate the text into a single &quot;contents&quot; field and index only that (you can still store the other fields). </font></p>
<p><font face="Arial">Increase&nbsp; mergeFactor, but not too much. </font></p>
<p><font face="Arial">Larger&nbsp; mergeFactors defers merging of segments until later, thus speeding up indexing because merging is a large part of indexing. However, this will slow down searching, and, you will run out of file descriptors if you make it too large. Values that are too large may even slow down indexing since merging more segments at once means much more seeking for the hard drives. </font></p>
<p><font face="Arial">Turn off any features you are not in fact using. </font></p>
<p><font face="Arial">If you are storing fields but not using them at query time, don't store them. Likewise for term vectors. If you are indexing many fields, turning off norms for those fields may help performance. </font></p>
<p><font face="Arial">Use a faster analyzer. </font></p>
<p><font face="Arial">Sometimes analysis of a document takes alot of time. For example, StandardAnalyzer is quite time consuming. If you can get by with a simpler analyzer, then try it. </font></p>
<p><font face="Arial">Speed up document construction. </font></p>
<p><font face="Arial">Often the process of retrieving a document from somewhere external (database, filesystem, crawled from a Web site, etc.) is very time consuming. </font></p>
<p><font face="Arial">Don't optimize unless you really need to (for faster searching). </font></p>
<p><font face="Arial">Use multiple threads with one IndexWriter. </font></p>
<p><font face="Arial">Modern hardware is highly concurrent (multi-core CPUs, multi-channel memory architectures, native command queuing in hard drives, etc.) so using more than one thread to add documents can give good gains overall. Even on older machines there is often still concurrency to be gained between IO and CPU. Test the number of threads to find the best performance point. </font></p>
<p><font face="Arial">Index into separate indices then merge. </font></p>
<p><font face="Arial">If you have a very large amount of content to index then you can break your content into N &quot;silos&quot;, index each silo on a separate machine, then use the writer.addIndexesNoOptimize to merge them all into one final index. </font></p>
<p><font face="Arial">Run a Java profiler. </font></p>
<p><font face="Arial">If all else fails, profile your application to figure out where the time is going. I've had success with a very simple profiler called&nbsp; JMP. There are many others. Often you will be pleasantly surprised to find some silly, unexpected method is taking far too much time.</font></p>
          <br/>
          <span style="color:red;">
            <a href="http://roki.javaeye.com/blog/103775#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 21 Jul 2007 16:26:40 +0800</pubDate>
        <link>http://roki.javaeye.com/blog/103775</link>
        <guid>http://roki.javaeye.com/blog/103775</guid>
      </item>
      <item>
        <title>郎咸平：人吃人的中国亟待和谐化 </title>
        <author>roki</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://roki.javaeye.com">roki</a>&nbsp;
          链接：<a href="http://roki.javaeye.com/blog/103322" style="color:red;">http://roki.javaeye.com/blog/103322</a>&nbsp;
          发表时间: 2007年07月20日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp; 中国国企改革蠹虫肆虐，教育改革成本由穷人负担，医疗改革基本失败，三农问题怵目惊心，弱势群体诉诸司法时又遭遇司法不公等等。中国处于最原始的人吃人的初期资本主义阶段，国内和谐化是当务之急。必须解决政府腐败低效问题，以严刑峻法实行法治。 </p>
<div twffan="done">我仔细研读中共十六届五中全会（今年十月）公报，认为五中全会是*本质转变的开始。二零零四年十一月三日前中共中央党校副校长郑必坚所提出的「国际和平化，国内和谐化，两岸和解化」的「三和理论」将主导*未来的执政理念。「国际和平化、两岸和解化」较易了解，我将另外为文讨论。我认为真正对中共执政基础产生冲击的将是「国内和谐化」问题，而这也是本文探讨的主题。</div>
<br />
<div twffan="done"><br />
今天的中国还是社会主义国家吗？我认为目前中国的社会，是处在一个以片面理解的经济发展观为唯一导向的、最原始的人吃人的初期资本主义阶段，而这个腐败阶段正是欧洲两百年前社会主义革命的温床。中国经历了那么多年的患难，打倒了西方帝国主义，赶走腐败的蒋介石政权，到头来片面强调经济发展的导向，又极为讽刺地把中国带回了两百年前以及类同蒋介石政权的腐败窘境。对外而言，这种单纯强调经济发展的必然结果是重蹈日本覆辙──出口激增、以邻为壑──带来了世界各国对中国的贸易与汇率的制裁。对内而言，各地政府放弃了本身职能，变成了个大商贩，招商引资、卖地筹资搞政绩工程，盲目发展经济，造成中国特有的低水平重复建设的大量浪费现象。</div>
<br />
<div twffan="done"><br />
表面上看，中国的GDP每年以百分之九的水平高速增长，但却是金玉其外，败絮其中。国家统计局局长李德水说，全国省级统计数据约有四成水分，县级高达八成，如果再扣除环境污染的成分，按照中科院的计算，大幅缩水的GDP还要再缩减七成八，而且还以每年两千亿美元的利润形式流向海外。更值得关注的是，中国这种资源贫穷国家的经济发展模式所造成的能源浪费是先进国家日本的九倍，欧洲的五倍和美国的二点五倍。其他问题如固定资产投资效益低落、四分之一城镇有着严重的政绩工程等更是不胜枚举。</div>
<br />
<div twffan="done"><br />
这些经济表面现象的恶化还不能说明问题的严重性。中国社会在以简单的经济发展为纲的改革开放下，整个土壤变坏了，变成了一个人吃人的社会才是最令人担忧的。举例而言，我在二零零四年提出「国退民进式的国企改革让少数国企老总暴富，而同样贡献的职工却被贱价买断工龄」这种社会不公现象时，主流经济学家的答覆令我感到震惊。他们认为民企比国企更有效率，所以应该进行改革，就算改革中出现一些腐败问题也是可以接受的。</div>
<br />
<br />
<div twffan="done">国企改革天怒人怨</div>
<br />
<div twffan="done"><br />
我在此必须郑重地申明，我谈的绝对不是国企或者民企谁有效率的问题，而是一个「大是大非」的问题。相当多的案例显示，国企收购者贱价买断工龄，将下岗职工推向社会，由失去了国企的政府和社会大众来负担，但收购者将国有资产据为己有或铲平工厂就地起高楼图利自己，但是改革成本却由全社会负担，这就是我所批评的天怒人怨的改革。这些收购者拿了不属于自己的东西，置下岗工人于死地，还能吃得饱、睡得好，甚至在台上口沫横飞地大谈自己「产权改革」的成功经验。我不懂他们怎么还能这样毫无羞耻心，甚至还睡得着觉。<br />
这个坏土壤所孕育出来的既得利益者处理「教改」的手法更是匪夷所思。虽然大学仍是公立大学，由政府补贴，但是政府却允许大学巧立名目、提高收费，让大学教职员中饱私囊，而其成本却由社会最底层的穷人负担，因为大学乱收费的结果阻断了农村子弟唯一脱贫致富的管道。但我们看不到一点既得利益者对弱势群体的关怀与同情，反而以市场化为手段，以个人利益为目的，透过教改，大事搜刮，中饱私囊。更有甚者，在这个社会一切往「钱」看时，北大和清华的教职员利用前人苦心经营的校誉，搞了个北大系和清华系的企业集团，在股市上呼风唤雨，操纵股价，利用北大清华的清誉坑害股民，图利自己。</div>
<br />
<div twffan="done"><br />
类似的现象在医改问题上也是让人扼腕痛惜。所谓的「市场化」的医改措施，让穷途末路的病人挂急诊病号竟然要先交付保证金，否则放在走廊上等死，难道我们的医院连一点最起码的人性关怀都没有了吗？医改的结果，不止穷人看不起病，甚至连一般人也视去医院为畏途。</div>
<br />
<div twffan="done"><br />
此外，腐败的地方政府官员和地产开发商合谋，利用黑道对付手无寸铁的拆迁户的手法更是令人发指。为了逼迫拆迁户接受不公平的补偿，不但利用黑道直接殴打当事人，甚至威胁当事人的子女。在腐败的司法制度下，拆迁户投诉无门，甚至连主动协助拆迁户打官司的律师，竟然也被利益团体利用腐败的司法力量将其入狱，置于死地。中国大地什么时候竟然变成了一个人吃人的社会？</div>
<br />
<div twffan="done"><br />
当老百姓投诉无门而转向司法体系寻求正义时，老百姓得到了什么待遇呢？基本上是中午吃原告晚上吃被告的待遇。在很多时候，司法机构包括法院和公安不是故弄玄虚的不受理，就是和利益团体勾结，侵害百姓利益。</div>
<br />
<div twffan="done"><br />
当老百姓的权益受损，因投诉无门而上街游行抗议冲击地方政府的时候，地方政府是什么处理态度呢？军警围剿甚而对外宣布是国外恶势力操纵，民众因而被捕下狱。你竟然看不到一点地方父母官解决百姓困难的情怀，那种人吃人的凶狠劲让人感到寒心。</div>
<br />
<br />
<div twffan="done">行政暴力侵吞民有资产</div>
<br />
<div twffan="done"><br />
更有甚者，目前中国这种人吃人、侵吞弱势群体的水平，还上升到了行政暴力侵吞民有资产、司法暴力审判、行政暴力合法的超高水平。最着名的例子当推港商嘉利来的股权被侵吞案。一九九五年，香港嘉利来与北京市二商集团、北京恒业房地产公司组建公司，共同开发世贸中心项目。二零零零年时，二商集团个别项目负责人垂涎于嘉利来的股权，于是勾结社会恶商，买通北京市工商局以及北京市外经贸委的个别公务人员，组成合谋团夥，侵吞嘉利来股权。</div>
<br />
<div twffan="done"><br />
二零零一年年底，嘉利来提起行政覆议，商务部其后撤销了北京市商务局的行政批覆，但北京商务局拒不执行。其后经国务院领导批示，国务院法制办查核后，国务院办公厅零三年七月责令商务部等单位督促北京市商务局立即执行中央政府行政覆议决定。八月十四日商务部也明确再次要求北京市商务局立即执行。为遮掩商务局违法行政的错误，北京二商集团依据伪造的复印件合同，在北京市二中院起诉商务部，北京市二中院竟然判中央政府败诉。北京市政府内部的腐败分子这种操纵司法、暴力判定行政暴力合法的判决将尽失民心，而严重动摇国本。</div>
<br />
<div twffan="done"><br />
这些年来农村的衰败也不遑多让。三农问题的严重，让人感到怵目惊心。农村破败的基本原因，还是因为农产品的附加价值远低于工业品的附加价值，因此经济越高速发展，农村就相对地越破败，而其必然结果就是农村资金大量流入城市追求高附加价值。但是农村资金缺乏的结果，是与各种权力高度相关的地方干部亲属和非农经营业主，透过高利贷进一步剥削穷困不堪的农民。</div>
<br />
<div twffan="done"><br />
根据中国人民大学温铁军教授的调查，类似于国民党时期的高利贷在很多农村地区就重新泛滥起来，而且情况是极其严重的，与国民党时期的乱象相比，毫不逊色。举例而言，月息在一点五至二分之间的民间高利率借贷占了百分之二十点五；月息二分以上的高利贷约占百分之四十三。其中月息二分至四分的高利贷占了百分之十八点二，月息超过四分的恶性高利贷占近百分之二十五。而且目前农村的农民借款中只有百分之十一的借贷是用于农业再生产，其他百分之八十九的借款都是消费性的借款，而不会投入生产的循环使用，因此就很难想像百分之八十九的借款者用什么来还钱。此外，高利借贷与买卖婚姻、赌博等现象相关，诱发了一系列的民间纠纷，有的债主请黑道讨债，有的发生斗殴致伤，还有的与黑恶势力结合，殴打无力还贷的农民、强行拉牛抓猪，影响了基层的政治稳定。</div>
<br />
<div twffan="done"><br />
其他少数既得利益者剥削社会大多数人的例子简直不胜枚举，例如上市公司剥削股民、民企老板克扣民工工资等等现象，我们见得少了吗？</div>
<br />
<div twffan="done"><br />
这种人吃人的国家还配称作社会主义国家吗？那么到底是什么因素把中国这个古老传统的国家带到了这个绝境呢？最主要的原因还是这块土壤出了问题，我们这块土壤的坏是中华民族五千年来所仅见。</div>
<br />
<br />
<div twffan="done">社会之坏五千年仅见</div>
<br />
<div twffan="done"><br />
我分析有三个原因使得我们的土壤变坏了。第一，中国这一代人是五千年来的唯一不敬鬼神的一代，古人「抬头三尺有神明」、做坏事下地狱的简单封建理念，到了这一代荡然无存。我虽不主张迷信，但是当一个民族到了一切向钱看而无所畏惧的时候，人吃人的社会就成形了。</div>
<br />
<div twffan="done"><br />
此外，土地改革将地主阶层一扫而空，我绝不否认恶地主的存在，但是地主阶层，也就是以前的乡绅，在中国文化中是中华礼教的维护者。举例而言，以往封建时期的修桥、铺路、建学校、建庙宇都是谁做的呢？都是地主阶级。例如，以往被*所批判的四川地主刘文采，最后也被*实事求是的态度翻案了，原来他是个大善人，他耗尽家产建立了闻名遐迩的文采中学。如此例子不胜枚举，山西几个大地主基本上都是这种类型，包括乔家、王家，到了分土地打土豪的时候，农民不忍心占据地主庄园，所以才将这些古迹保存了下来。可是地主阶级不分好坏地全部清除，其结果却使得广大农民不知何为礼教。<br />
最后，中国从来就是个没有法治的国家，一直到现在依然如此，地方干部和恶霸在历史上一向为所欲为的传统到了新中国没有丝毫的改变。这样一个不敬鬼神、没有礼教束缚、无法治约束的一代就是人吃人的一代人。今天以简单经济发展为目标的执政哲学使得中国这一代人更往「钱」看，但是不敬鬼神就无所畏惧，不知礼教就寡廉鲜耻，无法治约束就贪赃枉法，这不就是今天中国人的社会吗？</div>
<br />
<div twffan="done"><br />
就是因为这些改革的少数既得利益者侵吞大多数弱势群体的现象太过严重，因此五中全会「国内和谐化」的理念就特别地具有时代意义。从我前面所分析的问题看，目前在这片坏土壤上以简单经济发展为唯一考量的发展观，已经造成了社会的极度不和谐，而国内和谐化将是经济进一步发展的充分而且必要条件。经济发展停滞的菲律宾、泰国、印尼、马来西亚和民进党执政下的台湾就充分说明，一个社会绝无可能在社会极端不和谐的情况下发展经济，而且不和谐的社会将使得政府的执政基础迅速沦丧，造成社会进一步的动汤。这些国家和地区的政府的不稳定、暴动的频仍以及经济的停滞发展，不正说明社会和谐的重要吗？在社会不和谐的危机之下，学者专家却仍然高喊着以经济发展为唯一的目标的理念将会如同菲律宾等国一样，使得中国经济体系迅速瓦解。</div>
<br />
<br />
<div twffan="done">以法治挽回政府信誉</div>
<br />
<div twffan="done"><br />
宗教信仰是靠历史的传承，礼教的建立要靠文化的积累，绝对无法而且也不需要靠行政命令建立这套系统。透过长期的法治化建设形成法治化的游戏规则，以规范每个个体的行为应当是政府长期努力的目标。但在短期之下，政府必须利用严刑峻法解决老百姓痛恨的国资流失、以强欺弱、治安恶化、行政司法暴力、政府腐败和三农等等问题。可是严刑峻法的推动脱离不了各级政府在中央政府的领导下的执行。但很不幸的是，由香港嘉利来的案例可以看出地方政府包括司法机构的嚣张气焰，不但无视中央政府的存在，而且其作为已经开始动摇国本。有这样的地方政府，我们还需要敌人吗？再加上改革开放后官商勾结的既得利益者，使得国内和谐化的改革越发艰难。在此我呼吁中央政府进一步加强执政能力，以严刑峻法贯彻以民为本的思维，整肃吏治，因为没有一个廉洁有效率的政府就很难彻底解决老百姓痛恨的问题，也无法推动以民为本的法治化建设。</div>
<br />
<div twffan="done"><br />
其具体做法应重新定位各级地方政府的行政职能，首先我们要确立一个理念，何谓正确的政府职能。各级政府的职能不应以经济建设为唯一的目标，更不是像目前各级政府一样的大商贩的身份。协调发展才是科学发展观的根本要求，只有解决好人民最不满意的问题，才是各级政府的首要施政目标。但要解决这些问题，首先就必须要有一个如同香港和新加坡一样的廉洁和高效的政府。中国各级政府的全面腐败与低效率曾经引发了大面积的体制改革的讨论。一些食洋不化的专家学者提出西方式的民意监督包括民主（议会）监督和舆论监督是体制改革的唯一良方。但是，西方式的民主和民意监督能否到位还遥遥无期，而以简单经济发展为纲的错误思维已经造成了社会的严重动汤和不和谐。</div>
<br />
<div twffan="done"><br />
民主和民意监督根本解决不了中国各级政府的腐败以及低效率。我认为这一切应该归咎于我们对西方资本主义的理解太过肤浅所致。举例而言，一九九七年之前的港英政府不但清廉而且高效率。但是当时的香港有民主吗？有民意监督吗？有舆论监督吗？都没有。五六十年代香港本地媒体胆敢批评港英政府，政治部的官员就上门抓人以「不受欢迎的外国人」递解出境。这种威权体制下的港英政府竟然是最廉洁与最高效率的政府。清廉的新加坡政府也和香港类似。可是，亚洲其他地区包括菲律宾、印尼、马来西亚、泰国、台湾等等，在法治不健全的环境下引进了民主与舆论监督，但是政府的腐败和低效依然严重而不能解决。而这也是我为何主张单靠民主与舆论监督不能解决腐败与低效的主因，因为民主与舆论监督必须在法治化的框架下才能发挥作用，而这也是为何民主与舆论监督在法治化的西方国家有效而在亚洲大部分国家无效的主因。</div>
<br />
<div twffan="done"><br />
以香港和新加坡的案例而言，政府的廉洁和高效来自于英国人建立起来的严格的流程式管理。那么流程式的管理有多重要呢？以土地协议转让为例，如果规定要竞价拍卖，那么竞价拍卖本身就是流程化的管理，而不再由领导拍板决定。以往领导有很充分的空间去讨价还价，由于没有一个价格机制在，因此需求量是无限大的，太多人需要土地。而竞价拍卖就是一个规范的流程，减少了官员腐败的空间，而且由于价格的调整使得需求减少。如香港批地就是流程化的公开竞价，港府官员没有贪污的空间。而如何补偿拆迁户都有一整套的程序，双方都没有议价的空间，因此大幅减少司法暴力和黑道威胁。</div>
<br />
<div twffan="done"><br />
最后我想提出，五中全会的「三和理论」将是继「三个代表」之后的重要里程碑，也和「三个代表」一样肩负着不同时代的不同使命。毫无疑问，「国际和平化」及「两岸和解化」的推动，与「国内和谐化」的日益恶化，更显现了北京推行「三和理论」的迫切性，而解决「国内和谐化」是重中之重。在国内法治化的建设还未完成的前提下，我们应以严格流程化的管理解决各级政府的腐败和低效的现实情况，然后以严刑峻法解决人民最不满意的问题，才是各级政府的首要施政目标。</div>
          <br/>
          <span style="color:red;">
            <a href="http://roki.javaeye.com/blog/103322#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 20 Jul 2007 22:38:22 +0800</pubDate>
        <link>http://roki.javaeye.com/blog/103322</link>
        <guid>http://roki.javaeye.com/blog/103322</guid>
      </item>
      <item>
        <title>关于BDB-Directory 的问答</title>
        <author>roki</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://roki.javaeye.com">roki</a>&nbsp;
          链接：<a href="http://roki.javaeye.com/blog/102117" style="color:red;">http://roki.javaeye.com/blog/102117</a>&nbsp;
          发表时间: 2007年07月17日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>问：</p>
<p>Is it possible to turn off directory locking with BDB?&nbsp; How is the performance <br />
compared to regular FSDirectory for queries?<br />
</p>
<p>答：</p>
<p>If you're thinking of using Berkeley DB as a the store behind the Lucene index <br />
via the DbDirectory Directory implementation, here are a few things to keep in <br />
mind:<br />
<br />
&nbsp;&nbsp; - always setUseCompoundFile(false)<br />
&nbsp;&nbsp;&nbsp;&nbsp; don't use compound lucene index files on top of Berkeley DB:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; . there is a bug that prevents this from working correctly<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; . it makes no sense anyway since it duplicates what DbDirectory is<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; already doing (all index files are stored in the same Berkeley DB file)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; . it slows things down<br />
<br />
&nbsp;&nbsp; - if you are using a transaction around all the index updates, you may want<br />
&nbsp;&nbsp;&nbsp;&nbsp; to consider doing all the index updates in a RAMDirectory first and then<br />
&nbsp;&nbsp;&nbsp;&nbsp; adding the RAMDirectory wholesale to the DbDirectory in that transaction.<br />
&nbsp;&nbsp;&nbsp;&nbsp; This makes indexing considerably faster (3 times for me) and does a LOT<br />
&nbsp;&nbsp;&nbsp;&nbsp; less thrashing around in Berkeley DB which can lead to a large number of<br />
&nbsp;&nbsp;&nbsp;&nbsp; transactional log files rapidly filling up your hard drive.<br />
<br />
I'm not really sure if and how index merging works. For my use, having no <br />
merging is good enough since I never update existing documents, but always <br />
instead add a new version of them. The concept of version is tied to my <br />
application and each transaction corresponds to a new version.<br />
</p>
          <br/>
          <span style="color:red;">
            <a href="http://roki.javaeye.com/blog/102117#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 17 Jul 2007 19:52:19 +0800</pubDate>
        <link>http://roki.javaeye.com/blog/102117</link>
        <guid>http://roki.javaeye.com/blog/102117</guid>
      </item>
      <item>
        <title>一个中小型商业搜索引擎在线服务子系统的基本架构</title>
        <author>roki</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://roki.javaeye.com">roki</a>&nbsp;
          链接：<a href="http://roki.javaeye.com/blog/99888" style="color:red;">http://roki.javaeye.com/blog/99888</a>&nbsp;
          发表时间: 2007年07月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><strong>4层架构</strong></p>
<p>&nbsp;</p>
<p><strong>1 客户端</strong></p>
<p>负责接收用户发出的搜索请求， 转发到后端 &ldquo;分发服务器&rdquo;</p>
<p><strong>2 分发服务器</strong></p>
<p>分发服务器 接收到客户端发出的搜索请求后，根据不同的客户端类型（不同来源的搜索请求），把请求转发到</p>
<p>不同的&ldquo;业务总控服务器&rdquo;。</p>
<p>&nbsp;</p>
<p><strong>3业务总控服务器</strong></p>
<p>业务总控服务器连接到各个具体业务的服务器， 接受到分发服务器发过来的搜索请求之后， 经过业务总线</p>
<p>（缓存，搜索，相关搜索，定制搜索，竞价排名等等业务，组成业务流水线），组装成搜索结果，返回给分发服务器，</p>
<p>由分发服务器把搜索结果返回给客户端，呈现给用户。</p>
<p>&nbsp;</p>
<p><strong>4.业务服务器</strong></p>
<p>从业务总控服务器收到搜索请求后， 由自身或者结合其他辅助服务器完成业务，将结果返回给业务总控服务器。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://roki.javaeye.com/blog/99888#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 10 Jul 2007 22:50:19 +0800</pubDate>
        <link>http://roki.javaeye.com/blog/99888</link>
        <guid>http://roki.javaeye.com/blog/99888</guid>
      </item>
  </channel>
</rss>