フロントエンド: JavaScript でのバイナリ ツリー アルゴリズムの実装

フロントエンド: JavaScript でのバイナリ ツリー アルゴリズムの実装

[[359197]]

次に、js データ構造のツリーを調べてみましょう。ここでのツリーは、幹と枝を持つ現実のツリーに似ています。プログラムでは、ツリーは、すばやく見つける必要のあるデータを格納するのに非常に便利なデータ構造です。これは、階層データの抽象モデルです。ツリー構造は、親子関係を持つ一連のノードで構成されます。各ノードには親ノードと 0 個以上の子ノードがあります。以下はツリー構造です。


  • ツリーに関連する概念: 1. サブツリー: 上の図に示すように、ノードとその子孫で構成されます。 2. 深さ: ノードの深さは、その祖先ノードの数によって決まります。たとえば、ノード 5 には 2 つの祖先ノードがあり、その深さは 2 です。3. 高さ: ツリーの高さは、すべてのノードの深さの最大値によって決まります。

二分木と二分探索木の紹介

バイナリ ツリーのノードには、最大 2 つの子ノード (左側に 1 つ、右側に 1 つ) を含めることができます。この定義の利点は、ノードの挿入、検索、削除のためのより効率的なアルゴリズムを記述できることです。二分探索木は二分木の一種ですが、左の子ノードには親ノードより小さい値しか格納できず、右の子ノードには親ノードより大きい値を格納することができます。次に、このアイデアに従って二分探索木を実装します。

1. BinarySearchTreeクラスを作成する

ここではコンストラクターを使用してクラスを作成します。

  1. 関数BinarySearchTree(){
  2. // ノードを作成するためのクラス
  3. Node =関数(キー) {
  4. this.key =キー;
  5. this.left = null ;
  6. this.right = null ;
  7. }
  8. // ルートノード
  9. ルートをnullにします
  10. }

ノード間の関係を表すために、リンク リストに似たポインター メソッドを使用します。リンク リストがわからない場合は、次の記事「単一方向および双方向のリンク リストを実装する方法」をお読みください。

2. キーを挿入する

  1. // キーを挿入する
  2. this.insert =関数(キー) {
  3. newNode = new Node(キー) とします。
  4. ルート === null ? (ルート = newNode) : (insertNode(ルート、newNode))
  5. }

ツリーに新しいノードを挿入する処理は、次の 3 つの部分から構成されます。1. 新しいノードの Node クラス インスタンスを作成する --> 2. 挿入操作がルート ノードであるかどうかを判断し、そうである場合はルート ノードを指定します --> 3. ノードをルート以外のノードの場所に追加します。

insertNode の具体的な実装は次のとおりです。

  1. 関数insertNode(ノード, newNode){
  2. 新しいノードのキーがノードのキーより小さい場合
  3. node.left === null ? (node.left = newNode) : (insertNode(node.left , newNode))
  4. }それ以外{
  5. node.right === null ? (node.right = newNode) : (insertNode(node.right , newNode))
  6. }
  7. }

ここでは再帰を使います。この後実装する検索や削除などでも再帰を多用するので、わからない場合はまず自分で学んでみましょう。キーを挿入するためのバイナリ ツリー インスタンスを作成します。

  1. ツリーを新しい BinarySearchTree() にします。
  2. ツリーを挿入 (20);
  3. ツリーを挿入 (21);
  4. ツリーを挿入( 520 );
  5. ツリーを挿入 ( 521 );

挿入された構造は二分探索木のルールに従って挿入され、その構造は上記の最初のツリー図に似ています。

ツリートラバーサル

ツリーをトラバースする方法には、インオーダー、プレオーダー、ポストオーダーの 3 つがあります。

  • 順序通りのトラバーサル: 最小から最大の順にすべてのノードを訪問する
  • 先行順序トラバーサル: 各ノードをその子孫ノードの前の順序で訪問する
  • 後順トラバーサル: まずノードの子孫ノードを訪問し、次にノード自体を訪問する

上記の紹介に基づいて、次の実装コードを作成できます。

