NOTICE

 任何跟文章無關的閒聊,請愛用 留言板(Guestbook)。

 想要快速瀏覽主題,請點選單 目錄 標籤。

 停止更新ing,請見諒。 <(_ _)>


顯示具有 雜記 標籤的文章。 顯示所有文章
顯示具有 雜記 標籤的文章。 顯示所有文章

9月 15, 2010

【雜記】漫談樹狀結構

@
  在之前寫的「樹(tree)」這篇文章中,有網友提到:希望能夠瞭解 tree 能夠在應用上什麼問題上面。不過,由於我本身對樹的瞭解也很粗淺,所以這篇就野人獻曝一下,隨意講講一些我知道的東西。學得不甚透徹,可能會有些不完整或是錯誤的地方,就請各位別見怪囉 :P


  先前曾經提到:在樹狀結構中,節點(node)的分支度(degree)代表其子節點(child)數量。若是有一種樹狀結構至多只會有 n 個子節點,即樹中的任何節點分支度均小於或等於 n,則我們會將這種樹稱為一棵「n 元樹」。

  其中,大概就屬二元樹(binary tree)的應用最為廣泛。如上所述,其節點至多只會有兩個子節點。通常我們會直接將之稱為左子(left child)與右子(right child)。下圖是一棵二元樹:




  在談應用之前,讓我們先來看看一個樹狀結構常見的操作:尋訪(traversal),也就是依照某種順序訪問樹中的所有節點。一般來說,常見的尋訪方式包含深度優先尋訪(depth-first traversal)與廣度優先尋訪(breadth-first traversal)。

  以上面的樹狀圖來說明,深度優先尋訪會先從根節點 F 開始,走訪 F 的第一個子節點 B,再接著走訪 B 的第一個子節點 A。由於 A 不具有子節點,所以我們退回上一層,再接著走訪 B 的第二個子節點 D。完整的尋訪順序為:F B A D C E G I H。

  而廣度優先尋訪相對於深度優先尋訪的不斷深入,是以層級順序(level-order)來進行尋訪。所以同樣由根節點 F 開始,走訪 F 的第一個子節點 B,再接著走訪 F 的第二個子節點 G。由於 F 只有兩個子節點,所以我們接著尋訪下一層 B 的子節點 A 與 D,然後是 G 的子節點 I。完整的尋訪順序為:F B G A D I C E H。


  其中,二元樹又具有三種特殊的尋訪方式:前序(pre-order)、中序(in-order)、與後序(post-order)。若是把尋訪根節點、尋訪左子樹、尋訪右子樹分別記做 D、L、R,則前序的尋訪順序為 D L R、中序的尋訪順序為 L D R、後序的尋訪順序為 L R D。

  以同樣的圖舉例的話,前序的尋訪順序為:F B A D C E G I H、中序的尋訪順序為:A B C D E F G H I、後序的尋訪順序為:A C E D B H I G F。(正確來說,二元樹只比一般的樹多了中序與後序兩種尋訪方式,因為前序尋訪與深度優先尋訪的順序其實是相同的。)


  說完了尋訪,不過跟應用有什麼關聯呢?其中一個常見的用途是排序(sorting)。

  我們可以定義一個特殊的二元樹:樹狀結構中,其左子樹所有節點所存的值必定小於根節點的值,且其右子樹所有節點所存的值必定大於等於根節點的值。如下圖:



  有沒有發現,當我們用中序來尋訪這棵二元樹,我們便可以得到一個升序(ascending order)的數列。


  若是根據定義,給出一個新增節點的操作:

Function insertNode(TreeNode root, Type value)
    If root.value > value then
        If root.hasLeftChild Then
            insertNode(root.leftChild, value)
        Else
            root.leftChild = CreateNode(value)
    Else
        If root.hasRightChild Then
            insertNode(root.rightChild, value)
        Else
            root.rightChild = CreateNode(value)
End

  利用這個新增節點的操作,我們便可以將一堆資料建立成一棵符合定義的二元樹。於是,我們便可以利用這個操作,在加上中序尋訪來得到一串排序過的資料。


  事實上,這種特殊的二元樹,被稱為二元搜尋樹(binary search tree)。其義如其名,這種二元樹也可以用以進行「已排序資料」的搜尋(search)。

  根據定義我們可以得知:若是欲尋找的值小於二元搜尋樹的根節點,則其右子樹必定不可能出現欲尋找的值;同樣的,若是欲尋找的值大於二元搜尋樹的根節點,則其左子樹必定不可能出現欲尋找的值。而這種方式其實就跟二分搜尋法(binary search)的原理有異曲同工之妙。

  我們可以定義搜尋的操作如下:

