1: 二分探索木
次の構造を見てみましょう。下の図の二分探索ツリーは、二分探索ツリーおよび二分ソート ツリーとも呼ばれます。
次のような特徴があります。
1. 左のサブツリーが空でない場合、左のサブツリー上のノードの値はルート ノードより小さくなります。
2. 右のサブツリーが空でない場合、右のサブツリー上のノードの値はルート ノードより大きくなります。
3. サブツリーも上記 2 点に従う必要があります。
なぜバイナリソートツリーと呼ばれるのでしょうか?
バイナリ ツリーのトラバーサル方法:前層、中間層、後層 (Mysql)
ツリーが二分探索ツリーである限り、その順序内走査は順序通りでなければなりません。
左ルート (出力) 右側のバイナリ ツリーを見ると、その順序トラバーサルは次のようになります: 左ルート 右 左ルート (出力) 右: 0 3 4 5 6 8
これは二分探索アルゴリズムに似ています。数値を推測すると、0 から 100 までの数値が表示され、推測できるようになります。推測結果が大きすぎるか小さすぎるかを毎回教えてくれます。50 は大きすぎます -> 51 ~ 100 は小さすぎます 0 ~ 50、それぞれの推測でスペースの半分を削除できます マージ ソート、ログオン、順序付けされたシーケンス
2:二分探索木の追加、削除、変更、問い合わせ
二分探索挿入 5 3 6 0 4 8
挿入時には毎回ルートノードと比較されます。挿入すべき場所を常に見つけてください。必ずリーフノードに挿入されます。
実際、挿入することが実際には検索であることがわかります。
追加・変更チェック:簡易、主に削除
削除は次の 3 つの状況に分類できます。
1. 削除対象のノードはリーフノード O(1)
2. 削除するノードにはサブツリーが 1 つだけ (左または右) O(1) しかありません。
3. 削除するノードには 2 つのサブツリーがあります。後続ノードを見つけます。後続ノードの左側のサブツリーは空でなければなりません。
注: ここでの後続ノードは、削除される右側の最初のノードではなく、それより大きい最初のノードです。そうでない場合は、二分探索木の規則に準拠しないため、ソートできません。ノードのみが子ノードの場合は、削除の 2 番目のケースに相当します。そこで赤黒木が登場しました!
パフォーマンス:
ログの検索
挿入: nlogn。挿入する数値は n 個あります。各数値はまずその位置を見つける必要があります。これが logn です。合わせて nlogn です。単一の数値を挿入する場合は、logn である必要があります。
3: 二分木の応用
二分探索木の応用は何ですか?
O(n) for(int i = 0; i < n; i++){} 下の図と同様に、これも二分木ですが、順序付けされたシーケンスを挿入します。真ん中で分離された木が現れます。欠点はリンクリストに退化していることですが、検索ツリーなので検索にはそれを使用しなければなりません。その検索時間の計算量を分析してみましょう: 右側の 2 つの二分探索ツリーを見てください: それらのパフォーマンス: 検索時間の計算量は実際にはツリーの深さ O(n) であり、これは時間計算量を意味します: N 回検索します。なぜ N 回循環 (縮退) されたのでしょうか? どうやって解決すればいいでしょうか?鎖のようにならないように
AVL ツリー (絶対平衡ツリー): 赤黒ツリーと平衡二分木: AVL は実験室状態に属し、プロジェクトでは赤黒ツリーが使用されます。
3.1 バイナリコード
package tree;
public class BinarySeachTree {
private int color = 0; //0表示黑,1表示红
int data;
BinarySeachTree left;
BinarySeachTree right;
BinarySeachTree parent;
public BinarySeachTree(int data) {
this.data = data;
this.left = null;
this.parent = null;
this.color = 1;
this.right = null;
//parent.parent ;爷爷
//parent.parent.left 左边的叔叔
//parent.left 兄弟姐妹
}
//插入的时候每次都是和根结点比较。一直要找到它应该插入的位置。
//肯定会插在叶子结点。那么其实大家可以看到 插入其实就是查找。 默认root不会为空
public void insert(BinarySeachTree root,int data) {
//if(root == null) {}
if(root.data < data) { //根节点小 我们要放到右边
if(root.right == null) {
root.right = new BinarySeachTree(data);
}else {
insert(root.right, data);
}
}else {
if(root.left == null) {
root.left = new BinarySeachTree(data);
}else {
insert(root.left, data);
}
}
}
public void find(BinarySeachTree root,int data) {
if(root != null) {
if(root.data < data) {
find(root.right, data);
}else if(root.data > data) {
find(root.left, data);
}else {
System.out.println("找到了");
System.out.println(root.data);
return ;
}
}
}
public void pre() {
}
public void post() {
}
public void in(BinarySeachTree root) { //中序遍历
if(root != null) {
in(root.left);
System.out.print(root.data + " ");
in(root.right);
}
}
public static void main(String[] args) {
//快速排序,归并排序,二叉树排序
int data[] = {0,5,9,1,2,3,10};
BinarySeachTree root = new BinarySeachTree(data[0]); //第一个点作为跟结点
for(int i = 1 ; i < data.length ; i ++) {
root.insert(root, data[i]);
}
System.out.println("中序遍历:");
root.in(root);
}
}
4: 赤黒木の紹介 (所有物、左巻き、右巻き)
上の 2 つの図から、バイナリ ツリーの構造が検索パフォーマンスを決定することがわかります。では、それをどのように最適化すればよいでしょうか?
AVL の木と赤黒の木があります
AVL ツリー: バランスの取れたバイナリ ツリー。左右のサブツリー間の高さの差は 1 を超えません。これにより確かに直線構造を回避できますが、最も理想的なものではありません。
それは理想的な状態、実験室と考えることができます。赤黒い木
なぜ?総合的なパフォーマンスの考慮事項に基づいて選択します。
赤黒木の性質(重要なポイント):
1. 各ノードは赤または黒のいずれかです
2. 赤いノードを接続することはできません (黒いノードは問題ありません)。各リーフ ノードは黒い空のノード (NIL) です。つまり、リーフ ノードにはデータが格納されません。
3. ルート ノードはすべて黒のルートです 4. 各ノード、およびそのノードから到達可能な葉ノードまでのすべてのパスには、同じ数の黒のノードが含まれます。
4.2 赤黒木の 3 つの変形
1. 色の変更: 最も単純、赤から黒、黒から赤
2. 左回転: ポイントの回転の場合、ポイントの上のサブツリーも従う必要があります。ポインタ
3. 右回転:
では、上記の 3 つの方法をどのように選択すればよいのでしょうか?
4.3 ルールの挿入
挿入時の回転と色変換のルール:
1. 色の変化の状況: 現在のノードの親ノードは赤で、その祖父ノードの別の子ノードも赤です。(叔父ノード): (1) 親ノードを黒に設定します (2) 叔父を黒に設定します (3) 父の父親である祖父を赤に設定します (おじいちゃん) (4) 祖父ノードへのポインタを定義します (おじいちゃん) ) が現在の動作に設定されます。
2. 左回転: 現在の親ノードが赤、叔父が黒の場合、現在のノードは右のサブツリーになります。左回転では、親ノードを左回転として使用します。ポインタが親ノードに変わります
3. 右回転: 現在の親ノードが赤、叔父が黒の場合、現在のノードは左側のサブツリーになります。右回転 (1) 親ノードを黒にする (2) 祖父ノードを赤にする(おじいちゃん) (3) 祖父ノードを回転する(おじいちゃん)
赤黒ツリーの削除 正直に言うと、赤黒ツリーの削除が一番難しいので、ここではマスターしなければならない要件は書きませんが、二分探索の削除原理はマスターしておく必要があります。だって、左右のどんでん返しを徹底的に覚えたとしても、数日もすれば忘れてしまうこと請け合いです。赤黒ツリーのコード実装を学習しても、日々のプロジェクト開発にはあまり役に立ちません。ほとんどの人にとって、赤黒の木を今生で手書きすることは決してないかもしれません。また、アルゴリズム面接ではほとんど役に立ちません。通常であれば、赤黒木を手書きで書けとは普通の人は言わないでしょう。せいぜい原理について聞かれるだけですが、二分探索木は必ず書かなければならないものです。面接中に疑似コードを書くように求められる場合があります。
赤黒ツリーのパフォーマンス解析 挿入近似: nlogn logn の検索 削除: 近似 logn
赤黒ツリーのアプリケーション: 1. HashMap 2. TreeMap 3. Windows 最下層: 検索 4. Linux プロセス スケジューリング、nginx など。