データ構造 - 二分探索木(バイナリ検索ツリー)

バイナリ検索ツリー

バイナリ検索ツリーはバイナリツリーはまた、二分探索木として知られている最も一般的なタイプ、です。

名前が示すように、達成するために二分探索木はすぐに見つけると学生。

実際には、すぐにそのサポートに加えて、データをすばやく挿入するには更なる支援、削除データを見つけます。

特定のバイナリ検索ツリー構造に応じて、これらをサポートすることができました。

 

バイナリ検索ツリーは、ツリー内の任意のノードを必要とし、左の部分木の値の各ノードは、ノードの値未満であると、このノードの右の部分木のノードの値が値よりも大きいです。

 

オペレーティングツリー用のバイナリツリールックス

それは我々が探しているデータと同一である場合には最初のテイクのルートは、その後、返されました。

あなたがデータを検索したい場合は、ルートノードの値よりも小さい場合は、再帰的に左部分木に見えます。

あなたは、ルートノードの値よりも大きいデータを探している場合は、再帰的に右のサブツリーを見つけます。

 

バイナリ検索ツリー挿入

バイナリ検索ツリーの挿入プロセスは、検索操作に似ています。

新しいデータが一般的にリーフノードに挿入されて、私たちは順番に挿入されるデータとノード間の大小関係を比較し、ルートから開始する必要があります。

データが大きなデータ・ノードの上に挿入されるように、右部分木のノードが空の場合、新しいデータが直接右の子ノードの位置に挿入されます。

それが空でない場合は、再帰的に挿入位置を見つけ、右のサブツリーを横断します。

挿入されるデータは、ノードの値よりも小さい場合、ノードの左サブツリーが空の場合同様に、新しいデータが左の子ノードの位置に挿入されます。

それが空でない場合は、再帰的に挿入位置を見つけ、左のサブツリーをトラバース。

 

バイナリ検索ツリーの削除

より複雑な操作と削除操作を見つけると、それは3例に対処する必要が挿入されます。

 

あなたはノードが子ノードを持たない削除したい場合は、最初は、私たちは、あなたがノードのポインタを削除したいポイントがnullに設定されている、唯一の直接の親ノードを必要としています。(このようなグラフ55のノードの削除など)

あなたが唯一の子ノード(のみ左の子か右の子ノード)を削除したいノードは、我々は唯一の親ノードを更新する必要がある場合は、2番目のケースでは、ノードを削除するために、子ノードを指すようにノードポインタを削除したいポイントですその上に。(例えば図のノードの削除など。13)

三番目のケースでは、ノードを削除したい場合は、より複雑である2人の子供を持っているということです。私たちは、削除するノード上で、それを置き換えるために、ツリーの中で最小のノードの右の子ノードを見つける必要があります。私たちは、最小のノードを削除するには、上記2つのルールを適用することができるように、最低は確かに、(左の子ノードがある場合、それは最小のノードではない)子ノードを残していないので、その後、最小のノードを削除します。(例えば図1にノードを削除するなど。18)

 

その他の営業バイナリ検索ツリー

バイナリ検索ツリーの挿入および削除操作を見つけることに加えて、そのような迅速に最大および最小ノードノードノードの先行および後続ノードを検索するための支持体として多くの操作があります。

バイナリツリーの一つの重要な特徴バイナリ検索ツリートラバーサル順序、月出力データの順序付けられたシーケンスは、時間計算量はO(N)であり、非常に効率的です。

このため、また、二分探索木バイナリソートの木として知られています。

 

public class BinarySearchTree {
  private Node tree;

  public Node find(int data) {
    Node p = tree;
    while (p != null) {
      if (data < p.data) p = p.left;
      else if (data > p.data) p = p.right;
      else return p;
    }
    return null;
  }
  
  public void insert(int data) {
    if (tree == null) {
      tree = new Node(data);
      return;
    }

    Node p = tree;
    while (p != null) {
      if (data > p.data) {
        if (p.right == null) {
          p.right = new Node(data);
          return;
        }
        p = p.right;
      } else { // data < p.data
        if (p.left == null) {
          p.left = new Node(data);
          return;
        }
        p = p.left;
      }
    }
  }

