庄周梦蝶

生活、程序、未来
   :: 首页 ::  ::  :: 聚合  :: 管理

    发现gigix新的blog是支持atom的,也让这个小工具支持下atom,去rubyforge找了圈,有个叫atom的lib简单易用,就选他了。
    首先,gem install atom,安装一下
    其次,稍微修改下代码:
def blog_info(url)
  str
=open(url).read
  feed 
= RSS::Parser.parse(str, false)
  
unless feed
    feed
=Atom::Feed.new(str)
    blog
=Blog.new(feed.title,url,feed.entries)
  
else
    blog
=Blog.new(feed.channel.title,url,feed.items)
  end
end
先尝试用RSS模块去读,失败的话就用Atom模块,运行下,问题出来了,这个atom lib的entries数组中是一个一个的Atom:Entry对象,而这个Entry类并没有我在模板文件中定义的link,取而代之的是一个links数组,links数组中的Link对象href属性才是我想要的,那么,修改模板文件?或者修改atom lib的源码?No,No,都不用,ruby天然的open class特性让你随心所欲,我们打开Atom:Entry类,给它添加个link方法就OK:
class Atom::Entry
  def 
link
    links[
0].href
  end
end
这样一来,模板文件也不用改了,更不用去修改atom lib的源码,实在是够爽,现在完整的rss-reader是这样:
require 'rss/2.0'
require 'open-uri'
require 'erb'
require 'atom'
# author dennis
# email killme2008@gmail.com

class Atom::Entry
  def 
link
    links[
0].href
  end
end
class Blog
  attr_accessor
:title,:url,:items
  def initialize(title
,url,items=[])
    
@title=title
    
@url=url
    
@items=items
  end
end
def blog_info(url)
  str
=open(url).read
  feed 
= RSS::Parser.parse(str, false)
  
unless feed
    feed
=Atom::Feed.new(str)
    blog
=Blog.new(feed.title,url,feed.entries)
  
else
    blog
=Blog.new(feed.channel.title,url,feed.items)
  end
end
def rss_read
  urls
=['http://www.blogjava.net/canonical/rss','http://dreamhead.blogbus.com/index.rdf',
        
'http://michael.nona.name/rss','http://blog.csdn.net/mozilla/Rss.aspx','http://blog.csdn.net/g9yuayon/Rss.aspx']
  urls
.collect do |blog_url|
    blog_info(blog_url)
  end  
end
if $0==__FILE__
  blogs
=rss_read()
  
#读取模板文件
  template=IO.read(File.dirname(__FILE__)+"/blogs.html")
  message
=ERB.new(template)
  
#输出结果文件
  File.open("today.html","w+"){|file| file.puts message.result}
end


posted @ 2007-07-11 16:50 dennis 阅读(467) | 评论 (0)编辑 收藏

    一大早写这篇blog是心有所想,最近一段时间,我关注或者说读了太多杂七杂八的技术书籍,从读完第二章的SICP到《Concurrent Programming in Erlang》的上半部分,从《鸟哥的linux私房菜》到《EveryDay Scripting With Ruby》,从《深入java虚拟机》的重读到vmspec,再到浅尝辄止的wicket,javafx等技术。我读书的特点就是在读一本书的过程中,如果引申到其他我不了解的领域,我就想去读一下这个领域的书,比如我在读sicp的时候,就想再学一门函数式语言,于是我选择了Erlang。在读《鸟哥linux私房菜》的时候,我对shell编程产生兴趣,就去买了本《Unix/linux编程实践教程》准备读读。我读书的范围看似很广,其实也还是局限在感兴趣的领域:linux、java、ruby以及拓展了我思维的函数式语言等方面。广度是有了,可脑中充斥了太多杂七杂八的东西,我还不能将它们完全理顺,我还无法将这些语言清晰地进行对比和联系,我还没办法洞察或者说了解各种技术间的相似和不同,或者说它们的内部结构。比如在读了SICP第二章后以及牛人T1的《失踪的链环》,当去年我第一次读《失踪的链环》时,确实是云里雾里、稀里糊涂,读了SICP和学习了Erlang之后才算是有点理解,隐隐约约领悟到了什么,可又不是很清晰,再深入的思考又非我所能,真是太郁闷了,想想这样的东西,还是要水到渠成,就像我不知第几遍重读《深入java虚拟机》才感觉有所掌握,功力未到,急也急不来呀!说了这么多,也是要给自己打气,昨天晚上第一次看到《赢在中国》这个节目,马云的一句话让我印象深刻:一时的激情是赚不了钱,只有持续不断的激情才能赚钱。当然还有这句,哈哈:赚钱不是目的,赚钱只是结果。

