<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hant-TW">
	<id>https://wiki.zh-tw.ima.org.tw/w/index.php?action=history&amp;feed=atom&amp;title=%E5%89%8D%E5%93%A8%E7%AF%80%E9%BB%9E</id>
	<title>前哨節點 - 修訂紀錄</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.zh-tw.ima.org.tw/w/index.php?action=history&amp;feed=atom&amp;title=%E5%89%8D%E5%93%A8%E7%AF%80%E9%BB%9E"/>
	<link rel="alternate" type="text/html" href="https://wiki.zh-tw.ima.org.tw/w/index.php?title=%E5%89%8D%E5%93%A8%E7%AF%80%E9%BB%9E&amp;action=history"/>
	<updated>2026-07-01T16:02:06Z</updated>
	<subtitle>本 wiki 上此頁面的修訂紀錄</subtitle>
	<generator>MediaWiki 1.43.1</generator>
	<entry>
		<id>https://wiki.zh-tw.ima.org.tw/w/index.php?title=%E5%89%8D%E5%93%A8%E7%AF%80%E9%BB%9E&amp;diff=92&amp;oldid=prev</id>
		<title>TaiwanTonguesApiRobot：​從 JSON 檔案批量匯入</title>
		<link rel="alternate" type="text/html" href="https://wiki.zh-tw.ima.org.tw/w/index.php?title=%E5%89%8D%E5%93%A8%E7%AF%80%E9%BB%9E&amp;diff=92&amp;oldid=prev"/>
		<updated>2025-09-23T09:19:45Z</updated>

		<summary type="html">&lt;p&gt;從 JSON 檔案批量匯入&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新頁面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;在電腦程式設計中，哨兵節點（sentinel node）是一種特殊指定的節點，在鏈結串列和樹中用作遍歷路徑的終止符。此類節點不持有或引用該資料結構所管理的任何資料。&lt;br /&gt;