1 順序ソート

  1. this.inOrderTraverse =関数(cb){
  2. inOrderTraverseNode(ルート、cb);
  3. }
  4.  
  5. // ヘルパー関数
  6. 関数inOrderTraverseNode(node, cb){
  7. if(ノード ​​!== null ){
  8. inOrderTraverseNode( node.left , cb);
  9. cb(ノード.キー);
  10. inOrderTraverseNode( node.right , cb);
  11. }
  12. }

順序付きトラバーサルを使用すると、ツリーを小さいものから大きいものへと並べ替えることができます。

2 予約注文の並べ替え

  1. // 事前順序ソート--- 子孫ノードの優先順位に従って各ノードを訪問します 
  2. this.preOrderTraverse =関数(cb) {
  3. preOrderTraverseNode(ルート、cb);
  4. }
  5.  
  6. // 事前順序ソートヘルパーメソッド
  7. 関数preOrderTraverseNode(ノード、cb) {
  8. if(ノード ​​!== null ) {
  9. cb(ノード.キー);
  10. preOrderTraverseNode( node.left , cb);
  11. preOrderTraverseNode( node.right , cb);
  12. }
  13. }

事前順序ソートを使用すると、構造化された出力の機能を実現できます。

3 事後順序ソート

  1. // 後続のトラバーサル--- まず子孫ノードを訪問し、次にノード自体を訪問します 
  2. this.postOrderTraverse =関数(cb) {
  3. postOrderTraverseNode(ルート、cb);
  4. }
  5.  
  6. // 後続のトラバーサル補助メソッド
  7. 関数postOrderTraverseNode(ノード、cb) {
  8. if(ノード ​​!== null ){
  9. postOrderTraverseNode( node.left , cb);
  10. postOrderTraverseNode( node.right , cb);
  11. cb(ノード.キー);
  12. }
  13. }

後順序トラバーサルを使用すると、階層関係内のすべての要素のサイズを計算できます。

ツリー内の値の検索

ツリーで一般的に実行される検索には、最大値、最小値、特定の値の 3 つの種類があります。

1 最小

最小値は、左のツリーの最下層のノードとして定義されます。具体的な実装コードは次のとおりです。

  1. // 最小値
  2. this.min =関数(){
  3. minNode(ルート)を返す
  4. }
  5.  
  6. 関数minNode(ノード) {
  7. if(ノード) {
  8. while(node ​​&& node.left !== null ){
  9. ノード = node.left ;
  10. }
  11. node.key​を返す 
  12. }
  13. 戻る ヌル 
  14. }

同様に、最大値は次のように達成されます。

  1. // 最大値
  2. this.max =関数(){
  3. maxNode(ルート)を返す
  4. }
  5.  
  6. 関数maxNode(ノード) {
  7. if(ノード){
  8. while(node ​​&& node.right !== null ){
  9. ノード = node.right ;
  10. }
  11. node.key​を返す 
  12. }
  13. 戻る ヌル 
  14. }

2. 特定の値を検索する

  1. // ツリー内の値を検索する
  2. this.search =関数(キー) {
  3. searchNode(ルート、キー)を返します
  4. }
  5.  
  6. // 検索ヘルパーメソッド
  7. 関数searchNode(ノード、キー){
  8. if(ノード === null ) {
  9. 戻る 間違い 
  10. }
  11. if(キー< ノード.キー) {
  12. searchNode ( node.left key )を返します
  13. }そうでない場合(キー> ノード.キー) {
  14. searchNode ( node.right key )を返します
  15. }それ以外{
  16. 戻る 真実 
  17. }
  18. }

