JavaScriptのデータ構造とアルゴリズムのアメリカ合衆国 - 非線形テーブルの木のヒープがでているのですか?そのデータの構造は何ですか?

米国JavaScriptのデータ構造とアルゴリズムの

1.はじめに

フロントを勉強したい、最初Lianhaoneigongではなく、内部強度は、派手な動きが再び練習していても、結局、マスターになることができません。

非線形テーブル(ツリー、ヒープ)、プログラマが知っている、内臓のフロントエンドと言うことができる、その理由を知っています。

著者が書いたJavaScriptの米国のデータ構造とアルゴリズム、言語と直列にあるJavaScriptの、エントリー後のデータ構造とアルゴリズムと簡単な審査を目的としました。

非線形テーブルの木のヒープがでているのですか?そのデータの構造は何ですか?

私はあなたが以下読んでこれらの2つの問題を取る願っています。

2.ツリー

ツリー

私たちは本物の木に住んでいるようなデータ構造は、ちょうど逆の形状です。

用語の定義

  • ノード:ツリー内の各要素は、ノードと呼ばれ、例えばA、B、C、D、E、F、G、H、I、Jとして
  • 親:例えばAとノードを指し示す子ノード、
  • 子ノード:ノードはB、A、C、Dの子として、親によって指さ
  • 親子関係:親子関係がAとB、CとH、DおよびJ。と呼ばれる、2つの隣接ノードを接続します
  • ルート:なし親ノード、などなどA.
  • リーフノード:ノードは、E、F、G、H、I、Jのような子ノードを有していません
  • 兄弟ノードは:同じ親を有する複数のノードは、B、C、Dとして兄弟ノードと呼ばれ
  • 高度ノード:のリーフノードへのノード最长路径の辺の数が含まれます。
  • 深さノード:エッジの数のパスのルートノードが含まれます。
  • ノード層:+1深ノード(層の数のルートノードが1です)。
  • 木の高さ:同じ高さの根。
  • 森:n個の互いに素ツリーのセット木。

ツリーの高さ、深さ、層

高さからである下往上出発点はゼロで開始することで、そのような人の高さ180センチメートルとして、措置。
深さである上往下測定値、例えば180センチメートルのプールの深さとして、出発点は、ゼロベースです。
と高さと深さワードは、ゼロからカウントされます。
層の数を計算し、我々は最下層が1から数えて最初の層であるので、ルートノードが第一層に位置していると、通常は同じ階である、追加の子が順次インクリメントノード。

バイナリ分類

バイナリ分類

二進木

  • 各ノード最多只有のツリー2子ノードは、2つのノードが左の子ノードおよび右の子ノードです。上記図1、図2及び図3のように。
    しかし、バイナリツリーは、各ノードは2人の子供、一部のみ左の子ノード、一部のノードのみ右側の子を持っていることを必要としません。ように、私は四分木、八分木構造図をしたいです。

完全なバイナリツリー

  • リーフノードに加えて、特別なバイナリツリー、それぞれ都有2つのつの子ノードについては、バイナリツリーは完全なバイナリツリーと呼ばれています。上の図2。

完全二叉树

  • 特別なバイナリツリーは、リーフノードは、底部層で、リーフノードから最後の層がされ配置されており、加えて最后一つのノードの他の層の数に達した最大この二分木は、完全二分木と呼ばれています。図のように3。
    比較チャートは、次を参照してより困難ではないとの完全なバイナリツリーの完全なバイナリツリーは、区別するために。

そしてない完全なバイナリツリーの完全なバイナリツリー

ヒープ

前記事スタックメモリとヒープメモリ、深い浅いコピーのコピーが来る:基準タイプ(例えば、オブジェクト、等配列、機能は、)ヒープメモリに格納されているJavaScriptオブジェクトは、値のサイズは固定されていないが、スタックメモリオブジェクトとがっヒープメモリに格納されたアクセスアドレスは、JavaScriptが直接ヒープメモリの位置へのアクセス、及び従って物体の実際の動作を参照する操作対象を許可しません。

