記事ディレクトリ
二分木の紹介
多くの概念は以前のブログで見ることができます:バイナリ ツリー トラバーサル_Tatakai!!! のブログ - CSDN ブログ_バイナリ ツリー トラバーサル
二分木トラバーサル
- Preorder トラバーサル: ルート周辺
- 順序通りのトラバーサル: 左ルート右
- ポストオーダー トラバーサル: 左右のルート
- 層順トラバーサル: BFS
実現方法:
- 再帰
- 非再帰 (スタック)
1. 再帰的な実装
事前注文トラバーサル
コード
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
dfs(root, res);
return res;
}
/**
前:根左右
*/
public static void dfs(TreeNode root, List<Integer> res){
if(root == null){
// 叶子节点
return ;
}
res.add(root.val);
dfs(root.left, res);
dfs(root.right, res);
}
}
順序通りのトラバーサル
コード
class Solution {
List<Integer> ans = new ArrayList<>();
public List<Integer> inorderTraversal(TreeNode root) {
dfs(root);
return ans;
}
// 中序遍历
public void dfs(TreeNode root){
// 结束条件
if(root == null) return;
dfs(root.left);
ans.add(root.val);
dfs(root.right);
}
}
ポスト オーダー トラバーサル
コード
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
dfs(root, res);
return res;
}
/**
后:左右根
*/
public static void dfs(TreeNode root, List<Integer> res){
if(root == null){
// 叶子节点
return ;
}
dfs(root.left, res);
dfs(root.right, res);
res.add(root.val);
}
}
2.反復実装
事前注文トラバーサル
アイデア: スタックを使用して、事前注文トラバーサル プロセスをシミュレートします。これは、スタック (先入れ後出し) であるためです。
- ルート ノードの最初のスタック
- スタックが空でない場合、最初に右の子がスタックにプッシュされ、次に左の子がスタックにプッシュされます (後入れ先出し)。
スタック シミュレーション: root left-right -> root right-left
コード
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root == null){
return res;
}
// 前:根左右
Stack<TreeNode> stk = new Stack<>();
stk.push(root);
while(!stk.empty()){
TreeNode node = stk.pop();
res.add(node.val);
// 右儿子先入栈
if(node.right != null){
stk.push(node.right);
}
// 做儿子入队
if(node.left != null){
stk.push(node.left);
}
}
return res;
}
}
ポスト オーダー トラバーサル
上記の反復法は、事前順序トラバーサルを取得します: 根左右
—> 反復プロセスは、根右左
の順序でトラバースおよび挿入し、最終的に事前順序トラバーサル ( 根左右
)の結果を取得します。
そして、事後順序トラバーサルは であり左右根
、その反転は であり、このツリーの根右左
順序を取得する方法を見つけるだけでよく根左右
、それを反転して後続のトラバーサルの結果を取得します! では、根右左
トラバーサル順序の結果を取得するにはどうすればよいでしょうか。——予約注文トラバーサル反復の取得プロセスを模倣します。
根左右
⇒重ね順で根右左
入手- 次に
根右左
—>積み上げ順で根左
取得
コード
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
if(root == null){
return list;
}
Stack<TreeNode> stk = new Stack<>();
stk.push(root);
// 先获取根右左的遍历次序结果
while(!stk.empty()){
TreeNode node = stk.pop();
list.add(node.val);
if(node.left != null){
stk.push(node.left);
}
if(node.right != null){
stk.push(node.right);
}
}
// 翻转得到后序遍历结果
Collections.reverse(list);
return list;
}
}
順序通りのトラバーサル
真ん中:左根右
反復法:
-
ルート ノードへのポインタを定義し、ノードが空でないかスタックが空でない場合はループを続けます
- ポインターが空でない場合、現在のノードがスタックにプッシュされ、左の子がループされ、
p指针
空を指すまで ------- (左递归
プロセスのシミュレーション) - ポインターが空の場合、スタックの一番上の要素がポップアウトされ、ポインターはスタックからポップアウトされたノードを指し、
p = stk.pop()
ノード値がval
追加されますans
(ルートをたどるプロセスをシミュレートし、回答を記録します)。ポインターはp
現在のノードの右の子に移動し (走査プロセスの右の子をシミュレート)、次回に備えます (左ルート右)
- ポインターが空でない場合、現在のノードがスタックにプッシュされ、左の子がループされ、
-
というように、スタックが空になるまで。
コード
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
TreeNode p = root;
Stack<TreeNode> stk = new Stack<>();
List<Integer> ans = new ArrayList<>();
while(p != null || !stk.empty()){
while(p != null){
// 模拟一直左递归的过程
stk.push(p);
p = p.left;
}
// p走到了空
// 根
p = stk.pop();
ans.add(p.val);
// 右
p = p.right;
}
return ans;
}
}