編譯原理:實驗二、集合與線性表操作

(一).     實驗目的

編譯器處理源程序文件的過程中,集合、鏈表、棧是經常出現的數據結構。

與《數據結構》課程關注集合、線性表的編程實現不同,本實驗關注它們的使用。在Java語言中,集合和線性表分別就是Java工具類Util包中的Set和List兩個接口。特別的,本實驗關注HashSet、ArrayList(或Vector)和Stack(它們分別是集合、鏈表和棧的實現類)的使用,爲後續實驗做好準備。

(二).     預備知識

1.    集合和線性表的基本操作

集合和線性表(鏈表和棧)的基本操作是《數據結構》課程的基礎知識,這裏不一一進行介紹。

2.    Collection

在Java中,集合容器(Collection)是一個對象的容器,可以存放一組對象,主要用來組織和管理存放在容器中的對象。

注:Java中,集合Set繼承了Collection,因此Collection很難翻譯。目前較多情況下仍將Collection譯爲“集合”,如“Java Collection Framework”,一般譯爲“Java集合框架”。但要注意,此時的“集合”指Collection。其它情況下,集合指Set。

 

其中,常用的幾個實現類如下:

   HashSet — 使用散列算法實現Set接口

   TreeSet — 使用平衡二叉樹算法實現SortedSet接口

   ArrayList — 使用數組存放對象來實現List接口

  Vector — 與ArrayList的區別在於Vector是同步、線程安 全的,而ArrayList是異步、線程不安全的。性能上,Vector比ArrayList低。

  Stack — 上圖沒有畫出,它是Vector的直接子類,實現了棧的基本操作。

   LinkedList — 使用雙向鏈表來實現List接口

3.    泛型(Generic)

注:泛型與範型同音,但意義相差甚遠。

範型(Paradigm)的範,指一種規範的、可作爲模範的樣式、範例,也譯爲範式。如OO範式等,包含了面向對象編程許多方面的內容,與面向過程的範式作爲區別。

泛型(Generic)的泛,指的是泛化的含義,因爲Generic是“類屬的”的意思。在C++中,泛型就是“模板(Template)”。因爲同音的緣故,許多網絡上的文章,把“泛型”誤爲“範型”,要特別注意區分。泛型的例子如下:

Set<Object>,一個存放元素是“Object”的集合;

Set<String>,一個存放元素是“String”的集合;

Stack<Integer>,一個存放元素是“Integer”的集合;

Stack<aUserDefinedClass>,一個存放由用戶定義的類的集合

4.    集合與線性表基本操作的使用

通常使用形如 Set<Integer> si=new HashSet<Integer>();來聲明一個存放整數的集合(注:類Integer可換成其它自定義的類)。

然後,可使用si.add(new Integer(5));來向集合中插入一個元素5”;再使用si.contains(new Integer(5))來判斷集合中是否包含元素“5”;再使用si.remove(new Integer(5));來從集合中刪除元素“5”。

若要遍歷訪問集合si中的全部元素,則需要使用迭代器Iterator。

通過Iterator<Integer> it=si.iterator();取得si的迭代器,再通過判斷while(it.hasNext()){ //是否遍歷到最後一個元素,若是最後元素,
                   //則hasNext爲假,否則爲真

              Integer i=it.next(); //訪問當前元素

              //do something,對當前元素i進行操作

   }。

線性表的聲明、操作與集合的聲明、操作非常類似,只是換了一個類名而已。如聲明Stack<String> ss=new Stack<String>;爲一個存放字符串的棧,然後可通過ss.peek()、ss.push(aString)、ss.pop()來訪問棧頂元素、進行入棧和出棧操作。

 需要特別注意的是,集合Set不重複保存相同元素。那麼,Set要如何做,才能判斷一個元素是否跟另一個元素相同?答案就是o.equals(e)。如果元素o、e都不爲空,並且o.equals(e),那麼集合Set就認爲o和e是相同的元素。對基本數據類型,如Integer、String等,因爲語言已經實現了對應的equals方法,所以可以直接使用。若集合中的元素是自定義的類,那麼,則需要考慮應如何實現equals方法。在C++的STL庫中,則要實現的是小於等於的LE方法。

(三).     實驗內容

1.    字符集合

a)         聲明一個存放非終結符的集合sc。考慮應拿什麼數據類型或數據結構保存非終結符?

b)        從文件“NonTerminal.txt”中讀取所有的非終結符。文件內容如下:

a, b, c, d.

也即使用逗號分隔非終結符,使用句話表示輸入結束。

c)         使用迭代器遍歷讀入的非終結符,按一行輸出一個非終結符的方式,顯示在屏幕上,並同時寫入到另外一個文件中。

2.    產生式

a)       產生式是形如“A è aB”之類的式子,由產生式左側和產生式右側2個部分組成,中間的“è”用處在於顯示的時候可以分隔2端,並沒有特別含義。如果我們只處理2型和3型文法,即上下文無關文法和線性文法,那麼,產生式應如何設計怎樣的數據結構來保存產生式。換句話說,產生式類應如何設計?

b)      特別的,產生式類中,equals(或LE)方法,應如何實現?

3.    產生式棧

a)       聲明一個存放產生式的棧。產生式使用內容2中的產生式類。

b)      從文件“Production.txt”中讀取所有的產生式。文法的內容如下:

A -> aB

C -> sdfdf

也即一行一個產生式,產生式中間的分隔符是“->”(或其它,可自己再定義),一直到文件結束。

將讀入的產生式,按棧先進後出(First In Last Out FILO)的次序,一行一個在屏幕上顯示出來,並寫入到另外一個文件中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章