莊周夢蝶

          生活、程序、未來
             :: 首頁 ::  ::  :: 聚合  :: 管理

              發現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.aygfsteel.com/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 閱讀(478) | 評論 (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 閱讀(583) | 評論 (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.aygfsteel.com/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.aygfsteel.com/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 閱讀(1427) | 評論 (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 閱讀(414) | 評論 (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 閱讀(1238) | 評論 (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 閱讀(2967) | 評論 (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 閱讀(603) | 評論 (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 閱讀(418) | 評論 (0)編輯 收藏

             在天涯看了一個帖子,心情很沉重,《滿天都是綠帽子,我也搞了頂戴戴》。作者的妻子背叛了他,而作者以近乎殺手的冷酷頭腦制定了報復計劃,讀起來像小說,可似乎又非常真實。完全理解在知道自己所愛的人背叛后的心情,可似乎這也不能成為互相傷害,乃至同歸于盡的借口。一句很流行的話這樣形容:女人無所謂正派,正派是因為受到的引誘不夠;男人無所謂忠誠,忠誠是因為背叛的籌碼太低。在第一次看到這句話,很悲哀,難道這個世界再沒有書中或者電影中所描述的美好愛情了嗎?呵呵,我還是太理想主義。昨天老婆說我太多疑了,我必須承認,因為當年的某個傷口還沒有愈合,我害怕再次心疼心痛的感覺。只是如果大家不愛了,那就放手吧,讓時間來遺忘,報復也許能帶來一時的快感,但是悔恨和痛苦將伴隨終生,正如文中的當事人也早已經心死了。

          posted @ 2007-06-30 16:42 dennis 閱讀(360) | 評論 (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 閱讀(3682) | 評論 (0)編輯 收藏

          僅列出標題
          共56頁: First 上一頁 37 38 39 40 41 42 43 44 45 下一頁 Last 
          主站蜘蛛池模板: 会同县| 门源| 普安县| 桐城市| 疏勒县| 竹山县| 施甸县| 凌海市| 长春市| 孟村| 新兴县| 临城县| 嵊州市| 江川县| 吐鲁番市| 大田县| 孝义市| 洪泽县| 边坝县| 卓资县| 宁蒗| 长治县| 印江| 商洛市| 宕昌县| 彭阳县| 弥渡县| 青神县| 新泰市| 方正县| 饶河县| 洱源县| 金门县| 波密县| 汪清县| 广州市| 彩票| 金溪县| 托克逊县| 连江县| 靖西县|