だから、最終的にそれは何ですか?そのデータ構造とどのようにそれはありますか?

ヒープは、実際には、ツリーの特別な種類です。限り、これら二つの点として、それはヒープです。

  • ヒープは完全2分木です。
    バイナリツリーを完了します。最後のものを除いて、ノードの数は、他の層は、配置されたノードが残っている最後の層に満ちています。
  • ヒープの各ノードの値は、以上に(またはそれ以下)であるサブツリーの各ノードの値なければなりません。
    それは言うことができる:スタックは、各ノードの値が等しい(またはそれ未満)、その左右の子ノードの値よりも大きいです。これらの2つのステートメントは等価です。

各ノードの値は、我々が呼ぶサブツリー値の各ノードのための以上のスタックです大顶堆各ノードの値は、我々が呼ぶサブツリースタック値の各ノードに等しい未満です小顶堆

ヒープ、ヒープビッグトップ、トップの小さなヒープを区別する

図1および図2は、大きなパイル頂部は、図3は、図小さなパイルトップであり、図4は、ヒープではありません。加えて、それはまた、図面から分かるように、データの同じセットが、我々は、スタックの異なる様々な形態を構築することができます。

バイナリ検索ツリー(バイナリ検索ツリー)

  • 特別なバイナリツリーは、相対较小値で格納されている左节点较大に格納された値右节点中央には、また、二分探索木として知られている二分探索木と呼ばれます。
    二分探索木は順序木ですので、挿入早く、すぐに見つけるために、サポートしてデータを削除します。
    以下は、3人は、二分探索木です

バイナリ検索ツリー

平衡二分探索木

  • 平衡二分探索木:バイナリ差分内の任意のノードの左及び右サブツリーの高さが1よりも大きくありません
    この定義から、完全なバイナリツリーは、実際には、完全なバイナリツリー平衡二分木が、非完全なバイナリツリーは、バランスの取れたバイナリツリーことも可能であるしています。
    平衡二分探索木の平衡意味は、実際には、ツリー全体の周りに見えるようにすることで对称比較する、平衡非常に高い左側のサブツリーと非常に低い状況の右側のサブツリーを表示されません。高効率、我々はいくつかを、ツリー全体の高さは、対応する挿入比較的低いであることを確認、削除、検索などの操作ができるように。
    平衡二分探索木は、実際にはたくさん持っている例えば、スプレイツリー(スプレー木)、Treap(Treap)というように、私たちは平衡二分探索木を言及し、我々は基本的に赤黒木を聞きました。

非平衡二分木とのバランスの取れたバイナリツリー

赤黒木(赤黒木)

赤黒木は、クラスが赤でマークされ、カテゴリが黒でマークされているノード。また、赤黒木はまた、このようないくつかの要件を満たす必要があります。

  • ルートノードは黒です。
  • 各リーフノードと言うことである黒空ノード(NIL)であり、リーフノードは、データを格納しません。
  • 任意の隣接ノードは赤の両方ことができない、すなわち、赤ノードが黒のノードによって分離されている、と言うことです。
  • 各ノードは、そのノードから到達可能なリーフノードに至る全ての経路は、黒色のノードの同じ数を含みます。

ここでは、2つの赤黒木です。

赤、黒の木

メモリ

完全2分木ストレージ

  • チェーンストレージは、
    各ノードは、他の2つは左と右の子ノードポインタを指している三つのフィールド、ストレージデータの1、から構成されています。
    限り、我々はルートノードをLinzhuとして、ポインタは子ノード、一緒に文字列全体ツリーでおくことができます。
    この格納方法は、より一般的に使用される、バイナリコードのほとんどは、このように実装されています。

チェーン店

  • 順次格納する
    インデックスノードXは、配列に格納されている場合、完全二分木のために格納するためのアレイを、あるI、次に記憶添字その左の子ノードである2 * I、右の子添字2 * I +図1に示すように、今度は、添字I / 2は、ノードの親ノードの位置に格納されます。
    なお、ルートノードの位置が1のインデックスに格納されています。完全なバイナリツリーは、ほとんどの州のメモリを格納する配列を使用する方法です。

