他の解決策はO(n)だと思います。これに必要なのは、O(log n) の各ノードの子の数だけです。
ノードを挿入すると、トラバースするノードごとに、トラバースしたノードのカウンターが 1 ずつ増えます。
通常は難しくない削除、再調整などの際にこれらのカウンターを維持する必要があります。
これにより、挿入時にノードの位置を取得したり、値でノードの位置を見つけたり、位置でノードを見つけたりできます。
位置によるノードの検索は、値による検索と同じ種類のバイナリ トラバーサルです。アイテムを 1000 の位置に配置したい場合は、ルートから開始します。その位置のルートではなく、アイテムではありません。次に、左の子を見てください (他の順序でも実行でき、昇順/降順を切り替えることができます)。左の子が存在する場合、左の子の数は 0 に左の子の数を加えたものです。ノード。このシナリオで、左派が存在し、500 人の子供がいるとします。次に、1000 は左側に十分なアイテムがないため、残すことができないことがわかります。したがって、1000 は正しいに違いありません。これを繰り返して、境界をずっとチェックすることもできます。
単純な O(n) のトラバーサルの場合、グローバル カウンターがある場合は、左にトラバースした後にのみ増加させます。これは、深さ優先検索と同じことを行う必要があります。カウンターを増減したり、スタックをプッシュしたりポップしたりする必要はありません。関数でカウントを返すようにすることもできます。
public int inOrderTraverseTree(Node root){
if(root == null)
return 0;
int count = inOrderTraverseTree(root.leftChild);
count++;
count += inOrderTraverseTree(root.rightChild);
return count;
}
このアプローチは、ノードも返したい場合にのみ面倒になります。
もちろん、再帰関数を独自のスタックに置き換えることもできますが、これはほとんど必要とされないパフォーマンスの最適化であり、パフォーマンスが必要な場合は、最適化されたカスタム スタック ベースのソリューションよりも O(log n) ソリューションの方がはるかに優れています。