Function search(TreeNode root, Type value)
    If root.value = value then
        print "Found"
    Else If root.value > value then
        If root.hasLeftChild Then
            search(root.leftChild, value)
        Else
            print "Not Found"
    Else
        If root.hasRightChild Then
            search(root.rightChild, value)
        Else
            print "Not Found"
End

  而這種利用二元搜尋樹的搜尋方式,其複雜度為 O(h)。其中 h 為樹的高度(height)。而若每棵子樹的左右子樹節點數量都相同(或差一),則 h 即等同於 lg n,也就是說搜尋的複雜度為 O(lg n),與二分搜尋法相當。


  由以上這些例子,可以知道「樹」不僅可以用來處理常見的排序與搜尋問題,還是種挺有效率的方式呢。


References:

7月 11, 2010

【雜記】FLOLAC '10

@
  2010 Formosan Summer School on Logic, Language, and Computation(FLOLAC ’10),是辦在台大進修推廣部的暑期碩士學分班。雖然是碩士學分班,但由於剛好符合相關學系大二以上的報名資格,又在半自願被網友 yen3 「騙來」的狀態下還是報名了XD。




  對於一個語言,我們可以從兩個觀點來看它:一個是語法(syntax),即語言本身的規則(rule)與形式(form);另一個則是語意(semantics),為語言本身所表達的意義(meaning)。

  寫出可以執行的程式也許不難,要寫出正確的程式卻不簡單。當我們得到一段程式,我們該如何分析、驗證這個程式的結果,以確保其確實符合我們的預期?更甚者,我們該如何在撰寫程式的同時,也確保我們建構出來的程式一定是正確的?

  對於程式語法上的錯誤(syntax error)可以經由編譯器(compiler)或直譯器(interpreter)來幫我們檢查出來。但是,語意上的錯誤(logic error 或稱 semantic error)卻難以經由其他工具來協助我們察覺。

  一般我們也許習慣利用測試資料來確認程式的正確性:只要程式能通過所有的測試資料(即輸出結果符合預期),我們就可以「假設」程式是正確的了。不過,要產出全面性的測試資料本身有其難度,再加上此種方式必須仰賴於程式的實作(implement),作為驗證並不是一種非常好的方式。

  而 FLOLAC '10 這一系列的課程,主要的內容就是教導如何以邏輯推理為基礎,從語意的角度將程式形式化(formalize)並進行分析。以及用以輔助的 Frama-C 分析工具的使用。



  不過 FLOLAC ’10 的時程有兩天跟期末考撞期,所以一開始就請了兩天假。直到第三天的 Logic 跟 Op 課都已經是第二堂課,FP 課甚至已經結束了。要在沒聽過第一堂課的情況下銜接上內容,一開始還真是一個頭兩個大。還好後來漸漸跟上了,總算有種進入狀況的感覺。

  歷經了兩週八點準時起床出門上課,直到下午五點下課,比暑假前還規律的暑假生活,水深火熱的 FLOLAC '10 終於順利結束了。雖然課程有點辛苦,不過接觸了不少人、也接觸了不少新東西,感覺收獲也相當多。

  遇見了 yen3、GSR、dryman,還有其他周圍的人、努力想搞懂 Frama-C 到底在做什麼、跟 dryman 一起到麥當勞邊念書邊聊天、期末考前在 Google Wave 上熱烈的討論。對於整個 FLOLAC 的課程,我想我還滿樂在其中的。


  雖然不知道自己能學到多少,又能應用多少。不過也許就像 yen3 所說:「能體會,就能產生質變」。或許在之後就會發現,現在學過的這些,其實都有潛移默化的作用也說不定。

3月 05, 2010

【雜記】關於「近」況

