問題解決のアイデア
アイデア 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; // 返回头节点
}
};
このセクションの終わり