シーケンシャルストレージ

バイナリツリートラバーサル

3つの方法で古典:前順走査、順トラバーサルでは、後順。ここで、前に、シーケンスの間および後に、シーケンスは、その左右の部分木のアクセスノード・トラバーサルのノードによって表されます。

先行順走査(ルート=>左=>右)

  • その後、ツリー内の任意のノード、このノードへの最初の訪問、そしてその左部分木にアクセスするために、最後にそれを右のサブツリーにアクセスしました。

トラバーサル順序どおり(左=>ルート=>右)

  • ツリー内の任意のノードについて、その左部分木の最初の訪問は、最後の右部分木にアクセスし、独自のアクセス。

後順(左=> =右>ルート)

  • ツリー内の任意のノードについて、その左部分木の最初の訪問は、最後のそれ自体をアクセスし、その右のサブツリーをご覧ください。

実際には、順序トラバーサル中および前後のバイナリツリーは、再帰的なプロセスです。

トラバーサル

時間複雑度:3つのトラバーサル、各ノードは、N個のノードの数が比例していると、時間複雑度はO(n)は、ほとんど2回アクセスされます。

二分探索木を実装

バイナリ検索ツリーはによって特徴付けられる:比較的小さな値は左ノードに格納され、大きい方の値は、右ノードに格納されています。

コードは、バイナリ検索ツリー、以下のメソッドを実装します。

方法

  • (キー)を挿入します。新しいキーツリーを挿入します。
  • 検索(キー):ノードが存在する場合は、ツリー内のキーを見つけるためには、trueを返し、存在しない場合は、偽が返されます。
  • 分:最小の木/キーの値を返します。
  • 最大:リターン・ツリー/キーの最大値。
  • (キー)削除:ツリーからキーを削除します。

トラバーサル

  • preOrderTraverse:によって先序遍历、すべてのノードの仕方を横断。
  • inOrderTraverse:することにより中序遍历、すべてのノード経由の方法。
  • postOrderTraverse:によって后序遍历、すべてのノードの仕方を横断。

特定のコード

  • ファーストクラスのバイナリ検索ツリーのクラスを実装
// 二叉查找树类
function BinarySearchTree() {
    // 用于实例化节点的类
    var Node = function(key){
        this.key = key; // 节点的健值
        this.left = null; // 指向左节点的指针
        this.right = null; // 指向右节点的指针
    };
    var root = null; // 将根节点置为null
}
  • メソッドを挿入し、新しいキーがツリーに挿入されています。
    ツリーをトラバースするキー値は、ノード鍵を横断インサートノードとを比較し、前者が後者よりも大きい場合に、再帰的に右の子ノードを横断する、今度は、ノードが空になるまで、左の子ノードをトラバースし続け、この位置に挿入され。
this.insert = function(key){
    var newNode = new Node(key); // 实例化一个节点
    if (root === null){
        root = newNode; // 如果树为空,直接将该节点作为根节点
    } else {
        insertNode(root,newNode); // 插入节点(传入根节点作为参数)
    }
};
// 插入节点的函数
var insertNode = function(node, newNode){
    // 如果插入节点的键值小于当前节点的键值
    // (第一次执行insertNode函数时,当前节点就是根节点)
    if (newNode.key < node.key){
        if (node.left === null){
            // 如果当前节点的左子节点为空,就直接在该左子节点处插入
            node.left = newNode;
        } else {
            // 如果左子节点不为空,需要继续执行insertNode函数,
            // 将要插入的节点与左子节点的后代继续比较,直到找到能够插入的位置
            insertNode(node.left, newNode);
        }
    } else {
        // 如果插入节点的键值大于当前节点的键值
        // 处理过程类似,只是insertNode函数继续比较的是右子节点
        if (node.right === null){
            node.right = newNode;
        } else {
            insertNode(node.right, newNode);
        }
    }
}

図の親族値ノードツリーの挿入以下6、次のように:

  • 検索最小
    にかかわらず、そのサブツリー又はツリー全体、特定の最小の左下最ツリーのバイナリ検索ツリー内、。
    したがって、与えられたツリーまたはサブツリーは、あなただけのライン上に残された最後のノードにトラバースする必要があります。
