JavaScript 初心者のための二分探索木アルゴリズムのチュートリアル

JavaScript 初心者のための二分探索木アルゴリズムのチュートリアル

この記事では、コーディング面接の前に学ぶべきコアアルゴリズムのいくつかをできるだけ詳しく説明したいと思います。

バイナリ検索木 (BST) とは何ですか?

コーディング面接でよく見られる BST は、最上部にルートがあるツリーのようなデータ構造です。順序付けられた性質により高速な検索と参照が可能になるため、数値を保存するのに最適な方法です。

通常のツリーと比較して、BST には次の特性があります。

  • 左の子の値は親の値より小さい
  • 右の子はそれぞれ親よりも大きい値を持ちます
  • 各ノードには 0 ~ 2 個の子ノードを含めることができます。

次の図を見ると、より明確になるはずです。

バイナリツリーノードの定義

通常、Javascript では次の関数を使用してバイナリ ツリー ノードを定義します。

 関数 TreeNode(val, left, right) {
     this.val = val
     this.left = 左
     this.right = 右
 }

バイナリツリーの基本的な走査(インオーダー、ポストオーダー、プレオーダー)

まず、BST の各ノードをどのようにトラバースするかを知る必要があります。これにより、BST のすべてのノードで関数を実行できるようになります。たとえば、BST で値 x を見つけたい場合は、ノードが必要です。

これを行うには主に 3 つの方法があります。幸いなことに、それらは共通のテーマを共有しています。

順序通りの走査

再帰アルゴリズムは、バイナリ ツリーの順序どおりのトラバーサルを開始するための最も簡単な方法です。考え方は次のとおりです。

  • ノードが空の場合は何も行いません。それ以外の場合は、ノードの左の子に対して関数を再帰的に呼び出します。
  • 次に、すべての左の子ノードをトラバースした後、ノードに対していくつかの操作を実行します。現在のノードは、最も左のノードであることが保証されます。
  • 最後に、node.right の関数が呼び出されます。

Inorder アルゴリズムは、ツリー ノードを左、中央、右の順に走査します。

const inorder = (ルート) => {
    定数ノード = []
    if (ルート) {
        inorder(ルート.左)
        ノードをプッシュします(ルート.val)
        inorder(ルート.right)
    }
    ノードを返す
}
// この例のツリーでは、[1,2,3,4,5,6] が返されます

後順序トラバーサル

再帰アルゴリズムは、後順序トラバーサルを開始する最も簡単な方法です。

  • ノードが空の場合は何も行いません。それ以外の場合は、ノードの左の子に対して関数を再帰的に呼び出します。
  • 左の子がなくなったら、node.right の関数を呼び出します。
  • 最後に、ノードに対していくつかの操作を実行します。

後順トラバーサルは、ツリー ノードを左、右、中央から訪問します。

const postorder = (ルート) => {
    定数ノード = []
    if (ルート) {
        postorder(ルート.左)
        postorder(ルート.right)
        ノードをプッシュします(ルート.val)
    }
    ノードを返す
}
// この例のツリーでは、[1,3,2,6,5,4] が返されます

事前順序トラバーサル

事前順序トラバーサルを開始する最も簡単な方法は、再帰アルゴリズムを使用することです。

  • ノードが空の場合は何も行いません。それ以外の場合はノードに対して何かを実行します。
  • ノードの左の子ノードをトラバースして繰り返します。
  • ノードの右の子まで移動して繰り返します。

後順トラバーサルは、ツリー ノードを中央、左、右から訪問します。

const preorder = (ルート) => {
    定数ノード = []
    if (ルート) {
        ノードをプッシュします(ルート.val)
        preorder(ルート.left)
        事前注文(ルート.right)
    }
    ノードを返す
}
// この例のツリーでは、[4,2,1,3,5,6] が返されます

有効な二分探索木とは何ですか?

有効なバイナリ検索ツリー (BST) には、値が親ノードより小さいすべての左の子と、値が親ノードより大きいすべての右の子が含まれます。
ツリーが有効な二分探索ツリーであるかどうかを確認するには:

  • 現在のノードが持つことができる最小値と最大値を定義します
  • ノードの値がこれらの範囲内にない場合は、falseを返します。
  • ノードの左の子を再帰的に検証し、最大値をノードの値に設定します。
  • ノードの右の子を再帰的に検証し、最小境界をノードの値に設定します。
const isValidBST = (ルート) => {
    const ヘルパー = (ノード、最小値、最大値) => {
        if (!node) が true を返す
        node.val <= min || node.val >= max の場合、false を返します。
        ヘルパー(node.left, min, node.val) && ヘルパー(node.right, node.val, max) を返します
    }
    ヘルパーを返します(ルート、Number.MIN_SAFE_INTEGER、Number.MAX_SAFE_INTEGER)
}

二分木の最大深さを見つける方法

ここで、アルゴリズムは BST の高さ/深さを見つけようとします。言い換えれば、BST にいくつの「レベル」が含まれているかを調べていることになります。

  • ノードが空の場合は、深さを追加しないので0を返します。
  • それ以外の場合は、現在の深さに + 1 を追加します(1 つのレベルを通過しました)。
  • ノードの子の深さを再帰的に計算し、node.leftとnode.rightの間の最大合計を返します。
定数maxDepth = function(root) {
    const calc = (ノード) => {
        if (!node) が 0 を返す
        Math.max(1 + calc(node.left), 1 + calc(node.right)) を返します
    }
    calc(root)を返す
};

2つのツリーノード間の最小共通祖先を見つける方法

