基礎が不十分だったので、忘れないようにいくつかの問題形式を記録しました。
1. バイナリツリーの順序トラバーサル
このトラバーサル メソッドについては、ブログで多くの説明を検索できます。ここでは主にコードの実装を記録します。例として次のバイナリ ツリーを取り上げます。
結果は次のようになります。
2. 反復法
2.1 トラバーサルプロセス
ここで一時的なスタックを借用します (処理後の最初のアクセス) 対応するルート ノードと左のサブツリーに対応するノードを格納します. ノードはスタックにプッシュされます. 最後に訪問したルート ノードの左のサブツリー ノードが空の場合,対応する要素がスタックの最上位から取得され、操作前にその右のサブツリー ノードにアクセスして、左と右のサブツリーがあるかどうかが判断されます。
-
ルート ノード (23) から開始して、curr は元のルート ノードを指し始めます。
-
ルート ノード (23) を指す要素がスタックにプッシュされます (ルート ノードは後で処理されることが多いため、最初にスタックの一番下に置きます)。
-
現在のノードの左側のサブツリー ノード (34) を見つけます (curr=curr.left)。
-
現在移動されている curr (34 を指している) が空でない場合は、スタックにプッシュします。
-
現在のノードの左側の子ノードを探し続けます (34) (方法は前のノードと同じです。空でない場合はスタックにプッシュします)。
-
左のサブツリー ノードが空になるまで (つまり、図に示されている 77 に対応するノードの左のサブノードが空になる)、
この時点で対応する最上位の要素を取得し、ノードに左のサブツリーがないことを示し、順序をトラバースします。順序に従って左と右の順、左 サブツリーは空であり、この時点でルート ノード要素を読み取る必要があります (つまり、スタックの対応する最上位要素が取り出されます)。ここで 77 は、最初に通過するノードです。順番に
-
77 を訪問すると、右側のサブツリー ノードに対応します。
それが空の場合、このノードは右側のサブツリーに対応しないことを意味するため、対応する右側のノードにアクセスする必要はありません。これまでのところ、ルート ノードとして 77 を持つ左側のサブツリーは次のようになります
。訪問されました -
77 を左の子ノードとしてルート ノード 99 にアクセスします (スタックから対応するルート ノードを取得します。スタックの最上位要素は 99 です)。スタックの最上位要素にアクセスした後、すぐに右の
サブツリーにアクセスする必要があります。
-
99 をルート ノードとして右のサブツリーにアクセスします。空でない場合は、右のサブツリーのルート ノードとしてスタックにプッシュします。
-
90 をルート ノードとする右サブツリーに左の子ノードがあるかどうかを問い合わせます。90 をルート
ノードとする右のサブツリーに左の子ノードがある場合、方法は上記と同じです。
左の子ノードがない場合は、次に、スタック ルート ノードの 90 を取り出します。
-
90をルートノードとするサブツリーに右側のサブツリーがあるかどうかを問い合わせます
。このとき、90をルートノードとするサブツリーの右側のサブツリーノードは空であり、スタックに格納されている対応するルートノード要素にさらにアクセスします。 -
スタックの最上位要素 (この時点では 34 に対応) の読み取りを続けます。この時点で
、34 をルート ノードとして持つ左側のサブツリーの処理が終了し、ルート ノード 34 も読み込まれています。 34 に対応する右側のサブツリー。 -
ルート ノードとして 34 を持つ右のサブツリーを読み取ります。
ルート ノードとして 34 を持つ右のサブツリーは空であり、ルート ノードとして 34 を持つサブツリーが走査されています。スタック内の要素の処理を続けます
。 -
スタック内の要素の読み取りを続けます (この時点では 23)。
この時点で、バイナリ ツリー全体の左側のサブツリーが走査され、次に対応する右側のサブツリーが走査されます。 -
右のサブツリーのルート ノードをトラバースします (ルート ノード 23 は、右のサブツリーのルート ノードに対応しますが空ではありません。トラバースを続行し、最初に最初のルート ノード 21 をトラバースして、それをスタックにプッシュします)。
-
最初にルート ノードとして 21 を使用して左側のサブツリーのトラバースを続けます。空でない場合は、スタックへのプッシュを続けます (45)
-
空を指す左側のサブツリー
(45 の左側の子ノード) が見つかるまで左に移動し続け、スタックの最上位要素の処理を開始し、スタックの最上位要素を読み取ります。
-
ルート ノードとして 45 を持つ左側のサブツリーに右側の子ノードがあるかどうかを問い合わせます。
ある場合は、それをスタックにプッシュします。次に左側の子ノードがあるかどうかを問い合わせます。
ない場合は、ルート ノードとして 45 を持つサブツリーであることを意味します訪問されており、最上位要素の処理を続行します
-
21 をルート ノードとして右のサブツリーの状況を観察します。curr=curr.right の場合、
右のサブツリーのルート ノードが空 (60) でない場合は、それをスタックにプッシュします。
-
60 をルート ノードとして右側のサブツリーに左右のノードがあるかどうかを確認します。
左側の子ノードがある場合はトラバースを続行します。
左側の子ノードがない場合は、最上位の要素 (60) を取り出してトラバースを開始します。右のサブツリー。
右側の子ノードが空でない場合は、それをスタックにプッシュして走査を続行します。
右側の子ノードが空でスタックも空の場合、順序どおりの走査全体が終了します。
2.2 コードの実装
コードの前の記述は Likou の内容を直接コピーしています. この関数の主な考え方は
ルート ノードからバイナリ ツリーをたどることです. ルート ノードが空の場合は空のリストを直接返します.
次は通常の処理(全体の処理は上記のトラバース処理と同じ)
- 2 つの新しいリストを作成します。1 つはスタックの最上位要素を格納するスタックとして、もう 1 つは最終的な走査結果を格納します。
- Curr はルート ノードを指し始めます
- トラバーサルの終了条件は、現在のポインタが空で、スタックに要素が存在しないことです (ここでは while ループ条件)。
- ルート ノードをスタックにプッシュし、ノード ポインタを左に移動します。
- 左シフト ノード ポインタが空の場合は、このノードをルート ノードとするサブツリーに左の子ノードがなく、走査順序が左、ルート、右、次に左が空で、順序どおりの走査が直接行われることを意味します。スタックの最上位要素 (ルート ノードの値) を読み取り、ポインタもルート ノードを指し、2 番目の while ループから抜け出します。
- 前のステップでルート ノードがサブツリーである右側の子ノードをクエリし、ポインタを移動して、上記の走査を繰り返し続けます (最初の while ループに入ります)。
- ポインターが空を指し、スタックに要素がなくなるまで、順序どおりの走査を終了します。
2.2.1 パイソン
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
if not root:
return []
res, stack = list(), list()
curr = root
while curr or len(stack): # 指针为空且栈中元素为空时结束循环
while curr: # 当前指针不为空,推入根节点
stack.append(curr)
curr = curr.left
# 左子节点为空,则读取栈顶元素对应的根节点
node = stack.pop()
res.append(node.val)
# 读取右子树
curr = node.right
return res
ここでの使用例は、
入力:[1,null,2,3]
出力:[1,3,2]
ここで、最初のルート ノードを出力します。
(TreeNode{val: 1, left: None, right: TreeNode{val: 2, left: TreeNode{val: 3, left: None, right: None}, right: None}}, 'root')
2.2.2 JavaScript
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {
TreeNode} root
* @return {
number[]}
*/
var inorderTraversal = function(root) {
if (!root) return []
const stack = [], res = []
let curr = root
let node
while (!(!stack.length && !curr)) {
// 指针为空且栈中无元素时,结束循环
// while (stack.length || curr) {
while (curr) {
// 指针不为空
stack.push(curr)
curr = curr.left
}
node = stack.pop()
res.push(node.val)
curr = node.right
}
return res
};
3. 再帰的方法
3.1 トラバーサルプロセス
-
バイナリ ツリーを分割する主なアイデア
は、完全なバイナリ ツリーを左のサブツリー、ルート ノード、および右のサブツリーに分割し、
さらに分割し続けることです。
最も左のサブツリーに空の左の子ノードがある場合、再帰が終了します。 -
さらに小さいサブツリーから順に訪問
-
インオーダー
トラバーサル = 左サブツリーのインオーダートラバーサル + ルートノード + 右サブツリーのインオーダートラバーサル
3.2 コードの実装
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {
TreeNode} root
* @return {
number[]}
*/
var inorderTraversal = function(root) {
if (!root) return []
const inorder = (node, res) => {
if (!node) return
inorder(node.left, res)
res.push(node.val)
inorder(node.right, res)
}
const res = []
inorder(root, res)
return res
};