this.min = function(node) {
    // min方法允许传入子树
    node = node || root;
    // 一直遍历左侧子节点,直到底部
    while (node && node.left !== null) {
        node = node.left;
    }
    return node;
};
  • 最大値を探索する
    最大値を検索し、最小値検索は、ツリートラバーサルの右側に沿って以外は同様です。
this.max = function(node) {
    // min方法允许传入子树
    node = node || root;
    // 一直遍历左侧子节点,直到底部
    while (node && node.right !== null) {
        node = node.right;
    }
    return node;
};
  • 特定の値を検索し
    、特定の値を検索するために補間された値と同様の処理。前者が後者よりも大きい場合に検索されるツリーは、ノードのトラバーサルの値と比較される横断、再帰的、そうでない場合は、左の子ノードの再帰的トラバーサルを右の子ノードを横断します。
this.search = function(key, node){
    // 同样的,search方法允许在子树中查找值
    node = node || root;
    return searchNode(key, node);
};
var searchNode = function(key, node){
    // 如果node是null,说明树中没有要查找的值,返回false
    if (node === null){
        return false;
    }
    if (key < node.key){
        // 如果要查找的值小于该节点,继续递归遍历其左侧节点
        return searchNode(node.left, key);
    } else if (key > node.key){
        // 如果要查找的值大于该节点,继续递归遍历其右侧节点
        return searchNode(node.right, key);
    } else {
        // 如果要查找的值等于该节点,说明查找成功,返回改节点
        return node;
    }
};
  • ノードが除去され
    、ツリー内のノードを削除する見つけるために、すべての最初に削除されたノードと、そのノードが子を持つ、または子ノードが2つのつの子ノードを持ち、そして最終的には別々に処理するか否かを判定する。
this.remove = function(key, node) {
    // 同样的,允许仅在子树中删除节点
    node = node || root;
    return removeNode(key, node);
};
var self = this;
var removeNode = function(key, node) {
    // 如果 node 不存在,直接返回
    if (node === false) {
        return null;
    }

    // 找到要删除的节点
    node = self.search(key, node);

    // 第一种情况,该节点没有子节点
    if (node.left === null && node.right === null) {
        node = null;
        return node;
    }
    // 第二种情况,该节点只有一个子节点的节点
    if (node.left === null) {
        // 只有右节点
        node = node.right;
        return node;
    } else if (node.right === null) {
        // 只有左节点
        node = node.left;
        return node;
    }
    // 第三种情况,有有两个子节点的节点
    // 将右侧子树中的最小值,替换到要删除的位置
    // 找到最小值
    var aux = self.min(node.right);
    // 替换
    node.key = aux.key;
    // 删除最小值
    node.right = removeNode(aux.key, node.right);
    return node;
};

図に示すように、第三のケースを処理します。
削除するノードがツリーの構造を破壊しないようにするために、2人の子供がいる場合には、ベンチノードをオフに来てDeleteキーのサイズが削除された左と右の子、そしてベンチアップの重要なノード間でなければなりません。アップ交換右の部分木の最小値を見つけるために、したがって、ノードが子ノードを有していなければならない、またはノードはバイトケースの複数の点を有することになります。
同様に、最大値を見つけるために左側のサブツリーは、最大置換されていてもよいです。

  • 予約限定!
this.preOrderTraverse = function(callback){
    // 同样的,callback用于对遍历到的节点做操作
    preOrderTraverseNode(root, callback);
};
var preOrderTraverseNode = function (node, callback) {
    // 遍历到node为null为止
    if (node !== null) {
        callback(node.key); // 先处理当前节点
        preOrderTraverseNode(node.left, callback); // 再继续遍历左子节点
        preOrderTraverseNode(node.right, callback); // 最后遍历右子节点
    }
};

図示のツリー、及び印刷キーノードをトラバースすることによってトラバーサルをプレオーダー。
出力:11。7 5,369,810,151,312,142,018 25
トラバーサル図:

  • 予約限定!
