これは宿題ではなく、これはインタビューの質問です。
ここでの問題は、アルゴリズムが一定の空間であるべきだということです。スタックなしでこれを行う方法について私はかなり無知です。スタックを使用して書いたものを投稿しますが、とにかく関係ありません。
私が試したことは次のとおりです。事前注文のトラバーサルを試みて、左端のノードに到達しましたが、そこに留まっています。スタック/親ポインタなしでバックアップを「再帰」する方法がわかりません。
任意の助けをいただければ幸いです。
(私はJavaとしてタグ付けしていますが、それは私が使いやすいものだからですが、明らかなように言語にとらわれないのです。)
私はそれを完全に考えたわけではありませんでしたが、その過程であなたのツリーを台無しにすることをいとわない限り可能であると思います。
すべてのNodeには2つのポインターがあるため、二重にリンクされたリストを表すために使用できます。RootからRoot.Left = Currentに進むと仮定します。 Current.Rightになり、Current.Leftに進みます。左端の子に到達するまでに、いくつかのノードからツリーがぶら下がっているリンクリストが作成されます。あなたが行く
編集:考え抜いた。順番に印刷するアルゴリズムは次のとおりです。
void traverse (Node root) {
traverse (root.left, root);
}
void traverse (Node current, Node parent) {
while (current != null) {
if (parent != null) {
parent.left = current.right;
current.right = parent;
}
if (current.left != null) {
parent = current;
current = current.left;
} else {
print(current);
current = current.right;
parent = null;
}
}
}
Morris Inorderツリートラバーサルはどうですか?スレッド化されたツリーの概念に基づいており、ツリーを変更しますが、完了したら元に戻します。
リンキー: http://geeksforgeeks.org/?p=6358
余分なスペースを使用しません。
下向きのポインターベースのツリーを使用していて、親ポインターまたは他のメモリがない場合は、一定の空間を移動することはできません。
バイナリツリーがポインターベースのオブジェクト構造ではなく配列にある場合は可能です。ただし、その後、任意のノードに直接アクセスできます。それは一種の不正行為です;-)
これは、より短いバージョンのiluxaの 元の答え です。まったく同じ順序で、まったく同じノード操作および印刷手順を実行しますが、単純化された方法で実行します[1]:
void traverse (Node n) {
while (n) {
Node next = n.left;
if (next) {
n.left = next.right;
next.right = n;
n = next;
} else {
print(n);
n = n.right;
}
}
}
[1]さらに、ツリールートノードに左の子がない場合でも機能します。
ツリー自体を変更せずにバイナリツリーを走査できます(ノードに親ポインターがある場合)。そして、それは一定の空間で行うことができます。同じためにこの便利なリンクを見つけました http://tech.technoflirt.com/2011/03/04/non-recursive-tree-traversal-in-on-using-constant-space/
質問のタイトルは、ノードに「親」ポインターがないことを言及していません。 BSTには必ずしも必要ではありませんが、多くのバイナリツリーの実装には親ポインターがあります。 class Node {Node * left; Node * right; Node * parent; DATA data;};
これは、紙の上の木の図を画像化し、木の周りを鉛筆で描き、縁の両側から上下に移動する場合です(下に行くと、縁の左側になり、上に行くと、右側になります)。基本的に、4つの状態があります。
Traverse( Node* node )
{
enum DIRECTION {SW, NE, SE, NW};
DIRECTION direction=SW;
while( node )
{
// first, output the node data, if I'm on my way down:
if( direction==SE or direction==SW ) {
out_stream << node->data;
}
switch( direction ) {
case SW:
if( node->left ) {
// if we have a left child, keep going down left
node = node->left;
}
else if( node->right ) {
// we don't have a left child, go right
node = node->right;
DIRECTION = SE;
}
else {
// no children, go up.
DIRECTION = NE;
}
break;
case SE:
if( node->left ) {
DIRECTION = SW;
node = node->left;
}
else if( node->right ) {
node = node->right;
}
else {
DIRECTION = NW;
}
break;
case NE:
if( node->right ) {
// take a u-turn back to the right node
node = node->right;
DIRECTION = SE;
}
else {
node = node->parent;
}
break;
case NW:
node = node->parent;
break;
}
}
}
これは検索ツリーなので、いつでも次のキー/エントリを取得できます
次のようなsmthが必要です(コードはテストしませんでしたが、できるだけ簡単です)
Java.util.NavigableMap<K, V> map=...
for (Entry<K, V> e = map.firstEntry(); e!=null; e = map.higherEntry(e.getKey())) {
process(e)
}
わかりやすくするため、これはhigherEntry
であるため、再帰的ではありません。そこにある:)
final Entry<K,V> getHigherEntry(K key) {
Entry<K,V> p = root;
while (p != null) {
int cmp = compare(key, p.key);
if (cmp < 0) {
if (p.left != null)
p = p.left;
else
return p;
} else {
if (p.right != null) {
p = p.right;
} else {
Entry<K,V> parent = p.parent;
Entry<K,V> ch = p;
while (parent != null && ch == parent.right) {
ch = parent;
parent = parent.parent;
}
return parent;
}
}
}
return null;
}
受け入れられた回答には次の変更が必要です。それ以外の場合、BSTにノードが1つしかないツリーは出力されません。
if (current == NULL && root != NULL)
print(root);
上記のiluxaの回答のマイナーな特別なケース
if(current== null)
{
current = root;
parent = current.Right;
if(parent != null)
{
current.Right = parent.Left;
parent.Left = current;
}
}