posted @ 2007-07-11 08:54 dennis 阅读(574) | 评论 (3)编辑 收藏

    阅读专家和牛人的blog已经是我学习的一种主要方法之一,我每天的必做的就是关注下dreamhead、gigix、江南白衣、robbin、李锟等牛人的blog是不是有什么新文章。不过我非常讨厌安装商业公司的rss阅读器,我害怕他们是流氓软件!而且很多阅读器的文章格式与原文有较大差异从而导致重要信息的丢失,我还是喜欢用firefox畅游网络,这导致我不得不一次一次地在各个blog间跳转,打开n个网页查找我关注的信息,一次两次也就罢了,天天这样实在是太麻烦了,那么,有没有什么工具来简化我的工作,他能自动每天把我关注的所有blog的文章放在一个页面里,我每天早上需要做的只是运行下这个工具,然后打开生成的网页就可以看到牛人们的blog。甚至,我可以在windows下做个计划任务或者linux下使用cron让这个工具每天在夜深人静的时候自动运行下,那我每天早上就可以看到牛人们新鲜出炉的好文章了。这个工具生成的网页应该类似下面这样:

然后,当我点击某个blog标题的时候会自动展开文章列表:

   
    点击文章标题就会跳转到相应的文章网页。OK,想好了需求,怎么做?写这样的东西当然是脚本语言最快了,我们用ruby来完成这个工具脚本。稍微思考下就可以知道大概的思路,应该是通过某个方法连接到各个blog站点,然后抓取我们需要的信息集中显示在这个页面里。也许你还想到要用正则表达式去解析网页内容等等,可想象一下这个工作量将多大,再说现在的blog都有替换模板功能,如果哪天换了模板,正则匹配就失效了,还得重新再来,这也太麻烦了。幸好,blog都有提供RSS啊,我们根本没必要那么麻烦,直接读RSS不就可以了?那么ruby有没有提供读rss的API?还是要我们自己去解析xml?这件事问下《ruby cookbook》就OK。ruby有提供一个解析rss的库,支持rss0.9,1.0和2.0标准,权衡之下,我使用了rss2.0,后来发现也可以正常读取rss1.0的blog。开始写我们的脚本,先建立一个Blog类用于存放信息:
class Blog
  attr_accessor
:title,:url,:items
  def initialize(title
,url,items=[])
    
@title=title
    
@url=url
    
@items=items
  end
end
    title、url和items分别是blog的标题、地址和文章列表,我们将文章存储在一个数组里,默认是空的。然后再定义一个解析blog信息的方法blog_info,根据地址连接rss源并返回一个Blog对象:
def blog_info(url)
  feed 
= RSS::Parser.parse(open(url).read, false) 
  blog
=Blog.new(feed.channel.title,url,feed.items)
end
    注意,ruby方法默认返回的最后一行的运行结果,这里就是new的Blog对象,我们通过open-uri库的open方法连接地址并读取内容,然后使用RSS模块的Parser类解析信息,最后将这些信息组织成一个Blog对象并返回。我同时关注好几个blog,那么将这些blog的rss地址放在一个数组里,然后遍历数组分别调用blog_info得到Blog对象,最后需要考虑的就是怎么将Blog对象显示在网页里。
def rss_read
  urls
=['http://www.blogjava.net/canonical/rss','http://dreamhead.blogbus.com/index.rdf',
        
'http://michael.nona.name/rss','http://blog.csdn.net/mozilla/Rss.aspx','http://blog.csdn.net/g9yuayon/Rss.aspx']
  urls.collect do |blog_url|
    blogs
<<blog_info(blog_url)
  end  
