(一). 實驗目的
編譯器處理源程序文件的過程中,集合、鏈表、棧是經常出現的數據結構。
與《數據結構》課程關注集合、線性表的編程實現不同,本實驗關注它們的使用。在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)的次序,一行一個在屏幕上顯示出來,並寫入到另外一個文件中。