Java におけるバイナリ ツリーの深さ優先トラバースの詳細な説明
過去 2 日間、私は二分木に関連するアルゴリズムの質問をし、勉強ノートをとっていました。 (バイナリ ツリーの作り方さえ知りませんか? あなたは本当に熟練していないので、日常業務でバイナリ ツリーに関連するアルゴリズムやデータ構造を書く必要はありません。私はそれが得意なので、書かなければなりません。もっと勉強してください!)
定義
まず Wikipedia の説明を見てみましょう: コンピュータ サイエンスでは、Binary Tree (英語) : 二分木) は、最大 2 つの分岐を持つノードです (つまり、分岐次数が 2 を超えるノードを持つ木構造は存在しません)。通常、ブランチは「左サブツリー」または「右サブツリー」と呼ばれます。二分木の枝には左と右の順序があり、自由に逆転することはできません。
バイナリ ツリー自体によって定義される特性により、バイナリ ツリーは高度なローカル再現性を備えているため、バイナリ ツリーを深さ優先で走査する場合、通常は再帰的な方法で実装されます。この方法は非常に簡潔で美しく、理解しやすいです。
深さ優先トラバーサル
一般に、バイナリ ツリーの深さ優先トラバーサルには、最も一般的な次の 3 つの順序トラバーサルがあります。ミッドオーダーとポストオーダー。
プレオーダーの走査順序は次のとおりです: ルート ノードにアクセス -> 左のサブツリーを走査 -> 右のサブツリーを走査
中間オーダーの走査順序は次のとおりです:左のサブツリー -> ルート ノードにアクセス -> 右のサブツリーをトラバース
事後探索順序は次のとおりです: 左のサブツリーをトラバース -> 右のサブツリーをトラバース -> ルート ノードにアクセス
注 ここでの左側と右側はノードではなくサブツリー全体です。ツリー全体を走査する必要があるため、各走査はリーフ ノードまでこの順序で実行されます。
たとえば、次のようなバイナリ ツリーがあるとします。
プレオーダー トラバーサルによって得られるシーケンスは、A - B - C - D - E
です。中次トラバーサルで得られるシーケンスは B - A - D - C - E
ポストオーダー トラバーサルで得られるシーケンスは B - D - E - C - A
We事前順序トラバーサルを使用します (人間の再帰を使用することは強く推奨されません。少なくとも私の脳は 3 つのレベルを処理できません...):
再帰の最初のレベル:
最初にルート ノードにアクセスして、ルート ノードが出力 A になるようにし、次に左側のサブツリー (L1) をトラバースし、次に右側のサブツリー (R1) をトラバースします。
第 2 レベルの再帰:
For L1、ルート ノードが最初にアクセスされるため、この時点での出力はルート ノード B となり、B の左右のサブツリーが空であることがわかり、再帰が終了します。
R1 の場合、最初にルート ノードを作成するため、この時点ではルート ノード C を出力し、次に左側のサブツリー (L2) をトラバースし、次に右側のサブツリー (R2) をトラバースします。
再帰の 3 番目のレベル:
L2 の場合、最初にルート ノードを訪問するため、この時点のルート ノード D が出力され、D の左右のサブツリーが空になり、再帰が終了します;
R2 の場合、最初にルート ノードが訪問されるため、この時点のルート ノード E が出力され、E の左右のサブツリーが空であることがわかり、再帰が終了します。前中後注文の特徴
前中後注文の定義によれば、次のような特徴を見つけるのは難しくありません。 • 事前順序の最初のものはルート ノードである必要があり、事後順序の最後のものはルート ノードである必要があります
• 各種類の左側のサブツリーと右側のサブツリーの分布は規則的です。
• 各サブツリーについて、上記の 2 つのルールに従うツリー
#これらの特性は、定義における順序の表現です。さまざまな導出
バイナリ ツリー トラバーサルに関する最も基本的なアルゴリズムの質問をいくつか示します。 • バイナリが与えられたとします。ツリー、その前/中/後順序走査のシーケンスを取得します;
• 前順序と中間順序に基づいた後順序の導出 (またはバイナリ ツリー全体の導出);
• 事後順序と順序に基づいて事前順序を推定 (またはバイナリ ツリー全体を推定);
バイナリ ツリーのトラバーサルでは、前述したように、通常は再帰が使用されます。再帰については、直接適用できるテンプレートがあります:
public void recur(int level, int param) { // terminator if (level > MAX_LEVEL) { // process result return; } // process current logic process(level, param); // drill down recur(level+1, newParam); // restore current status }
これは、私が過去 2 日間に視聴したアルゴリズム トレーニング キャンプで、チャオ兄弟 (秦超) が言及した、より実践的なヒントです (このテンプレートは特に上記の 3 つの手順に従ってください (必要なローカル変数がある場合は、手順 4 で解放または追加の処理が行われます)。より順序立てて再帰的なコードを書くことができます。
プレオーダーとミッドオーダーに基づいてポストオーダーを導出する例を次に示します:
最初に 2 つのシーケンスを初期化します:
int[] preSequence = {1, 2, 3, 4, 5, 6, 7, 8, 9}; int[] inSequence = {2, 3, 1, 6, 7, 8, 5, 9, 4};
上記のいくつかの機能を通じて, 最小の繰り返し部分問題が見つかります。各再帰
は、次の
最初のノード値に従ってノード値が中間に位置するインデックス i と一致します。前のシーケンスを使用して、それぞれ左と右のサブツリーに対応するインデックス i の前部分と後ろ部分を取得し、次に左と右の 2 つのサブツリーをそれぞれ走査して、現在の事前順序の最初のノード値を出力します。ルートノードです。
トップダウン プログラミング手法に従って、最初に次の初期再帰呼び出しを作成できます: List<Integer> result = new ArrayList<>();
preAndInToPost(0, 0, preSequence.length, preSequence, inSequence, result);
2 番目のパラメータは順序シーケンスの最初の要素のインデックスを表します;
3 番目のパラメータはシーケンスの長さを表します;
第四个参数表示前序序列;
第五个参数表示后序序列;
第六个参数用于保存结果;
先来考虑终止条件是什么,也就是什么时候结束递归,当我们的根结点为空的时候终止,对应这里就是序列长度为零的时候。
if (length == 0) { return; }
接着考虑处理逻辑,也就是找到索引 i:
int i = 0; while (inSequence[inIndex + i] != preSequence[preIndex]) { i++; }
然后开始向下递归:
preAndInToPost(preIndex + 1, inIndex, i, preSequence, inSequence, result); preAndInToPost(preIndex + i + 1, inIndex + i + 1, length - i - 1, preSequence, inSequence, result); result.add(preSequence[preIndex]);
因为推导的是后序序列,所以顺序如上,添加根结点的操作是在最后的。前三个参数如何得出来的呢,我们走一下第一次遍历就可以得出来。
前序序列的第一个结点 1 在中序序列中的索引为 2,此时
左子树的中序系列起始索引为总序列的第 1 个索引,长度为 2;
左子树的前序序列起始索引为总序列的第 2 个索引,长度为 2;
右子树的中序系列起始索引为总序列的第 3 个索引,长度为 length - 3;
右子树的前序序列起始索引为总序列的第 3 个索引,长度为 length - 3;
完整代码如下:
/** * 根据前序和中序推导后序 * * @param preIndex 前序索引 * @param inIndex 中序索引 * @param length 序列长度 * @param preSequence 前序序列 * @param inSequence 中序序列 * @param result 结果序列 */ private void preAndInToPost(int preIndex, int inIndex, int length, int[] preSequence, int[] inSequence, List<Integer> result) { if (length == 0) { return; } int i = 0; while (inSequence[inIndex + i] != preSequence[preIndex]) { i++; } preAndInToPost(preIndex + 1, inIndex, i, preSequence, inSequence, result); preAndInToPost(preIndex + i + 1, inIndex + i + 1, length - i - 1, preSequence, inSequence, result); result.add(preSequence[preIndex]); }
参考链接
• 维基百科 - 二叉树(https://zh.wikipedia.org/wiki/%E4%BA%8C%E5%8F%89%E6%A0%91)
推荐教程:《java教程》
以上がJava におけるバイナリ ツリーの深さ優先トラバースの詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











この記事では、Java Spring の面接で最もよく聞かれる質問とその詳細な回答をまとめました。面接を突破できるように。

Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

Java での日付までのタイムスタンプに関するガイド。ここでは、Java でタイムスタンプを日付に変換する方法とその概要について、例とともに説明します。

カプセルは3次元の幾何学的図形で、両端にシリンダーと半球で構成されています。カプセルの体積は、シリンダーの体積と両端に半球の体積を追加することで計算できます。このチュートリアルでは、さまざまな方法を使用して、Javaの特定のカプセルの体積を計算する方法について説明します。 カプセルボリュームフォーミュラ カプセルボリュームの式は次のとおりです。 カプセル体積=円筒形の体積2つの半球体積 で、 R:半球の半径。 H:シリンダーの高さ(半球を除く)。 例1 入力 RADIUS = 5ユニット 高さ= 10単位 出力 ボリューム= 1570.8立方ユニット 説明する 式を使用してボリュームを計算します。 ボリューム=π×R2×H(4

PHPは、サーバー側で広く使用されているスクリプト言語で、特にWeb開発に適しています。 1.PHPは、HTMLを埋め込み、HTTP要求と応答を処理し、さまざまなデータベースをサポートできます。 2.PHPは、ダイナミックWebコンテンツ、プロセスフォームデータ、アクセスデータベースなどを生成するために使用され、強力なコミュニティサポートとオープンソースリソースを備えています。 3。PHPは解釈された言語であり、実行プロセスには語彙分析、文法分析、編集、実行が含まれます。 4.PHPは、ユーザー登録システムなどの高度なアプリケーションについてMySQLと組み合わせることができます。 5。PHPをデバッグするときは、error_reporting()やvar_dump()などの関数を使用できます。 6. PHPコードを最適化して、キャッシュメカニズムを使用し、データベースクエリを最適化し、組み込み関数を使用します。 7

PHP and Python each have their own advantages, and the choice should be based on project requirements. 1.PHPは、シンプルな構文と高い実行効率を備えたWeb開発に適しています。 2。Pythonは、簡潔な構文とリッチライブラリを備えたデータサイエンスと機械学習に適しています。

Java は、初心者と経験豊富な開発者の両方が学習できる人気のあるプログラミング言語です。このチュートリアルは基本的な概念から始まり、高度なトピックに進みます。 Java Development Kit をインストールしたら、簡単な「Hello, World!」プログラムを作成してプログラミングを練習できます。コードを理解したら、コマンド プロンプトを使用してプログラムをコンパイルして実行すると、コンソールに「Hello, World!」と出力されます。 Java の学習はプログラミングの旅の始まりであり、習熟が深まるにつれて、より複雑なアプリケーションを作成できるようになります。

Spring Bootは、Java開発に革命をもたらす堅牢でスケーラブルな、生産対応のJavaアプリケーションの作成を簡素化します。 スプリングエコシステムに固有の「構成に関する慣習」アプローチは、手動のセットアップを最小化します。