  public void delete(int data) {
    Node p = tree; // p指向要删除的节点,初始化指向根节点
    Node pp = null; // pp记录的是p的父节点
    while (p != null && p.data != data) {
      pp = p;
      if (data > p.data) p = p.right;
      else p = p.left;
    }
    if (p == null) return; // 没有找到

    // 要删除的节点有两个子节点
    if (p.left != null && p.right != null) { // 查找右子树中最小节点
      Node minP = p.right;
      Node minPP = p; // minPP表示minP的父节点
      while (minP.left != null) {
        minPP = minP;
        minP = minP.left;
      }
      p.data = minP.data; // 将minP的数据替换到p中
      p = minP; // 下面就变成了删除minP了
      pp = minPP;
    }

    // 删除节点是叶子节点或者仅有一个子节点
    Node child; // p的子节点
    if (p.left != null) child = p.left;
    else if (p.right != null) child = p.right;
    else child = null;

    if (pp == null) tree = child; // 删除的是根节点
    else if (pp.left == p) pp.left = child;
    else pp.right = child;
  }

  public Node findMin() {
    if (tree == null) return null;
    Node p = tree;
    while (p.left != null) {
      p = p.left;
    }
    return p;
  }

  public Node findMax() {
    if (tree == null) return null;
    Node p = tree;
    while (p.right != null) {
      p = p.right;
    }
    return p;
  }
  
  public static class Node {
    private int data;
    private Node left;
    private Node right;

    public Node(int data) {
      this.data = data;
    }
  }
}

 

バイナリ検索ツリー時間複雑分析

フォームのバイナリ検索ツリー品種は、同じデータセットのために、探索木を見つけ、挿入、バイナリの異なる形式の実装で削除操作効率が同じではありません。

時間の複雑さのため外観はO(n)になるように、非常に不均一図最初の二分探索木、左と右のサブツリーのルートは、リンクリストに縮退しています。 

これは、バイナリ検索ツリー最悪のケースで、二分探索木がある最良の場合は、完全なバイナリツリー(または完全なバイナリ木)時間です。

 

かどうかの挿入、削除、または高さを見つけるには、複雑さは、実際にO(高さ)で、ツリーに関連している時間に比例します。

完全なバイナリツリーを取得するにはどのようにn個のノードの高度が含まれていますか?

N個のノードの完全なバイナリツリーは、ノードは、第一層を含み含み、第二の層は第3層は4つのノードを備え、2つのノードを含みます。

そしてように、ノードの数が層の下2回層は、第一層Kに含まれるノードの数が2 ^(K-1)です。

完全2分木については、同法に不遵守の最後の層のノード番号。

我々は、層の最大数はLであり、ノードの数は、それが^(L-1)番目の1〜2の間の1つを含んでいると仮定する。

n >= 1+2+4+8+...+2^(L-2)+1
n <= 1+2+4+8+...+2^(L-2)+2^(L-1)

[LOG2(N + 1)、log2n +1]の範囲内の幾何学的配列の加算、Lは、層の数が少ない完全二分木log2n +1であり、木の高さは、層のマイナスの最大数に等しいです。

すなわち、以下log2nの完全二分木の高さです。

しかし、これは、よりバランスのとれた状況であるだけで理想的な状況です。

非常にアンバランスな二分探索木、その性能は確かに需要を満たすために見ていません。

私たちは、削除を構築する必要があるかに関係なく、データを挿入し、任意の時点で、任意のノードは、サブツリーがよりバランスされているバイナリ検索ツリーの周りを維持することができます。

その後、バイナリ検索ツリーの特別な種類を必要とする - 平衡二分探索木を

平衡二分探索木の高さに近いLOGN、挿入ので、削除、操作の時間計算量は比較的安定している見つけ、O(LOGN)があります。

公開された113元の記事 ウォン称賛25 ビュー30000 +

おすすめ

転載: blog.csdn.net/qq_42006733/article/details/104629382