&lt;br /&gt;
==優點==&lt;br /&gt;
&lt;br /&gt;
哨兵節點被用來替代 `NULL` 作為路徑終止符，以獲得以下一個或多個好處：&lt;br /&gt;
* 略微提升操作速度&lt;br /&gt;
* 提升資料結構的穩健性（有爭議）&lt;br /&gt;
&lt;br /&gt;
==缺點==&lt;br /&gt;
* 略微增加記憶體用量，尤其是在鏈結串列很短時。&lt;br /&gt;
&lt;br /&gt;
== 範例 ==&lt;br /&gt;
&lt;br /&gt;
=== 在鏈結串列中搜尋 ===&lt;br /&gt;
以下是兩個用於在單向鏈結串列中查找給定搜尋鍵的子程式版本（以 C 程式語言實作）。第一個版本使用哨兵值 `NULL`，第二個版本使用（指向）哨兵節點 `Sentinel` 的指標，作為串列結尾的指示符。兩種子程式的單向鏈結串列資料結構宣告和結果都是相同的。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct sll_node {                          // 單向鏈結串列的一個節點&lt;br /&gt;
    struct sll_node *next;                 // 串列結尾指示符或 -&amp;gt; 下一個節點&lt;br /&gt;
    int key;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== 第一個版本，使用 NULL 作為串列結尾指示符 ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line highlight=&amp;quot;7,10&amp;quot;&amp;gt;&lt;br /&gt;
// 全域初始化&lt;br /&gt;
first = NULL;                              // 在首次插入前（未顯示）&lt;br /&gt;
&lt;br /&gt;
struct sll_node *Search(struct sll_node *first, int search_key) {&lt;br /&gt;
    struct sll_node *node;&lt;br /&gt;
    for (node = first;&lt;br /&gt;
        node != NULL;&lt;br /&gt;
        node = node-&amp;gt;next)&lt;br /&gt;
&lt;br /&gt;
        if (node-&amp;gt;key == search_key)&lt;br /&gt;
            return node;                   // 找到&lt;br /&gt;
&lt;br /&gt;
    // search_key 不包含在串列中：&lt;br /&gt;
    return NULL;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
`for` 迴圈的每次迭代包含兩個測試（黃色標示行）：&lt;br /&gt;
* `node != NULL;`&lt;br /&gt;
* `if (node-&amp;gt;key == search_key)`。&lt;br /&gt;
&lt;br /&gt;
==== 第二個版本，使用哨兵節點 ====&lt;br /&gt;
全域可用的指標 `sentinel` 指向特意準備的資料結構 `Sentinel`，並被用作串列結尾指示符。&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line&amp;gt;&lt;br /&gt;
// 全域變數&lt;br /&gt;
sll_node Sentinel, *sentinel = &amp;amp;Sentinel;&lt;br /&gt;
// 全域初始化&lt;br /&gt;
sentinel-&amp;gt;next = sentinel;&lt;br /&gt;
first = sentinel;                          // 在首次插入前（未顯示）&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
請注意，`sentinel` 指標必須始終保持在串列的末端。&lt;br /&gt;
這必須由插入和刪除函式來維護。然而，這與使用 NULL 指標所需的功夫大致相同。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; highlight=&amp;quot;6&amp;quot;&amp;gt;&lt;br /&gt;
struct sll_node *SearchWithSentinelnode(struct sll_node *first, int search_key) {&lt;br /&gt;
    struct sll_node *node;&lt;br /&gt;
    // 為搜尋準備「節點」Sentinel：&lt;br /&gt;
    sentinel-&amp;gt;key = search_key;&lt;br /&gt;
    for (node = first;&lt;br /&gt;
        node-&amp;gt;key != search_key;&lt;br /&gt;
        node = node-&amp;gt;next)&lt;br /&gt;
&lt;br /&gt;
    // 後續處理：&lt;br /&gt;
    if (node != sentinel)&lt;br /&gt;
        return node;                       // 找到&lt;br /&gt;
    // search_key 不包含在串列中：&lt;br /&gt;
    return NULL;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
`for` 迴圈的每次迭代只包含一個測試（黃色標示行）：&lt;br /&gt;
* `node-&amp;gt;key != search_key;`。&lt;br /&gt;
&lt;br /&gt;
==== Python 的環狀雙向鏈結串列實作 ====&lt;br /&gt;
鏈結串列的實作，特別是環狀雙向鏈結串列，可以透過使用哨兵節點來標記串列的開頭和結尾，從而顯著簡化。&lt;br /&gt;
&lt;br /&gt;
* 串列始於一個單一節點，即哨兵節點，其 `next` 和 `previous` 指標都指向自身。此條件可用於判斷串列是否為空。&lt;br /&gt;
* 在非空串列中，哨兵節點的 `next` 指標指向串列的頭部，而 `previous` 指標則指向串列的尾部。&lt;br /&gt;
&lt;br /&gt;
以下是 Python 的環狀雙向鏈結串列實作：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class Node:&lt;br /&gt;
    def __init__(self, data, next=None, prev=None):&lt;br /&gt;
        self.data = data&lt;br /&gt;
        self.next = next&lt;br /&gt;
        self.prev = prev&lt;br /&gt;
&lt;br /&gt;
    def __repr__(self) -&amp;gt; str:&lt;br /&gt;
        return f&amp;#039;Node(data={self.data})&amp;#039;&lt;br /&gt;
&lt;br /&gt;
class LinkedList:&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self._sentinel = Node(data=None)&lt;br /&gt;
        self._sentinel.next = self._sentinel&lt;br /&gt;
        self._sentinel.prev = self._sentinel&lt;br /&gt;
&lt;br /&gt;
    def pop_left(self) -&amp;gt; Node:&lt;br /&gt;
        return self.remove_by_ref(self._sentinel.next)&lt;br /&gt;
&lt;br /&gt;
    def pop(self) -&amp;gt; Node:&lt;br /&gt;
        return self.remove_by_ref(self._sentinel.prev)&lt;br /&gt;
&lt;br /&gt;
    def append_nodeleft(self, node):&lt;br /&gt;
        self.add_node(self._sentinel, node)&lt;br /&gt;
&lt;br /&gt;
    def append_node(self, node):&lt;br /&gt;
        self.add_node(self._sentinel.prev, node)&lt;br /&gt;
&lt;br /&gt;
    def append_left(self, data):&lt;br /&gt;
        node = Node(data=data)&lt;br /&gt;
        self.append_nodeleft(node)&lt;br /&gt;
&lt;br /&gt;
    def append(self, data):&lt;br /&gt;
        node = Node(data=data)&lt;br /&gt;
        self.append_node(node)&lt;br /&gt;
&lt;br /&gt;
    def remove_by_ref(self, node) -&amp;gt; Node:&lt;br /&gt;
        if node is self._sentinel:&lt;br /&gt;
            raise Exception(&amp;#039;Can never remove sentinel.&amp;#039;)&lt;br /&gt;
        node.prev.next = node.next&lt;br /&gt;
        node.next.prev = node.prev&lt;br /&gt;
        node.prev = None&lt;br /&gt;
        node.next = None&lt;br /&gt;
        return node&lt;br /&gt;
&lt;br /&gt;
    def add_node(self, curnode, newnode):&lt;br /&gt;
        newnode.next = curnode.next&lt;br /&gt;
        newnode.prev = curnode&lt;br /&gt;
        curnode.next.prev = newnode&lt;br /&gt;
        curnode.next = newnode&lt;br /&gt;
&lt;br /&gt;
    def search(self, value):&lt;br /&gt;
        self._sentinel.data = value&lt;br /&gt;
        node = self._sentinel.next&lt;br /&gt;
        while node.data != value:&lt;br /&gt;
            node = node.next&lt;br /&gt;
        self._sentinel.data = None&lt;br /&gt;
        if node is self._sentinel:&lt;br /&gt;
            return None&lt;br /&gt;
        return node&lt;br /&gt;
&lt;br /&gt;
    def __iter__(self):&lt;br /&gt;
        node = self._sentinel.next&lt;br /&gt;
        while node is not self._sentinel:&lt;br /&gt;
            yield node.data&lt;br /&gt;
            node = node.next&lt;br /&gt;
&lt;br /&gt;
    def reviter(self):&lt;br /&gt;
        node = self._sentinel.prev&lt;br /&gt;
        while node is not self._sentinel:&lt;br /&gt;
            yield node.data&lt;br /&gt;
            node = node.prev&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
請注意 `add_node()` 方法如何將會被新節點取代的節點作為參數 `curnode` 傳入。當在左側附加時，此節點是非空串列的頭部；而在右側附加時，則是尾部。但由於鏈結的設定方式會指回哨兵節點，因此這段程式碼對於空串列同樣有效，此時 `curnode` 會是哨兵節點。&lt;br /&gt;
&lt;br /&gt;
=== 在二元樹中搜尋 ===&lt;br /&gt;
一般宣告，類似於二元搜尋樹的文章：&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct bst_node {                     // 二元搜尋樹的一個節點&lt;br /&gt;
    struct bst_node *child[2];        // 每個：-&amp;gt;node 或 結尾路徑指示符&lt;br /&gt;
    int key;&lt;br /&gt;
&lt;br /&gt;
struct bst {                          // 二元搜尋樹&lt;br /&gt;
    struct bst_node *root;            // -&amp;gt;node 或 結尾路徑指示符&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
全域可用的指標 `sentinel` 指向單一特意準備的資料結構 `Sentinel = *sentinel`，用來指示子節點不存在。&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line highlight=&amp;quot;12&amp;quot;&amp;gt;&lt;br /&gt;
// 全域變數&lt;br /&gt;
bst_node Sentinel, *sentinel = &amp;amp;Sentinel;&lt;br /&gt;
// 全域初始化&lt;br /&gt;
Sentinel.child[0] = Sentinel.child[1] = sentinel;&lt;br /&gt;
&lt;br /&gt;
BST-&amp;gt;root = sentinel;                 // 在首次插入前（未顯示）&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
請注意，`sentinel` 指標必須始終代表樹中的每一個葉節點。&lt;br /&gt;
這必須由插入和刪除函式來維護。然而，這與使用 NULL 指標所需的功夫大致相同。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;11&amp;quot;&amp;gt;&lt;br /&gt;
struct bst_node *SearchWithSentinelnode(struct bst *bst, int search_key) {&lt;br /&gt;
    struct bst_node *node;&lt;br /&gt;
    // 為搜尋準備「節點」Sentinel：&lt;br /&gt;
    sentinel-&amp;gt;key = search_key;&lt;br /&gt;
 &lt;br /&gt;
    for (node = bst-&amp;gt;root;;) {&lt;br /&gt;
        if (search_key == node-&amp;gt;key)&lt;br /&gt;
            break;&lt;br /&gt;
        if search_key &amp;lt; node-&amp;gt;key:&lt;br /&gt;
            node = node-&amp;gt;child[0];    // 向左&lt;br /&gt;
        else&lt;br /&gt;
            node = node-&amp;gt;child[1];    // 向右&lt;br /&gt;
&lt;br /&gt;
    // 後續處理：&lt;br /&gt;
    if (node != sentinel)&lt;br /&gt;
        return node;                  // 找到&lt;br /&gt;
    // search_key 不包含在樹中：&lt;br /&gt;
    return NULL;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;備註：&lt;br /&gt;
# 使用 `SearchWithSentinelnode` 會使搜尋失去其唯讀屬性。這意味著在有並行處理的應用程式中，它必須受到互斥鎖（mutex）的保護，這種額外開銷通常會超過使用哨兵節點所節省的效益。&lt;br /&gt;
# `SearchWithSentinelnode` 不支援處理重複值。&lt;br /&gt;
# 必須有且僅有一個「節點」用作哨兵，但可以有極多個指標指向它。&lt;br /&gt;
&lt;br /&gt;
== 參見 ==&lt;br /&gt;
* 金絲雀值 (Canary value)&lt;br /&gt;
* 開羅的大象 (Elephant in Cairo)&lt;br /&gt;
* 衛述句 (電腦科學) (Guard (computer science))，一個布林表達式，若程式要繼續在該分支中執行，則此表達式必須為真&lt;br /&gt;
* 魔法數字 (程式設計) (Magic number (programming))&lt;br /&gt;
* 魔法字串 (Magic string)&lt;br /&gt;
* 空物件模式 (Null object pattern)&lt;br /&gt;
* 半謂詞問題 (Semipredicate problem)&lt;br /&gt;
* 哨兵值 (Sentinel value)&lt;br /&gt;
* 時間格式化與儲存錯誤 (Time formatting and storage bugs)&lt;br /&gt;
&lt;br /&gt;
==參考資料==&lt;br /&gt;
&lt;br /&gt;
[[分類: 待校正]]&lt;/div&gt;</summary>
		<author><name>TaiwanTonguesApiRobot</name></author>
	</entry>
</feed>