3 ノードを削除する

  1. this.remove =関数(キー) {
  2. ルート = removeNode(ルート、キー);
  3. }
  4.  
  5. // 最小のノードを見つける
  6. 関数findMinNode(ノード) {
  7. if(ノード) {
  8. while(node ​​&& node.left !== null ){
  9. ノード = node.left ;
  10. }
  11. 戻りノード
  12. }
  13. 戻る ヌル 
  14. }
  15.  
  16. // ノードヘルパーメソッドを削除する
  17. 関数removeNode(ノード、キー) {
  18. if(ノード === null ) {
  19. 戻る ヌル 
  20. }
  21.  
  22. if(キー< ノード.キー) {
  23. node.left = removeNode(node.left ,キー) ;
  24. 戻りノード
  25. }そうでない場合(キー> ノード.キー) {
  26. node.right = removeNode(node.right キー) ;
  27. 戻りノード
  28. }それ以外{
  29. // ページノード
  30. if( node.left === null && node.right === null ) {
  31. ノード = null ;
  32. 戻りノード
  33. }
  34.  
  35. // 子ノードが 1 つだけあるノード
  36. if(ノード.left === null ) {
  37. ノード = node.right ;
  38. 戻りノード
  39. }そうでない場合(node.right === null ) {
  40. ノード = node.left ;
  41. 戻りノード
  42. }
  43.  
  44. // 2つの子ノードを持つノード
  45. aux = findMinNode( node.right );とします。
  46. ノードキー= aux.key ;
  47. ノード削除ます
  48. 戻りノード
  49. }
  50. }

ノードを削除するときに考慮する必要がある状況は多数あります。ここでは、min に似た実装を使用して、最小のノードを見つける関数を記述します。削除するノードに 2 つの子ノードがある場合、削除する現在のノードを子ノードの中で最大のノードの値に置き換えてから、この子ノードを削除する必要があります。

この時点で、バイナリ検索ツリーは実装されましたが、まだ問題があります。ツリーの片側が非常に深い場合、特定のパフォーマンス問題が発生します。この問題を解決するには、任意のノードの左サブツリーと右サブツリーの高さの差が最大 1 である自己バランスバイナリツリーである AVL ツリーを使用できます。

<<:  人工知能(AI)が商業ビルのアプリケーションで成功を収める

>>:  無料の Python 機械学習コース パート 3: 多項式回帰

ブログ    

推薦する

...

未来が到来: 脳コンピューターインターフェースの新たなブレークスルー: 人間の脳信号をテキストに変換する精度は 97%

4月23日、海外メディアの報道によると、カリフォルニア大学サンフランシスコ校の研究チームが開発した...

LangChain と DeepInfra を使用してカスタマー サポート チャットボットを構築するためのガイド

翻訳者 |ブガッティレビュー | Chonglou日常のオンラインのやり取りの中でチャットボットを目...

人工知能がヘルスケア業界にもたらす変化

AIが医療業界を変える[[397937]] AIとロボットはすでにいくつかの医療機関で活用されていま...

AIが研究者に歴史の匂いを再現する手助けをする方法

欧州連合は、AIを使って歴史的な香りや嗅覚要素を再現することを計画している研究チームに280万ユーロ...

3つの主要なSQL ServerアルゴリズムのI/Oコストの簡単な分析

1. ネストループ結合アルゴリズム:考え方は非常に単純かつ直接的です。関係 R の各タプル r を、...

視線追跡は無視できない、視覚制御車はもうすぐ登場する

正直に言ってみましょう。ジョブズが2007年に初めてiPhoneをリリースしたとき、革命的な新時代が...

「初の常温常圧超伝導体」に対する共同研究者の反応:内容に欠陥あり

この記事はAI新メディアQuantum Bit(公開アカウントID:QbitAI)より許可を得て転載...

注目の話題レビュー:人工知能市場規模は100兆元を超え、爆発的な成長を導く

AI(人工知能)は、研究開発を通じて人間の理論、方法、技術、アプリケーション システムをシミュレート...

ライフル銃で動くロボット犬の発明者が恐怖を巻き起こす:プログラミング制御は恐れる必要はない

[[429985]]先週、米国陸軍協会(AUSA)の会議がワシントンで開催されました。アメリカのロボ...

...

機械学習のバックボーン: モデル構築のためのインフラストラクチャ ツールは何ですか?

この記事は公開アカウント「Reading Core Technique」(ID: AI_Discov...

トップエキスパートが語る: 生成型AIとロボット工学の未来

ビッグデータダイジェスト制作最近、カーネギーメロン大学、カリフォルニア大学バークレー校、Meta、N...

C# モザイク アルゴリズムの実装

視聴者の要望に応えて、今日は C# モザイク アルゴリズムの実装についてお話します。古いルール、理解...