@
  顯然,這裡已經很久沒有更新了。雖然我還有持續在注意有沒有新留言,但是遲遲沒有貼新文章。總覺得偷懶也偷得夠久了,似乎該回來寫點東西XD。

  其實這個 blog 平台用久了,總會覺得不太滿意,想要一個針對自己需求特化的一些功能(當然 blogger 這個平台也相當好,我用起來也挺順手的,但是我還是覺得缺了點什麼XD)。因為不太想用一些如 WordPress 或 Joomla! 之類的現成 CMS(Content Management System,內容管理系統)來修改,便瘋狂的想要自己寫一個(這種重複造輪子的行為千萬別模仿XD)。

  原本我是打算,暫時停止 blog 的更新,專心寫一個 CMS 出來,再將現有的文章做個整理過去。但是事實證明,除了我對 Web Programming 不是非常熟悉之外,還有無止境的偷懶造就了現在的結果:blog 停止更新永無止境,想做出來的 CMS 卻連個影子都沒有XD。

  前陣子,剛好在誠品書局隨手翻到了 IThome 電腦報的 IT部落客大直擊(上)。被標題吸引的我,就這樣順手買了回來翻翻,突然懷念起以前寫 blog 的日子XD。雖然我仍舊沒有放棄想要一個客製功能 blog 的想法,但我也不想繼續這樣把 blog 擺著。

  經過考慮之後,我決定先從整理這裡的舊文章開始。也許有些文章會被我修改、或是分割內容成其他文章,或許有些文章會被我偷偷地砍掉。也或許,會「順手」新增幾篇文章吧XD。



  太久沒有寫 blog,有點不知道自己在寫些什麼,感謝各位耐心看完我一整篇的胡言亂語XD。

11月 01, 2008

【雜記】莫忘初衷

@
  從今年二月申請 blogger 帳號,開了現在這個 blog、三月開始寫文章、貼程式。歷經高三的 TOI、學測、指考,大學的暑假、開學、NCPC。這樣斷斷續續的寫寫停停,直到現在,也已經八個月了。好不容易,終於到達目前的第一百篇(雖然廢話佔了不少篇)。

  最初開始寫這個部落格,其實只是單純的想要放上自己的作品。一段時間之後,出於對那些在網誌分享知識的人的嚮往,我開始試著將自己所學、所想寫出來,貼在網誌上分享給其它人。那時候的想法也很簡單:希望所有想學程式設計的人,都可以用簡單的方式入門,再透過網誌留言討論互相切磋、進步。也因此,我為這個網誌定下了「世界,你好!」這個名字。

  等到真正開始之後,才更深刻的知道寫網誌的困難。自己蒐集資料、整理資料,揉合自己的想法,用自己的口吻與文字表達出來。一篇篇的文章寫了又刪、刪了又寫,有時一耗就是一整個晚上。寫得越久,也越發現自己能力的不足、發現自己並沒有學得透徹。偶爾稍有空閒,我會再回頭去看看以前寫的文章。總是會有許多缺點與漏洞,時常讓我差點禁不住衝動,想要一次砍光。

  再加上,由於基礎的教學文章難寫,常常是耗了半天,遲遲寫不出滿意的內容。無奈之下,我也只得以解題文章充數。因為如此,說不定我從一開始就偏離了「簡單入門」的目標。而且,在開創以來的前幾個月,其實並不如我所期望的,有任何程式設計愛好者的討論與交流。只見網誌的文章數徒增,留言區卻依舊冷冷清清,這種「文章不知寫給誰看」的感覺,實在是相當難過。

  這一次,在整個網誌改版之後,我順勢把網誌換了個名字 - Infinite Loop。代表著我對往後的自己能夠有所突破(break)所做的期許。不過,沒想到 Tory 看到標題,卻直接說:「寫程式就是如此,一直寫下去,不知盡頭在那」。雖然這並不是我當初更名的本意,但是我想,或許這句話對一個程式人、對一個程式設計的網誌來說,也是再好不過的註腳了。

  假借一百篇的名義,我特地將這些想法、這些理念訴諸文字,寫在這裡。與未來的自己、以及所有喜愛程式的同好共勉之。

3月 20, 2008

【雜記】由TOI回顧我的過往