this.inOrderTraverse = function(callback){
    // callback用于对遍历到的节点做操作
    inOrderTraverseNode(root, callback);
};
var inOrderTraverseNode = function (node, callback) {
    // 遍历到node为null为止
    if (node !== null) {
        // 优先遍历左边节点,保证从小到大遍历
        inOrderTraverseNode(node.left, callback);
        // 处理当前的节点
        callback(node.key);
        // 遍历右侧节点
        inOrderTraverseNode(node.right, callback);
    }
};

図中のツリートラバーサルシーケンスを実行し、各ノードのキー値を出力します。
順次出力:3 5,678,910,111,213,141,518 20 25であります
トラバーサル図:

  • 後順
this.postOrderTraverse = function(callback){
    postOrderTraverseNode(root, callback);
};
var postOrderTraverseNode = function (node, callback) {
    if (node !== null) {
        postOrderTraverseNode(node.left, callback); //{1}
        postOrderTraverseNode(node.right, callback); //{2}
        callback(node.key); //{3}
    }
};

これは、ほぼ正確にコードの行のみ、{1}、{2}、{3}の異なる実行順序を同一の実装を通過した後、順次、第一の配列を見ることができます。
3 6,581,097,121,413,182,520 15 11:ツリーは、図トラバーサルの順序、及び印刷キーである後
トラバーサル図:

  • 印刷方式の印刷を追加します。
this.print = function() {
  console.log('root :', root);
  return root;
};

完全なコードファイルを参照してください。バイナリ検索-tree.htmlを

テストプロセス:

// 测试
var binarySearchTree = new BinarySearchTree();
var arr = [11, 7, 5, 3, 6, 9, 8, 10, 15, 13, 12, 14, 20, 18, 25];
for (var i = 0; i < arr.length; i++) {
    var value = arr[i];
    binarySearchTree.insert(value);
}

console.log('先序遍历:');
var arr = [];
binarySearchTree.preOrderTraverse(function(value) {
    // console.log(value);
    arr.push(value);
});
console.log('arr :', arr); // [11, 7, 5, 3, 6, 9, 8, 10, 15, 13, 12, 14, 20, 18, 25]

var min = binarySearchTree.min();
console.log('min:', min); // 3
var max = binarySearchTree.max();
console.log('max:', max); // 25
var search = binarySearchTree.search(10);
console.log('search:', search); // 10
var remove = binarySearchTree.remove(13);
console.log('remove:', remove); // 13

console.log('先序遍历:');
var arr1 = [];
binarySearchTree.preOrderTraverse(function(value) {
    // console.log(value);
    arr1.push(value);
});
console.log('arr1 :', arr1); //  [11, 7, 5, 3, 6, 9, 8, 10, 15, 14, 12, 20, 18, 25]

console.log('中序遍历:');
var arr2 = [];
binarySearchTree.inOrderTraverse(function(value) {
    // console.log(value);
    arr2.push(value);
}); 
console.log('arr2 :', arr2); // [3, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 18, 20, 25]

console.log('后序遍历:');
var arr3 = [];
binarySearchTree.postOrderTraverse(function(value) {
    // console.log(value);
    arr3.push(value);
});
console.log('arr3 :', arr3); //  [3, 6, 5, 8, 10, 9, 7, 12, 14, 18, 25, 20, 15, 11]

binarySearchTree.print(); // 看控制台

結果は以下の通りであります:

テスト結果

ここを参照してください、あなたは質問に、ツリー内の非線形テーブルアーティクルに答えることができ、ヒープがでているのですか?そのデータの構造は何ですか?

ない場合は、ああよく見てお勧めするために戻って行きます。

3.最後に

あなたはこの記事はかなり良いと思うなら、星を与えることを忘れないでください、あなたは私のスターパワーが継続的に更新されます。

I GitHubの

参考記事:

米国のデータ構造とアルゴリズムの

JavaScriptのデータ構造とアルゴリズムを学ぶ - ツリー

おすすめ

転載: www.cnblogs.com/biaochenxuying/p/11463257.html
おすすめ