end
    rss_read方法最后返回Blog对象组成的数组,剩下的任务就是将这个数组里信息显示在生成的网页里。这个问题很类似生成静态html文件的需求,那么ruby是否有类似freemark的模板语言?答案当然是yes,ruby on rails使用了ERb将ruby代码嵌入模板当中,我们当然也可以这样做。ERb类似jsp的语法,<%=name%>就是输出变量name,<% %>中的代码就是一般的ruby代码,因此,首先定义我们的模板文件blogs.html

<html>
    
<head>
        
<title>simple rss reader</title>
            
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        
<style rel="stylesheet" type="text/css" media="all" />body {
    margin
: 80px;
    text
-align:left;
    font
:normal 12px Verdana, Arial;
    background
:#FFF
  }
  a
:link,a:visited{
    text
-decoration:none;
    color
:#333333;
  }
  a
:hover{
    text
-decoration:none;
    color
:#FF6600
  }
  
.dotline {
    BORDER
-BOTTOM-STYLE: dotted; BORDER-LEFT-STYLE: dotted; BORDER-RIGHT-STYLE: dotted; BORDER-TOP-STYLE: dotted
  }
        
</style>
  
<script language="javascript">
           function change(name){
              var div
=eval("document.all."+name);
              div
.style.display=="none"?(div.style.display=""):(div.style.display="none");
           }
  
</script>
  
</head>
        
<body>
            
<p align="center"><strong>您关注的blog列表:</strong></p>
                    
<% num=1 %>
                    
<% for blog in blogs %>
                      
<% begin %>
                        
<div>
                            
<a href="#" onclick="change('blog<%=num%>');"><%= blog.title %></a>
                            
<div id="blog<%=num%>" style="display:none">
                                
<% for item in blog.items %>
                                    
&nbsp;&nbsp;&nbsp;&nbsp;
                                    
<a href="<%=item.link%>" target="_blank"><%= item.title %></a>
                                    
<br>
                                
<% end %>
                            
</div>
                        
</div>
                        
<hr class=dotline color=#000000 size=1>
                        <% num=num+1 %>
                      
<% 
                      rescue StandardError
=>e
                         puts 
"错误信息"+e
                      end 
%>  
                  
<% end %>
        
</body>
</html>
    遍历blogs数组,然后将blog的title输出到网页,接着就是blog.items文章列表循环输出,将文章列表放在一个div层中以便隐藏,javascript函数change用于隐藏或者显示文章列表。模板文件有了,现在需要的是读取模板文件并render,输出到结果文件:
  blogs=rss_read()
  
#读取模板文件
  template=IO.read(File.dirname(__FILE__)+"/blogs.html")
  message
=ERB.new(template)
  
#输出结果文件
  File.open("today.html","w+"){|file| file.puts message.result}
最后,我们生成的是一个today.html文件,这个网页就是我们就是我们在文章开头处展示的。message.result就是经过render后,将blogs变量传入模板文件后得到结果,我们将它写入today.html。
    完整的rss-reader.rb如下:
require 'rss/2.0'
require 'open-uri'
require 'erb'
# author dennis
# email killme2008@gmail.com


class Blog
  attr_accessor
:title,:url,:items
  def initialize(title
,url,items=[])
    
@title=title
    
@url=url
    
@items=items
  end
end
def blog_info(url)
  feed 
= RSS::Parser.parse(open(url).read, false) 
  blog
=Blog.new(feed.channel.title,url,feed.items)
end
def rss_read
  urls
=['http://www.blogjava.net/canonical/rss','http://dreamhead.blogbus.com/index.rdf',
        
'http://michael.nona.name/rss','http://blog.csdn.net/mozilla/Rss.aspx','http://blog.csdn.net/g9yuayon/Rss.aspx']
  blogs
=[]
  urls
.each do |blog_url|
    blogs
<<blog_info(blog_url)
  end  
  blogs
end
if $0==__FILE__
  blogs
=rss_read()
  
#读取模板文件
  template=IO.read(File.dirname(__FILE__)+"/blogs.html")
  message
=ERB.new(template)
  
#输出结果文件
  File.open("today.html","w+"){|file| file.puts message.result}
end
    使用小窍门:最好将today.html加入FireFox的标签或者IE的收藏夹,windows下建立一个计划任务每天凌晨自动运行rss-reader.rb生成toady.html(linux可以使用cron),那么你每天早上打开浏览器就可以看到牛人们的新鲜文章了^_^