難易度を上げてみましょう。バイナリツリー内の 2 つのツリーノード間の共通祖先をどのように見つけるのでしょうか?いくつか例を見てみましょう。

このツリーでは、3 と 1 の最小共通祖先は 2 です。3 と 2 の LCA は 2 です。6 と 1 と 6 の LCA は 4 です。

ここにパターンが見えますか? 2 つのツリー ノード間の LCA は、いずれかのノード自体 (ケース 3 および 2)、または最初の子が左のサブツリーのどこかにあり、2 番目の子が右のサブツリーのどこかにある親ノードのいずれかです。

2 つのツリー ノード p と q 間の最小共通祖先 (LCA) を見つけるアルゴリズムは次のとおりです。

  • p または q が左または右のサブツリーに見つかるかどうかを確認します。
  • 次に、現在のノードがpかqかを確認します。
  • 左または右のサブツリーにpまたはqのいずれかが見つかり、pまたはqのいずれかがノード自体である場合、LCAが見つかったことになります。
  • 左または右のサブツリーにpとqの両方が見つかった場合、LCAが見つかったことになります。
const lowestCommonAncestor = function(root, p, q) {
    lca = null とします
    const isCommonPath = (ノード) => {
        if (!node) が false を返す
        var isLeft = isCommonPath(node.left)
        var isRight = isCommonPath(node.right)
        var isMid = ノード == p || ノード == q
        if (isMid && isLeft || isMid && isRight || isLeft && isRight) {
            lca = ノード
        }
        isLeft || isRight || isMid を返します
    }
    isCommonPath(ルート)
    リターンLCA
};

😊 終わり

これまで、BST の深さをトラバース、検証、計算する方法を学習しました。

これで、JavaScript 初心者向けのバイナリ サーチ ツリー アルゴリズム チュートリアルに関するこの記事は終了です。JavaScript バイナリ サーチ ツリー アルゴリズムに関するより関連性の高いコンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • JS を使用してバイナリ ツリー トラバーサル アルゴリズムのサンプル コードを実装する
  • JavaScript を使用してソートアルゴリズムを実装する方法
  • Matlab による JavaScript プログラミング、重心アルゴリズムによる位置決め学習
  • JavaScript で実装された 7 つのソート アルゴリズムの概要 (推奨!)
  • JavaScript でツリー構造を構築するための効率的なアルゴリズムについての簡単な説明
  • JavaScript でアルゴリズムの複雑さを学ぶ方法
  • jsは赤い封筒の順序と量を指定するアルゴリズムを実装します
  • JavaScript を使用して簡単なアルゴリズムを実行する方法

<<:  mysql8.0.20 のダウンロードとインストールおよび発生した問題 (図とテキスト)

>>:  Alibaba Cloud ホストが IP を使用して Web サイトにアクセスできない問題の解決策 (セキュリティ グループ ルールを構成することで解決)

推薦する

CSS の :focus-within の楽しさについて簡単に説明します

Bステーションでパスワードを入力するときに目を覆っているこの画像を見たことがある人もいると思いますこ...

jQueryはキャンバスタグを使用して検証コードを描画します

<canvas> 要素は、クライアント側のベクター グラフィックス用に設計されています。...

Linux gzipコマンドの使用

1. コマンドの紹介gzip (GNU zip) コマンドは、ファイルの圧縮と解凍に使用されます。こ...

mybatis-plusページングパラメータが渡された後、SQLのwhere条件にはページング情報操作の制限がありません

2時間近くかけて、さまざまな方法を試しました。後で、whereでフィルタリングした後のデータ量が1ペ...

Vueは、選択した月に応じて日付に対応する曜日を動的に表示します。

私たち謙虚なプログラマーは、今でもこう歌わなければなりません。「あなたも私も、この世に生まれて、一日...

Vueは水平の斜めの棒グラフを実装します

この記事では、水平傾斜棒グラフを実装するためのVueの具体的なコードを参考までに共有します。具体的な...

Ubuntu 18.04 LTSでIPアドレスを設定するための完全な手順

序文Ubuntu 18.04 LTS で IP アドレスを設定する方法は、これまで使用されていた設定...

Vue でのカスタムディレクティブの基本的な使用方法

目次序文文章1. グローバル登録2. 部分登録3. フック機能とパラメータ設定4. 柔軟な使い方(1...

Vue スクロールダウンしてさらにデータを読み込む スクロールケースの詳細な説明

vue-無限スクロールインストール npm インストール vue-infinite-scroll -...

MySQL フラッシュバック ツール binlog2sql の詳細なインストールと設定のチュートリアル

概要binlog2sql は、Python で開発されたオープンソースの MySQL Binlog ...

React でカレンダー コンポーネントを構築するためのステップ バイ ステップ ガイド

目次事業背景テクノロジーの活用技術的な問題デザインのアイデア😱 困惑と苦痛に満ちた顔🙄考え始める🌲デ...

CSSはBEM命名規則の実践を使用する

クラスを見るとき、どのような情報を得たいですか?このクラスはどこで使用され、その機能は何ですか?この...

ウェブページのメモリとCPU使用量を削減する方法

<br />Web ページによっては、サイズは大きくないように見えても開くのに非常に時間...

Mysql はテーブル内の古いデータを定期的にクリアし、いくつかのデータを保持します (推奨)

以下の目標を達成するため: Mysql データベースは、一定の間隔 (2 時間または 1 日、カスタ...

MySQL 全体または単一のテーブルデータのエクスポート

単一のテーブルをエクスポートするmysqldump -u ユーザー -p db名 テーブル名 >...