@
  剛好TOI(台灣資訊奧林匹亞)初選比完一段時間了。仔細想想,去年還覺得走到這一步,在我的高中生涯中是不可能實現的。


  回頭想想,我對電腦可以說一見鍾情。第一次接觸電腦,是在小三或是小四的時候吧,那時還是Windows 95相當風行的時代。由於老爸是資訊相關工作者的緣故,所以在他使用電腦時,只要發現我偷偷湊在後面仔細的瞧,就會為我解說他現在在做什麼。

  不過,當時吸引我的,可不是什麼特別的電腦遊戲。而是一款再平常不過,Windows內建的磁碟重組工具。或許相當怪異,但是當時的我,可是被那幾個移動的小方塊所深深吸引。彷彿電腦本身是一場魔術,而我老爸就是訓練有素的魔術師。之後,我前前後後玩過幾款電腦遊戲,但是多半沒留下太多印象。


  當時的網路還是撥接上網(還會發出有趣的撥接音效),只是當時要上網,還得是老爸在家時,幫忙輸入帳號密碼才行。過了一兩年,好不容易跟家裡的人要到連線的帳號密碼,我才開始能夠自由上網。

  也不曉得是怎麼個因緣際會,我偶然發現了HTML(HyperText Markup Language,超文字標記語言)。不過那時我也不算真正學會,頂多就只是看到別人寫的網頁特別的地方,使用複製貼上勉強拼湊出一個網頁來(後來才知道,我複製的那一堆原始碼不光是HTML,其中多半是JavaScript)。


  也差不多是那個時期,我接觸了當時相當流行的LF1(Little Fighter,小朋友齊打交),還記得那是當時最大的娛樂。常常是到同學家,一玩就是整個下午。過了不久,LF2推出之後曾經掀起了一股熱潮,那就是「改版」。也就是透過一套非官方的改版器,只要學會簡單的語法規則,就能夠修改遊戲中的人物、絕招、關卡、甚至地圖。

  當然,我也是追著這股熱潮的其中一人。一開始我只是嘗試性的做小小的更改,再參照別人發出的改版,搭配從各處蒐集或是自繪的圖片。那時,我常常天馬行空的想哪個人可以有哪些招式。只要一有時間,我就沒天沒夜的做,到最後竟然還真的弄出一系列來了!

  當時頗得意的是,我將自製改版發佈於某個LF2的論壇專版,還獲得不少好評(不過之後由於電腦中毒重灌,我的辛苦結晶就如此付之一炬,也就沒有再次製作的意願了)。由於有過這種經歷,當時的我甚至決定了志向:遊戲設計師。雖然不可否認的,當時的這個夢想已逐漸淡忘。不過,也或許就是當時,悄悄的埋下了我學習程式設計的種子。


  上了國中之後,朋友介紹給我他正在學的一套互動多媒體軟體:Flash。這套軟體立刻激起我的興趣,我先是跟他借了書、要了軟體,再自己買書來研究。我試著用Flash作出幾個簡單的小動畫,或是直接將它做成網頁(我做出來的效果很差)。雖然到最後都沒有玩得很透徹,但是回想起來那段時期還是非常有趣。


  不過直到高二,才是真正影響我走向程式設計的時刻吧。當時的我第一次獲知有資訊學科競賽這回事,憑著高一電算課學過的Visual Basic,勉強通過了校內初選。當時還不是很清楚程式設計是怎麼一回事(或許現在也沒比當時瞭解多少),只知道看到前幾年的考古題只有一片茫然,暗自猜想憑己當時所學,去比賽必定是相當不利吧。事實果真不出所料,之後晉級參加的北市競賽只抱了個悽慘的成績(術科總共六題,滿分150分。我只得了10分)。

  在一次比賽下來,我認為使用VB來解題實在有諸多不便之處。於是,我決定另尋起點,重新開始。在詢問過學長及老師的意見後,我決定把C當作我的起點。我買了書,花了一個月的課後時間讀完。又花了一週的晚上零碎時間,一題一題把北市資訊競賽的題目解出來。等到對程式設計有些心得了,我開始試著寫一些其他的程式,或是以C語言的基礎接觸其他諸如C++、Ruby、PHP等等語言。

  直到接下來的這一年(也就是今年),我先後得到了全校第一、電腦軟體設計競賽高中組佳作(以排行來看應是第10名)、北市資訊學科能力競賽三等獎(第16名),到有幸參加TOI的初選。儘管比賽多少留有些許遺憾(太緊張的出錯,意外忽略的小細節),不過至少我證明自己靠著努力做到了!


  似乎是在長久的追尋,我才在電腦世界中找到自己的熱情。於是,我決定要繼續投身在程式世界當中。

  這次的比賽,是我高中生涯中資訊競賽的終點。也或許,這只是我往後程式設計的起點。將來會怎麼樣?我不知道。總之,只要夢想還在前方,只要我對程式設計還有熱情,我就會繼續走下去。

  最後,好像有什麼忘了說?




   我落選了。

  後記.還以為自己對學習資訊的歷程記憶猶新,實際寫出才發現所記得的事早已不多了。內容比較零星,但這些是我珍藏已久的回憶。