posted @ 2007-07-09 15:14 dennis 阅读(1412) | 评论 (3)编辑 收藏

    用了这么久ruby,知道String对象可以通过[]操作得到字符或者子字符串,比如:
>"abc"[0]
97
>"abc"[0,2]
"ab"

97就是字符a的ASCII码了,却不知道[]操作同样可以接受正则表达式,返回匹配正则的那部分字符串,比如:
>"has 5 and 3" [/\d+/]
5
>"hello there"[/(..)e/]
the

ruby的API设计充分体现了马教主所说的人本接口

posted @ 2007-07-06 19:39 dennis 阅读(401) | 评论 (0)编辑 收藏

一、subversion最新版本已经到1.4.4,我安装的还是老版本,新版本也可以,BerkeleyDB和Apache的版本要与subversion要求的一致,安装所需文件及下载地址:
1) Subversion 1.2.3
http://subversion.tigris.org/downloads/subversion-1.2.3.tar.gz

2)Berkeley DB 4.4.20
http://downloads.sleepycat.com/db-4.4.20.tar.gz

3)Apache 2.0.54
http://apache.justdn.org/httpd/httpd-2.0.54.tar.gz

二、以root用户登陆系统。

安装Apache
#tar -zxvf httpd-2.0.54.tar.gz
#cd httpd-2.0.54
#./configure --enable-dav --enable-so --enable-maintainer-mode
#make
#make install

安装Berkeley DB
#tar -zxvf db-4.4.20.NC.tar.gz
#cd db-4.4.20.NC/build_unix/
#../dist/configure --prefix=/usr/local/bdb
#make
#make install

安装Subversion
#tar -zxvf subversion-1.2.3.tar.gz
#cd subversion-1.2.3
#./configure --with-berkeley-db=/usr/local/bdb --with-apxs=/usr/local/apache2/bin/apxs
#make
#make install
/* 你可以用以下命令检验subversion是否安装成功 */
#svnadmin --version

三、新建一用户组svn,并建立一用户svnroot,用于管理svn的运行和维护
groupadd svn
useradd -G svn -m "the svn mananger" svnroot
passwd svnroot  #设置svn密码

四、使用svnroot登录,执行下列操作
# mkdir /home/svnroot/repository

//创建仓库test
svnadmin create /home/svnroot/repository/test

//导入项目到仓库中
svn import /home/yourproject file:///home/svnroot/repository/test –m "initial import"
//改变权限,仅限svnroot拥有读、写、执行权利
chmod 700 /home/svnroot/repository

五、root用户登录,设置Apache
//编辑httpd.conf
# vi /usr/local/apache2/conf/httpd.conf
   找到下面两行,如果没有,则添加:
   LoadModule dav_svn_module modules/mod_dav_svn.so
   LoadModule authz_svn_module modules/mod_authz_svn.so
   接着上面再添加下面这段配置:
 <Location /svn/>
   DAV svn
   SVNParentPath 
/home/svnroot/repository/
   AuthzSVNAccessFile 
/home/svnroot/repository/authz.conf
   AuthType Basic
   AuthName 
"Subversion.svn"
   AuthUserFile 
/home/svnroot/repository/authfile
   Require valid
-user
   
</Location>

这段信息设置了/svn/目录需要认证才能访问,用户信息放在authfile,授权信息在authz.conf文件里。

六、权限管理,使用svnroot登录
1)增加用户,通过下列命令第一次增加时建立authfile文件,比如添加了一个用户dennis
htpasswd -c /home/svnroot/repository/authfile dennis
会提示你输入密码,以后再添加就不用-c选项了

2)权限分配,建立并编辑authz.conf
# vi /home/svnroot/repository/authz.conf
[groups]  #这个表示群组设置
admin
=svnroot  #svnroot是admin组
[test:
/]  #这表示,仓库test的根目录下的访问权限
dennis
=rw #test仓库dennis用户具有读和写权限
[test2:
/] #假设有test2仓库,它的访问权限
dennis
=r  #test2仓库dennis有读权限
[
/] #这个表示在所有仓库的根目录下
* = r     #这个表示对所有的用户都具有读权限
@admin
=rw #admin组有读和写权限,比如svnroot


