標籤:style blog java http tar ext
3.1符號表
符號表最主要的目的就是將一個鍵和一個值聯絡起來。用例能夠將一個索引值對插入符號表並希望在之後能夠從符號表的所有索引值對中按照索引值姐找到對應的值。要實現符號表,我們首先要定義其背後的資料結構,並指明建立並操作這種資料結構以實現插入、尋找操作所需要的演算法。
尋找在大多數應用程式中都至關重要,許多編程環境也因此將符號表實現為進階的抽象資料結構,包括Java——我們會在3.5節中討論Java的符號表實現。下標給出的例子是在一些典型的應用情境中可能出項的鍵和值。我們馬上會看到一些參考性的用例。3.5節的目的就是向你展示如何在程式中有效使用符號表。本書中我們還會在其他演算法中使用符號表。
定義。符號表是一種儲存索引值對的資料結構,支援兩種操作:插入(put),即將一組新的索引值對存入表中;尋找(get),即根據給定的鍵得到相應的值。
3.1.1 API
符號表是一種典型的抽象資料類型:它代表著一組定義清晰的值以及相應的操作,使得我們能夠將類型的實現和使用區分開來。和以前一樣,我們要用API(API)來精確地定義這些操作,為資料類型的實現和用例提供一份“契約”。
在查看用例代碼之前,為了保證代碼的一致、簡潔和實用,我們要先說明具體實現中的幾個設計決策。
3.1.1.1 泛型
和排序一樣,在設計方法時我們沒有指定處理對象的類型,而是使用了泛型。對於符號表,我們通過明確地制定尋找時鍵和值的類型來區分它們的不用角色,而被忽視優先隊列那樣將鍵和元素本身混為一談。在考慮了這份基本的API後(例如,這裡沒有說明鍵的有序性),我們會用Copparable的對象來擴充典型的用例。這也會為資料類型帶來許多新的方法。
3.1.1.2 重複的鍵
我們的所有實現都遵循以下規則:
◆每個索引值能對應著一個值(表中不允許存在重複的鍵)
◆當用例代碼向表中存入的索引值對和表中已有的鍵(及關聯的值)衝突時,新的值會代替舊的值。
這些規則定義了關聯陣列的抽象形式。你可以將符號表想象成一個數組,新的值會代替舊的值。關聯陣列(符號表)中,鍵可以是任意類型,但我們可以用它阿里快速存取數組的內容。一些程式設計語言(非Java)值姐支援程式員使用st[key]來代替st.get(key), st[key] = val來代替st.put(key, val),其中key(鍵)和val(值)都可以是任意類型的對象。
3.1.1.3 空(null)鍵
鍵不可為空。和Java中的許多其他機制一樣,使用空鍵會產生一個運行時異常。
3.1.1.4 空(null)值
我們還規定不允許有空值。這個規定的值姐原因是在我們的API定義中,當鍵不存在時get()方法會返回空,這也意味著任何不在表中的鍵關聯的值都是空。這個規定產生了兩個(我們所期望的)結果:第一,我們可以用get()方法是否返回空來測試給定的鍵是否存在於符號表中;第二,我們可以將空值作為put()方法的第二個參數存入表中來實現刪除,也就是刪除操作的主要內容。
3.1.1.5 刪除操作
在符號表中,刪除的實現可以有兩種方法:延時刪除,也就是將鍵對應的值置為空白,然後在某個時候刪除所有值為空白的鍵;或是即時刪除,也就是立刻從表中刪除指定的鍵。剛才已經說過,put(key, null)是delete(key)的一種簡單的(延時型)delete()就是為了代替這種預設的方案。在我們的符號表實現中不會使用預設的方案,而在本書的網站上put()實現的開頭有這樣一句防禦性代碼:
if(val == null) {delete(key); return ;}
這保證了符號表中任何鍵的值都不為空白。
3.1.1.6 便捷方法
為了用例代碼的清晰,我們在API中加入了contains()和isEmpty()方法,他們的實現如下表。
方法 |
預設實現 |
boolean contains(key key) |
return get(key) != null; |
void delete(Key key) |
put(key, null); |
boolean isEmpty() |
return size() == 0; |
3.1.1.7 迭代
為了方便用例處理表中的所有索引值,我們有時會在API的第一行加上implements Iterable<Key>這句話,強制所有實現都必須包含iterator() 方法來返回一個實現了hasNext()和next()方法的迭代器。但是對於符號表我們採用了一個更簡單的方法。我們定義了keys()方法來返回一個Iterable<Key>隊形以方便用例遍曆所有的鍵。這麼做是為了和以後的有序符號表的所有方法保持一直,使得用例可以遍曆表的鍵集的一個指定的部分。
3.1.1.8 鍵的等價性
要確定一個給定的鍵是否存在於符號表中,首先要確立對象等價性的概念。在Java中,按照約定所有的對象都繼承了一個equals()方法,Java也為它標準資料類型例如Integer、Double和String 以及一些更複雜的類型,如File和URL,實現了equals()方法——當使用這些資料類型時你可以直接使用內建的實現。例如,如果x和y都是String類型,若且唯若x和y的長度相同且每個位置上的字母都相同時,x.equals(y)返回true。而自訂的鍵則需要重寫equals()方法。