[古典問題] 二分探索木と二重連結リスト

二分探索木と二重連結リストへのリンク

問題解決のアイデア

アイデア 1: 順序通りにトラバーサルし、ノードをベクトルに入れ、リンク関係を変更する これは簡単に思いつき、解決できますが、明らかに質問の意味を満たしていません。
ここに画像の説明を挿入

アイデア 2:
この質問では、新しいノードを作成せずにポインタを調整するだけで、二分探索木をソート済み二重連結リストに変換する必要があります。
二分探索木の特徴は、左側の部分木の値がルートノードよりも小さく、右側の部分木の値がルートノードよりも大きく、in-オーダートラバーサル。
したがって、インオーダートラバーサルの順序を使用して、各ノードの左ポインターを前のノードにポイントし、各ノードの右ポインターを次のノードにポイントして、二重にリンクされたリストを形成できます。
前のノード、最初は nullptr を記録するには、変数 prev を使用する必要があります。次に、バイナリ ツリーを再帰的にトラバースし、ノードにアクセスするたびに、そのノードへのポインターを変更して prev を変更し、prev を現在のノードに更新します。
最後に、ルート ノードから開始して左に移動し、双方向リンク リストの先頭ノードである左端のノードを見つけて、戻ります。
ここに画像の説明を挿入

栗を取ります:
次のような二分探索木があるとします:

       10
      /  \
    6    14
    / \   / \
   4   8 12 16

最初に prev を空に初期化し、ルート ノードから二分木を再帰的にトラバースします。

最初に、左側のサブツリーを持たないノード 4 にトラバースするため、その左側のポインターを prev (この時点では空) を指すように直接変更し、prev を 4 に更新します。

次に、左側のサブツリーを持つノード 6 に戻ります。そのため、その左側のポインターを prev (現在は 4) を指すように変更し、4 の右側のポインターを 6 を指すように変更します。次に、prev を 6 に更新します。

次に、左側のサブツリーを持たないノード 8 にトラバースするため、その左側のポインターを変更して prev (この時点では 6) を指し、6 の右側のポインターを 8 にポイントします。次に、prev を 8 に更新します。

次に、左側のサブツリーを持つノード 10 に戻るので、その左側のポインターを変更して、prev (現在は 8) を指すようにし、8 の右側のポインターを 10 に指すようにします。次に、prev を 10 に更新します。

次に、左サブツリーを持たないノード 12 にトラバースするため、その左ポインターを変更して prev (この時点では 10) を指し、10 の右ポインターを 12 にポイントします。次に、prev を 12 に更新します。

次に、左側のサブツリーを持つノード 14 に戻ります。そのため、その左側のポインターを prev (この時点では 12) を指すように変更し、12 の右側のポインターを 14 を指すように変更します。次に、prev を 14 に更新します。

次に、左側のサブツリーを持たないノード 16 にトラバースします。そのため、左側のポインターを変更して prev (この時点では 14) を指すようにし、14 の右側のポインターを 16 に変更します。次に、prev を 16 に更新します。

最後に、ルート ノード 10 に戻り、そこから左に移動して、双方向リンク リストの先頭ノードである左端のノード 4 を見つけます。4を返すだけです。

この時点で、二分探索木は次の二重連結リストに変換されています。

NULL <-> 4 <-> 6 <-> 8 <-> 10 <-> 12 <-> 14 <-> 16 <-> NULL
ここに画像の説明を挿入

コード - コメントを追加

/*
struct TreeNode {
    int val; // 节点的值
    struct TreeNode *left; // 左子节点的指针
    struct TreeNode *right; // 右子节点的指针
    TreeNode(int x) : // 构造函数,初始化节点的值和子节点指针
            val(x), left(NULL), right(NULL) {
    }
};*/
class Solution {
    
    
  public:
    void InOrderConvert(TreeNode* cur, TreeNode*& prev) {
    
    
        if (cur == nullptr) // 如果当前节点为空,直接返回
            return;
        InOrderConvert(cur->left, prev); // 递归遍历左子树
        //这里cur出现的顺序就是中序
        cur->left = prev; // 将当前节点的左指针指向前一个节点
        if (prev) // 如果前一个节点不为空,将其右指针指向当前节点
            prev->right = cur;
        prev = cur; // 更新前一个节点为当前节点

        InOrderConvert(cur->right, prev); // 递归遍历右子树
    }
    TreeNode* Convert(TreeNode* pRootOfTree) {
    
    
        TreeNode* prev = nullptr; // 初始化前一个节点为空
        InOrderConvert(pRootOfTree,
                       prev); // 调用辅助函数,中序遍历二叉树,并修改指针

        TreeNode* head = pRootOfTree; // 初始化头节点为根节点
        while (head &&
                head->left) {
    
     // 循环找到最左边的节点,即双向链表的头节点
            head = head->left;
        }


        return head; // 返回头节点
    }
};

このセクションの終わり

おすすめ

転載: blog.csdn.net/weixin_62676865/article/details/130414227