《 常見演算法與資料結構》符號表ST(1)——基本介紹
阿新 • • 發佈:2019-01-02
符號表(Symbol Table)
本系列文章主要介紹常用的演算法和資料結構的知識,記錄的是《Algorithms I/II》課程的內容,採用的是“演算法(第4版)”這本紅寶書作為學習教材的,語言是java。這本書的名氣我不用多說吧?豆瓣評分9.4,我自己也認為是極好的學習演算法的書籍。
通過這系列文章,可以加深對資料結構和基本演算法的理解(個人認為比學校講的清晰多了),並加深對java的理解。
1 符號表介紹和API
1.1 符號表介紹
符號表(Symbol Table)是一個非常常見的資料結構,在現實生活中應用很多。它是一個“鍵”—“值”對應的結構。在符號表中,儲存的是鍵值對。通過輸入鍵,查詢對應的值。
這個基礎的資料結構,在現實生活中使用的特別多,比如字典。
1.2 符號表API
其實符號表的操作,也無非就是增刪改查之類的
函式名 | 功能 |
---|---|
ST() | 建立一個符號表物件 |
void Put(Key key, Value val) | 往集合中插入一條鍵值對記錄,如果value為空,不新增 |
Value Get(Key key) | 根據key查詢value,如果沒找到返回null |
void Delete(Key key) | 刪除鍵為key的記錄 |
boolean Contains(Key key) | 判斷集合中是否存在鍵為key的記錄 |
boolean IsEmpty() | 判斷查詢表是否為空 |
int Size() | 返回集合中鍵值對的個數 |
Iterable Keys() | 返回集合中所有的鍵 |
Ps.有一些約定要提前說一下
- 值不為null
- 如果key不存在,get()返回為null
- put()會覆蓋舊值
通過這幾個約定,我們可以把contain和delete函式簡單實現。
public boolean contains(Key key)
{ return get(key) != null; }
public void delete(Key key)
{ put(key, null ); }
2 鍵和值的約定
2.1 值(value)
在java中如果我們想要實現一個符號表,我們希望它是支援所有泛型的。
2.2 鍵(Key)
對於鍵的,我們希望:
- Key是可比較的,即是
Comparable
的,並且使用compareTo()
函式 - Key是泛型的
- 能用
equals()
判斷相等,能用hashCode()
獲取鍵(這兩個函式都是java的內建函式) - 對於Key最好是使用不可變的型別(Integer,Double, String之類的)
3 相等性測試
如果我們提到了equals()
函式,就不得不提提java的相等性測試,Java要求equals()
滿足:
- 自反性: x.equals(x) is true
- 對稱性: x.equals(y) iff y.equals(x)
- 傳遞性: if x.equals(y) and y.equals(z), then x.equals(z)
- 不為null: x.equals(null) is false
一般來說,我們做判斷使用的( x == y ) 這個式子並不做型別檢查。所以,我們在實現equals()的時候,要特別注意,它看起來很簡單,但是想實現完美比較麻煩。
比如一個日期的class,你可能會這樣實現equals()
public class Date implements Comparable<Date>
{
private final int month;
private final int day;
private final int year;
...
public boolean equals(Date that)
{
if (this.day != that.day ) return false;
if (this.month != that.month) return false;
if (this.year != that.year ) return false;
return true;
}
}
但是你如果這樣實現會更好:
- 用
final
欄位,不然可能會違反對稱性(繼承) - 最好用
Object
,(不過這個專家們目前還在激烈爭論中) - 加入自反性,不為null的判斷,並且驗證型別一致性。
- 關於比較一個類中的不同變數:
- 如果比較的是一個原始型別,用==
- 如果比較的是一個物件,用equals()
- 如果比較的是一個數組,對Arrays.equals(a, b),而不是a.equals(b)
public final class Date implements Comparable<Date>
{
private final int month;
private final int day;
private final int year;
...
public boolean equals(Object y)
{
if (y == this) return true;
if (y == null) return false;
if (y.getClass() != this.getClass())
return false;
Date that = (Date) y;
if (this.day != that.day ) return false;
if (this.month != that.month) return false;
if (this.year != that.year ) return false;
return true;
}
}