簡體   English   中英

std::map 迭代器如何工作?

[英]How does the std::map iterator work?

C++ STL 類 std::map 使用二叉樹實現 O(log(n)) 查找。 但是對於樹,迭代器的工作方式並不是很明顯。 ++ 運算符在樹結構中的實際含義是什么? 雖然“下一個元素”的概念在數組中有一個明顯的實現,但對我來說它在樹中並不那么明顯。 如何實現樹迭代器?

對於中序遍歷(可能也適用於其他人),如果您的節點中有父指針,則可以進行非遞歸遍歷。 應該可以只在迭代器中存儲兩個指針:您需要指示您所在的位置,並且您可能(我現在不做研究)需要諸如“前一個”指針之類的東西,以便您可以弄清楚您當前的移動方向(即我需要進入左子樹,還是剛從它回來)。

如果我們剛剛進入節點,“上一個”可能類似於“父”; “left”如果我們從左子樹返回,“right”如果我們從右子樹返回,“self”如果我們返回的最后一個節點是我們自己的。

我想添加我的兩美分作為評論,但由於我無法添加,我將不得不添加一個答案。 我一直在谷歌搜索並且感到沮喪,因為我找到的所有答案(這些除外)都假定了一個堆棧或其他一些可變大小的數據結構。 我確實找到了一些代碼 它表明它可以在沒有堆棧的情況下完成,但我發現它很難遵循,因此決定從第一原則解決問題。

首先要注意的是,該算法是“左貪婪”的。 因此,當我們從根開始時,我們會立即盡可能地向左移動,因為最左邊的節點是我們首先需要的節點。 這意味着我們永遠不需要考慮左子樹。 它已經被迭代了。

迭代順序為左子樹、節點、右子樹。 因此,如果我們位於一個給定的節點,我們就知道它的左子樹和節點本身已經被訪問過,接下來我們應該訪問右子樹,如果有的話,盡可能向左走。

否則,我們必須上樹。 如果我們從一個左孩子到它的父母,那么接下來是父母。 (之后我們將訪問它的右子樹,正如已經介紹的那樣。)

最后一種情況是當我們從一個右孩子到它的父母時。 父母已經被訪問過,所以我們必須再次上去。 事實上,我們必須繼續向上,直到到達根或樹,或者發現自己從左子節點移動到父節點。 正如我們已經看到的,在這種情況下,父節點是下一個節點。 (根可能由空指針指示,如在我的代碼中,或一些特殊的哨兵節點。)

以下代碼可以很容易地適應 STL 風格的迭代器

// Go as far left from this node as you can.
// i.e. find the minimum node in this subtree
Node* Leftmost(Node* node)
{
    if (node == nullptr)
        return nullptr;
    while (node->left != nullptr)
        node = node->left;
    return node;
}

// Start iterating from a root node
Node* First(Node* root)
{
    return Leftmost(root);
}

// The iteration is current at node.  Return the next node
// in value order.
Node* Next(Node* node)
{
    // Make sure that the caller hasn't failed to stop.
    assert(node != nullptr);

    // If we have a right subtree we must iterate over it,
    // starting at its leftmost (minimal) node.

    if (node->right != nullptr)
        return Leftmost(node->right);
    
    // Otherwise we must go up the tree

    Node* parent = node->parent;
    if (parent == nullptr)
        return nullptr;

    // A node comes immediately after its left subtree

    if (node == parent->left)
        return parent;

    // This must be the right subtree!
    assert(node == parent->right);

    // In which case we need to go up again, looking for a node that is
    // its parent's left child.

    while (parent != nullptr && node != parent->left)
    {
        node = parent;
        parent = node->parent;
    }

    // We should be at a left child!
    assert(parent == nullptr || node == parent->left);

    // And, as we know, a node comes immediately after its left subtree

    return parent;
}

考慮映射中不小於當前元素但也不是當前元素的所有元素的集合。 “下一個元素”是該元素集合中小於該集合中所有其他元素的元素。

要使用地圖,您必須擁有鑰匙。 並且該鍵必須實現“小於”操作。 這決定了映射的形成方式,從而使查找、添加、刪除、遞增和遞減操作高效。

通常地圖內部使用某種樹。

stl_tree.h中 map iterator operator++ watch 的標准實現:

_Self&
operator++() _GLIBCXX_NOEXCEPT
{
_M_node = _Rb_tree_increment(_M_node);
return *this;
}

_Rb_tree_increment實現在這里討論

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM