哨兵(sentinel)
昨天看算法導論里對哨兵的描述后,覺得這是一種很有意思的編程思想。
哨兵是一個啞對象。一般哨兵不存放任何數據,但其結構體與其他有用的元素一致。
正如其字面意思,哨兵是在邊界保衛祖國的軍人,所以在編程的世界里,哨兵充當着簡化邊界條件處理的角色。
比較常見的應用是直接插入排序里的哨兵。
在直接插入排序里使用數組首位A[0]作為哨兵,這里的哨兵有兩個作用:
1、暫時存放待插入的元素和防止數組下標越界。
2、簡化了判斷上的表達:循環頭部的控制條件應為j>0與A[j]>t轉化成比較一次:A[j]>A[0]
再比如算法導論里介紹的一個加上了哨兵的雙向循環鏈表(書p238)。
在這個數據結構里,為了簡化對邊界條件的判斷與維護,單獨地生成一個結構對象與其他鏈表結點一致的結點,prev域指向表尾,next域指向表頭。
正因為next域指向表頭,在對鏈表處理的過程中可以省去頭指針,直接用對哨兵的引用來代替對頭指針的引用。
如圖所示:(圖自算法導論P238)
又比如掃雷游戲,每次點擊一個格子就要掃描相鄰的8個格子。當點擊到邊界的時候,相鄰不足8個格子,這時候就可以在設計游戲的時候為邊界外圈加上隱藏的一層格子。這樣就可以使所有的操作一致化,不需要對邊界的條件作出特殊的處理。
總結:
1、哨兵基本不能降低數據結構相關操作的漸近時間界,但其可以降低常數因子。
2、哨兵的設計可以使得代碼更簡潔,可以省去一些由於邊界環境不同而作出的特殊處理。
3、在某些情況下哨兵可以使得循環語句更緊湊,降低運行時間里n或者n²項的系數。
4、慎用:哨兵會占用額外的內存。當使用哨兵的開銷較大時,有可能會造成嚴重的浪費。