3月 13, 2008

【雜記】漫談程式設計

@
  在我的經驗中,許多人聽到程式設計,臉上總會閃過一瞬驚恐的表情,彷彿聽到世界末日的宣言。有的人相反,臉上掛著興致勃勃的表情,卻絲毫不懂什麼叫做「寫程式」。在這裡,我想隨意的(或者說,主觀的)談一談「程式設計」。

  首先,什麼是程式設計?現實中,我們會碰到許許多多的問題。例如:想要方便的保存資料,並且能夠快速的取用與管理。我們或許可以使用電腦來這個問題(例如建立一個近端的資料系統),而所謂的程式設計(programming)就是實現這些解決方法的過程。

  所以,為了要快速找到資料,而有搜尋程式;為了方便文字編輯工作,而有文本編輯器;為了能夠電子繪圖,而有繪圖軟體;(或許)為了要打發無聊時間,而有遊戲軟體。或許這樣定義過於草率,不過簡單說來,程式設計也就是這麼回事。

  至於要如何學好程式設計?我認為,應該要先學會以下幾點:

【怕它,不如瞭解它】

  「這個好難,我學不會」,有時不經意跟別人講起程式設計,時常會聽到這樣的話(不光是程式設計,各個學科領域其實都有這種情況)。在真正瞭解什麼是程式設計之前,許多人就先入為主的認為難度過高,學不會。

  當然,程式設計有它的難度。但是再怎麼說,它也不過是一種技術,學習技術是可以靠練習達成的。與其在學習之前就直接放棄,不如先試著接受它,是吧?

【從基礎學起,別妄想一步登天】

  除了「把程式當天敵」的人之外,也有人是對程式有著強烈興趣,卻只停留在表象的。舉例來說,我相信,製作遊戲應該是引發許多人想學程式設計的動機之一。製作遊戲並沒什麼不好,但是我看過的許多人,是連程式都沒寫過幾行(更甚者,是連程式都不想學),就妄想能夠立刻"蹦"出一個遊戲來。

  這邊一定要提醒各位,程式設計是循序漸進、一步一腳印的知識累積。假如你還抱著什麼都不學,或是隨便學幾招皮毛,就能夠寫出驚人的程式(或遊戲)的想法,還是趁早放棄吧!

【多查資料,少發問】

  另一種很常見的情況,總會有許多人在奇摩知識+或是各大論壇的程式設計版提出許許多多的問題。我不是要批評發問是個不好的行為,相反的,發問還有助於每個人的意見交流。但是,有多少人是自己查過資料,發現仍有不解之處,或是查到的資料不符所需才提出的疑問?根據我的觀察,比較常見的應該是什麼都不查,就直接提出疑問的吧(其中不乏一些現有資料已經相當多的基礎問題)。

  學習的過程當中,當然需要不斷的發問。但是,我相信假如碰到問題能夠學著自己去搜尋、整理資料來解決,比起一碰到問題,就只會一味的請求別人解惑的作法收穫更多吧。

【會寫程式,也要會讀程式】

  就我自己的經驗而言,與其叫我去解讀別人的程式,我還寧願自己去寫一個出來。這是難免的,畢竟程式是別人寫的,要花費時間解讀,有時還不如自己寫一個還比較輕鬆。

  不過再仔細想想,以文學的角度來看,多看別人的文章,對自己的文筆能有所提升;以藝術的角度來看,多觀摩他人的作品,也有利於增進自己的畫技。程式設計也是一樣的道理。當你限在正在解讀他人的程式時,也就是在吸收別人的菁華,儘管剛開始會有些困難,不過久而久之,對於自己的能力也會有一定提升。

【持之以恆,廣博學習】

  雖然這兩句話看來都陳腔濫調了。不過首先,持之以恆確實是重要的。當然你不用到「廢寢忘食」,每日三餐下午茶加宵夜都在研究程式設計(不過狂熱者真的可以做到這樣)。不過,時常回顧寫程式的感覺,偶爾花點時間練習。哪怕只是想寫什麼就寫什麼,也是很有幫助的。

  至於廣博學習,就是時常翻閱書籍、查詢網路了。也不需要抱著「有新資訊我一定要知道」的想法,想知道什麼,就去看什麼。一切出於自發,就能夠學到很多了!

  註.以上皆為個人淺見。假如有人認為有該補充的地方,歡迎提出。若是以上出現任何謬誤,還請各位多多包含指正。