设置完成后,
重启apache
/usr/local/apache2/bin/apachectl restart
启动svn服务
#svnserve -d

通过浏览器访问http://localhost/svn/test/,输入用户名密码,一切OK!

我只在我的windows机器上安装了subversion管理我的文档,这次在redhat9上的安装还算顺利,参考了下列文章:
Linux 上安装 Subversion
《在Redhat9 Linux下安装,配置Subversion 1.3.1》
 

posted @ 2007-07-06 13:47 dennis 阅读(1220) | 评论 (0)编辑 收藏

    shell编程,类似dos下的批处理文件,也有很大不同,shell更接近一门编程语言。最近迷上了这玩意,入门很容易,再深入就有点难了,写了几个简单的script处理日常命令,用着蛮爽,大大提高了我继续深入学习linux的积极性,待复习了C语言基础,准备读读《UNIX/LINUX编程实践教程》。前天在emule下了《EveryDay Scripting With Ruby》,这本书在amazon评价很高,昨天一口气读了6章,非常不错。这本书适合ruby初学者,有一定ruby使用经验的也能有不少收获,书中介绍了4个常用的ruby编写的工具脚本,循序渐进、一步一步引你走入ruby的世界,有趣并实用;更可贵的是,这本书从第2个Project开始就以TDD的方式开发,让你充分体验TDD和Ruby结合带来的快感,强烈推荐准备开始学ruby的看看这本书。读这本书主要是想更深入地将ruby使用在我的日常工作中,熟识部分飞快翻过,总共也才250多页,花不了一两天功夫。这本书的源码从网站上下不了,封了来自中国大陆的IP,我将源码传上,有兴趣的看看。

《EveryDay Scripting With Ruby》书中源码

posted @ 2007-07-05 15:06 dennis 阅读(2950) | 评论 (1)编辑 收藏

 习题2.2没有全部做,我读书的速度远远超过做习题的进度,没办法,时间有限,晚上的时间基本用来看书了,习题也都是在工作间隙做的,慢慢来了,前两章读完再总结下。回到2.3节,这一节在前几节介绍数值型符号数据的基础上引入了符号数据,将任意符号作为数据的能力非常有趣,并给出了一个符号求导的例子,实在是太漂亮了。

