1.
二分探索木の概念二分探索木は二分木で構成されており、そのような木は、各ノードがオブジェクトであるリンクリストのデータ構造で表すことができます。
2.バイナリサーチツリーノードオブジェクトの属性
(1)キー(オブジェクト全体を表すために使用されるキーワード)
(2)基本データおよび情報
(3)左、右、およびp、それぞれノードの左の子ノードを指す、右の子ノード、親ノード(親ノードの使用量が少ない場合は省略できます)
class TreeNode {
int key; //关键字
TreeNode left; //左节点
TreeNode right; //右节点
TreeNode() {
}
TreeNode(int val) {
this.val = val; }
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
3.二分探索木の最も基本的な構築規則
どのノードノードでも、左側のサブツリーの各ノードのキーはnode.keyより大きくできず、右側のサブツリーの各ノードのキーはnode.keyより小さくできません。 。この構築ルールは、二分探索木のプロパティにつながる可能性があります。childNodeがノードの左側のサブツリーのノードである場合、childNode.key <= node.keyが同様に、右側のサブツリーにある場合、 childNode.key> = node.key。
4.バイナリツリー検索のトラバーサル
(1)バイナリツリーのトラバースには、BFS幅検索トラバーサルとDFSディープ検索トラバーサルの2つの主要な方法があります。幅検索トラバーサルのコアは、キューのデータ構造のアプリケーションです。ディープ検索トラバーサルには、 2つの方法があります。1つは再帰関数の設計をトラバースする方法、もう1つはスタックデータ構造を使用してトラバースする方法です。
1> DFS
//递归遍历
public void search(TreeNode root){
if(root==null)
return;
search(root.left);
search(root.right);
}
//利用栈进行遍历
public void search(TreeNode root){
public void search(TreeNode root) {
TreeNode node = root;
Stack<TreeNode> DFS = new Stack<>();
while (!DFS.isEmpty() || node != null) {
while (node != null) {
DFS.push(node);
node = node.left;
}
node = DFS.pop().right;
}
}
}
2> BFS
//利用队列进行遍历
public void search(TreeNode root){
TreeNode node=root;
Queue<TreeNode>DFS=new LinkedList<>();
DFS.offer(node);
while(!DFS.isEmpty()||node!=null){
node=DFS.poll();
if(node.left!=null)
DFS.offer(node.left);
if(node.right!=null)
DFS.offer(node.right);
}
}
(2)バイナリツリートラバーサルの高度なアルゴリズム:モリスアルゴリズム。Morrisアルゴリズムは、バイナリサーチツリーを走査する際のスペースの複雑さを大幅に軽減します。アルゴリズムは主に、バイナリサーチツリーに存在する必要がある多数の空のノードを使用します(エンドノードには空のノードが必要)またはキュー。
アルゴリズムの主なステップ:
1>。バイナリ検索ツリーの子ノードについて、ノードに左の子がない場合は、ノードの右の子にアクセスし、ノードに左の子がある場合は、ノードの左のサブツリー(つまり、ノードの左のサブツリー)で最も右のノードを見つけます。シーケンストラバーサルの最後のノード)がmorrisBackとして記録されます。
2>。morrisBackの右の子が空かどうかに応じて、次の操作を実行します。右の子が空の場合は、右の子をノードにポイントしてから左の子にアクセスします。右の子が空でない場合は、ノードをたどったことを意味します左側のサブツリーについては、morrisBackの右側の子を空のままにして(バイナリ検索ツリーの構造を破壊しないようにするため)、ノードの右側の子にアクセスします(サブツリーのヘッドノードに戻るか、右側のノードにアクセスします)。
3>。完全なツリーが表示されるまで上記の操作を繰り返します。
モリスアルゴリズム図:
画像のソース
class Solution {
public void Search(TreeNode root) {
TreeNode node=root;
TreeNode morrisBack;
while(node!=null){
if(node.left!=null){
morrisBack=node.left;
while(morrisBack.right!=null&&morrisBack.right!=node)
morrisBack=morrisBack.right;
if(morrisBack.right==null){
morrisBack.right=node;
node=node.left;
}
else{
morrisBack.right=null;
node=node.right;
}
}
else
node=node.right;
}
}
}
5.
二分木のトラバーサル分類二分木のトラバーサルアルゴリズムには、3つの特別な形式があり、前順トラバーサル、中次トラバーサル、および後続のトラバーサルです。
プリオーダートラバーサルの場合、これは、現在のノードの場合、最初にノード、次に左の子、最後に右の子にアクセスすることを意味します。
順序トラバーサルの場合、現在のノードでは、最初に左の子にアクセスし、次にノードにアクセスし、最後に右の子にアクセスします。(二分探索木の場合、中位のトラバーサルはノードのキー値の昇順でアクセスされ、ノードのキー値の昇順の配列を取得できます。)
後続のトラバーサルでは、現在のノードが最初です左の子、次に右の子、最後にノードにアクセスします。
上の図の二分探索木を例にとります:
予約注文トラバーサル:
//递归算法
class Solution {
public void search(TreeNode root) {
if(root ==null)
return;
System.out.print(root.val+" ");
search(root.left);
search(root.right);
}
}
//非递归算法
public void search(TreeNode root) {
TreeNode node = root;
Stack<TreeNode> DFS = new Stack<>();
while (!DFS.isEmpty() || node != null) {
while (node != null) {
System.out.print(node.val+" ");
DFS.push(node);
node = node.left;
}
node = DFS.pop().right;
}
}
出力結果:6 5 2 5 7 9 8
順序トラバーサル:
//递归算法
class Solution {
public void search(TreeNode root) {
if(root ==null)
return;
search(root.left);
System.out.print(root.val+" ");
search(root.right);
}
}
//非递归算法
public void search(TreeNode root) {
TreeNode node = root;
Stack<TreeNode> DFS = new Stack<>();
while (!DFS.isEmpty() || node != null) {
while (node != null) {
DFS.push(node);
node = node.left;
}
node = DFS.pop();
System.out.print(root.val+" ");
node=node.right;
}
}
出力結果:2 5 5 6 7 8 9
注文後の走査:
//递归算法
class Solution {
public void search(TreeNode root) {
if(root ==null)
return;
search(root.left);
search(root.right);
System.out.print(root.val+" ");
}
}
//非递归算法
public void search(TreeNode root) {
HashMap<TreeNode,Integer>check=new HashMap<>();
TreeNode node = root;
Stack<TreeNode> DFS = new Stack<>();
while (!DFS.isEmpty() || node != null) {
while (node != null) {
check.put(node,1);
DFS.push(node);
node = node.left;
}
node=DFS.peek();
if(check.get(node)==1){
check.put(node,2);
node=node.right;
}
else{
DFS.pop();
System.out.print(node.val+" ");
node=null;
}
}
}
出力結果:2 5 5 8 9 7 6