バイナリツリーで値を見つけようとしていて、探している値を持つノードを返しています。
値がツリーの非常に深いレベルにない場合にうまく機能するアルゴリズムを実行しましたが、値が深い位置にある場合、Java.lang.StackOverflowError
。これが私のコードです:
class Node {
// keep these fields
Node left, right;
int value;
public Node find(int v){
if(v > this.value && this.right != null)
return right.find(v);
if(v < this.value && this.left != null)
return left.find(v);
if(this.value == v)
return this;
return null;
}
}
誰でも私にこの問題の解決策を提案できますか?.
最も単純なアプローチは、これをwhile
ループに変換することです。これは、「テストしている現在のノード」の状態を維持するだけです。
ループの反復ごとに、3つの可能性があります。
だから次のようなもの:
public Node find(int v) {
Node current = this;
while (current != null) {
if (current.value == v) {
return current;
}
// This will drop out of the loop naturally if there's no appropriate subnode
current = v < current.value ? current.left : current.right;
}
return null;
}
またはさらに少ないコードで、おそらくおそらく読みにくくなります:
public Node find(int v) {
Node current = this;
// Keep navigating down the tree until either we've run
// out of nodes to look at, or we've found the right value.
while (current != null && current.value != v) {
current = v < current.value ? current.left : current.right;
}
return current;
}
反復としてリキャストしたコードの例:
class Node {
// keep these fields
Node left, right;
int value;
public Node find(int v){
Node n = this;
while (n != null)
{
if (v > n.value)
n = n.right;
else if (v < n.value)
n = n.left;
else // v == n.value
return n;
}
return null;
}
}
編集:不明な場合に備えて、これがどのように機能するかについてのメモ。現在のノードに到達した方法について何も覚えておく必要はないので、検索する必要がある現在のサブツリーのルートのみを追跡します。各ステップで、検索するサブツリーが残っていない(最初の条件)、左側または右側にサブツリーがある(中央の2つの条件)、または実際にルートのルートで値を見つけたと判断しました現在のサブツリー(最後の条件)。サブツリーが不足するまで(while条件)、探し続けます。不足した場合は、値がツリー内にないことがわかり、nullを返します。
編集:コメントで指摘されているように、連続するif
sの使用は問題です。 if/else if/elseを使用するようにコードを更新しました。
ツリー検索は、大規模な配列の反復を回避するために使用されます。
ツリーアプローチの弱点は、ノード値が順序付けられることです。ツリーが読み込まれると、すべてのノードが左または右に移動し、多くの再帰が発生します。そうは言っても、スタックオーバーフローは多くの再帰を必要とします。
ツリーのバランスを取る傾向がある値をハッシュするか、特定のブランチが長くなりすぎた場合にツリーのバランスをとるようにツリー構築アルゴリズムを拡張できます。
とはいえ、スタックオーバーフローを引き起こすのに十分な数のノードがツリー内にあることも確認する必要があります。ここに示されていないコードにバグがある可能性があります。