习题2.53,直接看结果:
> (list '''c)
(a b c)
> (list (list 'george))
((george))
> (cdr '((x1 x2) (y1 y2)))
((y1 y2))
> (cadr '((x1 x2) (y1 y2)))
(y1 y2)
> (pair? (car '(a short list)))
#f
> (memq? 'red '((red shoes) (blue socks)))
#f
> (memq? 'red '(red shoes blue socks))
(red shoes blue socks)

习题2.54,equal?过程的定义,递归定义,很容易
(define (equal? a b)
  (cond ((
and (not (pair? a)) (not (pair? b)) (eq? a b)) #t)
        ((and (pair? a) (pair? b))
         (
and (equal? (car a) (car b)) (equal? (cdr a) (cdr b))))
        (
else
          (display 
"a and b are not equal"))))
注意,在DrScheme实现中,eq?可以用于比较数值,比如(eq? 1 1)也是返回真

习题2.55,表达式(car ''abracadabra)其实就是
(car (quote (quote abracadabra))),也就是(car '(quote abracadabra)),显然将返回quote

习题2.56,求幂表达式的导数,学着书中的代码写,也很容易了,先写出constructor和selector:
(define (make-exponentiation base e)
  (cond ((
= e 0) 1)
        ((
= e 1) base)
        (
else
          (list 
'** base e))))
(define (base x) (cadr x))
(define (exponent x) (caddr x))
(define (exponentiation? x)
  (
and (pair? x) (eq? (car x) '**)))
用**表示幂运算,因此(make-exponentiation x 3)表示的就是x的3次方。
修改deriv过程,增加一个条件分支:
(define (deriv exp var)
  (cond ((number? exp) 0)
        ((variable? exp)
         (
if (same-variable? exp var) 1 0))
        ((sum? exp)
         (make
-sum (deriv (addend exp) var)
                   (deriv (augend exp) var)))
        ((product? exp)
         (make
-sum
            (make
-product (multiplier exp)
                          (deriv (multiplicand exp) var))
            (make
-product (multiplicand exp)
                          (deriv (multiplier exp) var))))
        ((exponentiation? exp)
         (let ((n (exponent exp)))
         (make
-product (make-product n (make-exponentiation (base exp) (- n 1))) (deriv (base exp) var))))
        (
else
           error 
"unknown expression type -- Deriv" exp)))
粗体的就是我们增加的部分,两次运用make-product做乘法。
测试下:
> (deriv '(** x 3) 'x)
(
* 3 (** x 2))
> (deriv '(** (+ x 1) 5) 'x)
(
* 5 (** (+ x 14))

习题2.57,只要修改selector函数就够了,如果是多项的和或者积,那么被乘数和被加数也是列表,可以直接表示为符号表达式而不求值
 (define (augend s)
 (let ((rest (cddr s)))
    (
if (null? (cdr rest))
        (car rest) 
        (cons 
'+ rest))))
(define (multiplicand p)
  (let ((rest (cddr p)))
    (
if (null? (cdr rest))
        (car rest) 
        (cons 
'* rest))))

习题2.58,分为a和b,a倒是很容易解答,修改下谓词、选择函数和构造函数就可以了,将运算符号放在列表中间,注意,题目已经提示,假设+和*的参数都是两个,因此
(a)题目:
(define (=number? x y)
  (
and (number? x) (= x y)))
(define (variable? x) (symbol? x))
(define (same
-variable? v1 v2) (and (variable? v1) (variable? v2) (eq? v1 v2)))
(define (sum? x)
  (let ((op (cadr x)))
    (
and (symbol? op) (eq? op '+))))
(define (addend s) (car s))
(define (augend s) (caddr s))
(define (make
-sum a1 a2)
  (cond ((
=number? a1 0) a2)
        ((
=number? a2 0) a1)
        ((
and (number? a1) (number? a2)) (+ a1 a2))
        (
else
         (list a1 
'+ a2))))
(define (product? x)
  (let ((op (cadr x)))
    (
and (symbol? op) (eq? op '*))))
(define (multiplier x) (car x))
(define (multiplicand x) (caddr x))
(define (make
-product a1 a2)
  (cond ((
or (=number? a1 0) (=number? a2 0)) 0)
        ((
=number? a1 1) a2)
        ((
=number? a2 1) a1)
        ((
and (number? a1) (number? a2)) (* a1 a2))
        (
else
          (list a1 
'* a2))))
测试下:
> (deriv '(x + (3 * (x + (y + 2)))) 'x)
4
> (deriv '(x + 3) 'x)
1
> (deriv '((2 * x) + 3) 'x)
2
> (deriv '((2 * x) + (3 * x)) 'x)
5

习题2.59,求集合的交集,遍历集合set1,如果(car set1)不在集合set2中,就将它加入set2,否则继续,当集合set1为空时返回set2。
(define (union-set set1 set2)
  (cond ((null? set1) set2)
        ((null? set2) set1)
        ((element
-of-set? (car set1) set2) set2)
        (
else
          (union
-set set1 (cons (car set1) set2))))) 

习题2.60,需要修改的仅仅是adjoin-set:
(define (adjoin-set x set)
  (cons x set))
效率由原来的n变成常量。其他操作的效率与原来的一样。有重复元素的集合,比如成绩单、钱币等等。


习题2.61,关键点就是在于插入元素后要保持集合仍然是排序的,如果x小于(car set),那么最小的就应该排在前面了,如果大于(car set),那么将(car set)保留下来,继续往下找:
(define (adjoin-set x set)
  (cond ((null
? set) (list x))
        ((
= x (car set)) set)
        ((
< x (car set)) (cons x set))
        (
else
           (cons (car set) (adjoin
-set x (cdr set))))))

习题2.62,与求交集类似:
(define (union-set set1 set2)
  (cond ((null
? set1) set2)
        ((null
? set2) set1)
        (
else
         (let ((x1 (car set1))
               (x2 (car set2)))
           (cond ((
= x1 x2)
                  (cons x1
                        (union
-set (cdr set1) (cdr set2))))
                 ((
< x1 x2)
                  (cons x1
                        (union
-set (cdr set1) set2)))
                 ((
> x1 x2)
                  (cons x2
                        (union
-set set1 (cdr set2)))))))))

测试下:
> (define set1 (list 2 3 4 5 9 20))
> (define set2 (list 1 2 3 5 6 8))
> (union-set set1 set2)
(
1 2 3 4 5 6 8 9 20)

习题2.63,其实两个变换过程都可以看成是对树的遍历
a)通过测试可以得知,产生一样的结果,两者都是中序遍历二叉树,书中图的那些树结果都是(1 3 5 7 9 11)
b)对于tree->list-1过程来说,考虑append过程,并且每一步并没有改变搜索规模,而append的增长阶是O(n),因此tree->list-1的增长阶应该是O(n2),n的二次方
而对于tree-list-2过程,增长阶显然是O(n)

习题2.64,这题非常有趣,用一个数组构造一棵平衡的树,显然,方法就是将数组对半拆分,并分别对两个部分进行构造,这两个部分还可以拆分直到遇到数组元素(左右子树都是'()),中间元素作为entry。这个过程可以一直递归下去。这里采用的正是这种方式
a)解释如上,(1 3 5 7 9 11)将形成下列的二叉树:
        5
       /  \
      1    9
       \  /  \
        3 7   11
显然,列表的对半拆分,以5作为根节点,然后左列表是(1 3),右列表是(7 9 11),左列表拆分就以1为节点,右列表拆分以9为节点,其他两个为子树。

b)仍然是O(n)

习题2.65,很简单了,转过来转过去就是了:
(define (union-set-1 tree1 tree2)
  (list->tree (union-set (tree->list-2 tree1)
                         (tree->list-2 tree2))))
(define (intersection-set-1 tree1 tree2)
  (list->tree (intersection-set (tree->list-2 tree1)
                                (tree->list-2 tree2))))

 习题2.66,与element-of-set?类似:
(define (lookup given-key set-of-records)
  (cond ((null? set-of-records) #f)
        ((= given-key (key (entry set-of-records))) (entry set-of-records))
        ((
< given-key (key (entry set-of-records))) 
           (lookup given-key (left-branch set-of-records)))
        ((
> given-key (key (entry set-of-records))) 
           (lookup given-key (right-branch set-of-records)))))

习题2.67,结果是(a d a b b c a) ,DrScheme字母符号是小写
习题2.68,使用到memq过程用于判断符号是否在列表中:
(define (encode-symbol symbol tree)
  (define (iter branch)
    (if (leaf? branch)
        '()
        (if (memq symbol (symbols (left-branch branch)))
            (cons 0 (iter (left-branch branch)))
            (cons 1 (iter (right-branch branch))))
        ))
  (if (memq symbol (symbols tree))
      (iter tree)
      (display "bad symbol -- UNKNOWN SYMBOL")))
习题2.69,因为make-leaf-set产生的已经排序的集合,因此从小到大两两合并即可:
(define (generate-huffman-tree pairs)
  (successive
-merge (make-leaf-set pairs)))
(define (successive-merge set)
  (if (= 1 (length set))
(car set)
(successive-merge
(adjoin-set (make-code-tree (car set) (cadr set)) (cddr set)))))

习题2.70,利用generate-huffman-tree和encode过程得到消息,使用length测量下消息长度就知道多少位了:
(define roll-tree (generate-huffman-tree '((A 2) (NA 16) (BOOM 1) (SHA 3) (GET 2) (YIP 9) (JOB 2) (WAH 1))))
(define message (encode
         
'(Get a job Sha na na na na na na na na Get a job Sha na na na na na na na na Wah yip yip yip yip yip yip yip yip yip Sha boom)
         roll
-tree))

> (length message)
84
  通过huffman编码后的位数是84位,如果采用定长编码,因为需要表示8个不同符号,因此需要log2(8)=3位二进制,总位数至少是36*3=108位,压缩比为22.22%

习题2.71,很显然,最频繁出现的符号肯定在根节点下来的子树,位数是1,而最不频繁的符号是n-1位




posted @ 2007-07-03 17:04 dennis 阅读(592) | 评论 (1)编辑 收藏

    vi作为linux下的通用文本编辑工具,是经常使用到的。vi功能强大,命令也相当多,常用的摘记下:
1.设置显示行号  :set nu
  取消显示行号  :set nonu
2.光标移动到n行 nG
  光标移动到最后一行 G
3.光标移动到本行第n个字符 n空格
  光标移动到本行最后一个字符 $
4.向光标之后搜索字符串 /word
  向光标之前搜索字符串 ?word
5.从第n1行到第n2行搜索word1字符串,并替换为word2   :n1,n2s/word1/word2/g
  逐个替换   :n1,n2s/word1/word2/gc
  从第一行到最后一行进行替换应该是              :1,$s/word1/word2/g
6.向前翻页 ctr+f
  向后翻页 ctr+b
7.恢复修改操作 u
8.复制本行 yy
  本行往下n行进行复制 nyy
9.粘贴在光标以下的行 p
  粘贴在光标以上的行 P
10.向后删除一个字符 x
   向前删除一个字符 X
   向后删除n个字符 nx
11.保存   :w
   退出   :q
   强制退出不保存 :q!
   强制保存   :w!
   保存并退出 :wq
   另存为     :w otherfilename
  


posted @ 2007-07-03 09:17 dennis 阅读(393) | 评论 (0)编辑 收藏

   在天涯看了一个帖子,心情很沉重,《满天都是绿帽子,我也搞了顶戴戴》。作者的妻子背叛了他,而作者以近乎杀手的冷酷头脑制定了报复计划,读起来像小说,可似乎又非常真实。完全理解在知道自己所爱的人背叛后的心情,可似乎这也不能成为互相伤害,乃至同归于尽的借口。一句很流行的话这样形容:女人无所谓正派,正派是因为受到的引诱不够;男人无所谓忠诚,忠诚是因为背叛的筹码太低。在第一次看到这句话,很悲哀,难道这个世界再没有书中或者电影中所描述的美好爱情了吗?呵呵,我还是太理想主义。昨天老婆说我太多疑了,我必须承认,因为当年的某个伤口还没有愈合,我害怕再次心疼心痛的感觉。只是如果大家不爱了,那就放手吧,让时间来遗忘,报复也许能带来一时的快感,但是悔恨和痛苦将伴随终生,正如文中的当事人也早已经心死了。

posted @ 2007-06-30 16:42 dennis 阅读(349) | 评论 (0)编辑 收藏

    没事做,就在两台机器间测试下Erlang分布式的例子,一个台是windowsXP,一台装的redHat9,没有详细的文档,自己摸索着搞成功了,记录下。

1.首先,分布式Erlang的实现提供了自有的安全机制来预防未经授权的Erlang系统访问。Erlang系统与别的机器进行交互时必须有同样的magic cookie,保存在一个称为.erlang.cookie的文件中,为了在两台不同机器间测试,需要编辑一份.erlang.cookie,内容随便,比如:
just_test

然后将这份文件拷贝到windows环境变量HOMEPATH所在的目录 ,比如我的是C:\Documents and Settings\Admin,而linux拷贝到环境变量$HOME指向的目录,比如我这里是/root。特别注意一点,linux的.erlang.cookie文件需要设置权限为-r--------,也就是400,仅所有者可读:
chmod 400 .erlang.cookie

2.因为Erlang中的node名称是name@host,host是计算机名,因此在两台机器上都需要将计算机名和ip加进hosts文件,这个文件在linux下是在/etc/hosts,你可以用vi编辑如下:
127.0.0.1  localhost localhost
x.x.x.x    zane      zane
   #windows机器的ip和计算机名
,hosts在windows系统的C:\WINDOWS\system32\drivers\etc目录下,编辑:
127.0.0.1       localhost
x.x.x.x   dennis 
#linux机器的名称和ip

3.第三步,要启动节点,通过命令erl -sname 或者erl -name,在此之前需要启动epmd进程,它负责映射符号名到机器地址
在两个机器都执行:
epmd -daemon

4.至此配置完成,可以测试下Erlang分布式编程在不同的机器和系统之间了(比如《Erlang入门(三)--分布式编程》中的ping pong例子),very cool!

posted @ 2007-06-29 16:33 dennis 阅读(3658) | 评论 (0)编辑 收藏

仅列出标题
共56页: First 上一页 37 38 39 40 41 42 43 44 45 下一页 Last