web-dev-qa-db-ja.com

定数空間とO(n)ランタイムを使用して、バイナリ検索ツリーの非再帰的走査を記述します

これは宿題ではなく、これはインタビューの質問です。

ここでの問題は、アルゴリズムが一定の空間であるべきだということです。スタックなしでこれを行う方法について私はかなり無知です。スタックを使用して書いたものを投稿しますが、とにかく関係ありません。

私が試したことは次のとおりです。事前注文のトラバーサルを試みて、左端のノードに到達しましたが、そこに留まっています。スタック/親ポインタなしでバックアップを「再帰」する方法がわかりません。

任意の助けをいただければ幸いです。

(私はJavaとしてタグ付けしていますが、それは私が使いやすいものだからですが、明らかなように言語にとらわれないのです。)

48
user183037

私はそれを完全に考えたわけではありませんでしたが、その過程であなたのツリーを台無しにすることをいとわない限り可能であると思います。

すべての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;
    }
  }
}
30
iluxa

Morris Inorderツリートラバーサルはどうですか?スレッド化されたツリーの概念に基づいており、ツリーを変更しますが、完了したら元に戻します。

リンキー: http://geeksforgeeks.org/?p=6358

余分なスペースを使用しません。

29
brainydexter

下向きのポインターベースのツリーを使用していて、親ポインターまたは他のメモリがない場合は、一定の空間を移動することはできません。

バイナリツリーがポインターベースのオブジェクト構造ではなく配列にある場合は可能です。ただし、その後、任意のノードに直接アクセスできます。それは一種の不正行為です;-)

4
jmg

これは、より短いバージョンの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]さらに、ツリールートノードに左の子がない場合でも機能します。

3
ens

ツリー自体を変更せずにバイナリツリーを走査できます(ノードに親ポインターがある場合)。そして、それは一定の空間で行うことができます。同じためにこの便利なリンクを見つけました http://tech.technoflirt.com/2011/03/04/non-recursive-tree-traversal-in-on-using-constant-space/

0
Priyanka

質問のタイトルは、ノードに「親」ポインターがないことを言及していません。 BSTには必ずしも必要ではありませんが、多くのバイナリツリーの実装には親ポインターがあります。 class Node {Node * left; Node * right; Node * parent; DATA data;};

これは、紙の上の木の図を画像化し、木の周りを鉛筆で描き、縁の両側から上下に移動する場合です(下に行くと、縁の左側になり、上に行くと、右側になります)。基本的に、4つの状態があります。

  1. 南西:あなたはEdgeの左側にあり、親から左の子へ
  2. 北東:左の子から親に戻る
  3. 南東:親から右の子に行く
  4. NorthWest:右の子から親に戻る
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;
        }
    }
}
0
Uri

これは検索ツリーなので、いつでも次のキー/エントリを取得できます

次のような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;
}
0
bestsss

受け入れられた回答には次の変更が必要です。それ以外の場合、BSTにノードが1つしかないツリーは出力されません。

if (current == NULL && root != NULL)
   print(root);
0
Steffen San

上記のiluxaの回答のマイナーな特別なケース

if(current== null)
        {
            current = root;
            parent = current.Right;
            if(parent != null)
            {
                current.Right = parent.Left;
                parent.Left = current;
            }
        }
0