web-dev-qa-db-ja.com

インオーダーツリートラバーサル:正しい定義はどれですか。

私はバイナリツリー(BSTではない)の順序トラバーサル(パンキャッキングとも呼ばれます)について少し前に取り上げたアカデミックコースからの次のテキストを持っています:

Inorderツリートラバーサル

木の外側に線を引きます。ルートの左側から開始し、ツリーの外側を回って、ルートの右側に到達します。できるだけ木に近づきますが、木を越えないでください。 (ツリー-その枝とノード-を堅固な障壁として考えてください。)ノードの順序は、この線がその下を通過する順序です。ノードの「下」に移動するタイミングがわからない場合は、常に「左側」のノードが最初に来ることに注意してください。

使用した例を以下に示します(下とは少し異なるツリー)

tree 1

しかし、Googleで検索すると、矛盾する定義が表示されます。たとえば wikipedia example

Tree definition

順序トラバーサルシーケンス:A、B、C、D、E、F、G、H、I(左子、ルートノード、右ノード)

しかし、定義#1(私の理解)によれば、これは

A、B、D、C、E、F、G、I、H

誰がどの定義が正しいかを明確にできますか?どちらも異なるトラバーサルメソッドを説明している可能性がありますが、たまたま同じ名前を使用しています。査読済みの学術テキストが間違っているとは信じられませんが、確信が持てません。

21
Chris S

絵を描くのが苦手だったのですが、どのように選ぶかを示した順番です。 alt text

描画される線の真上にあるノードをほぼ選択します。

36
John Boker

定義を忘れてください。アルゴリズムを適用する方がはるかに簡単です。

void inOrderPrint(Node root)
{
  if (root.left != null) inOrderPrint(root.left);
  print(root.name);
  if (root.right != null) inOrderPrint(root.right);
}

たった3行です。事前注文と事後注文の順序を並べ替えます。

26
Andrew Coleson

注意深く読むと、最初の「定義」がルートのleftを開始するように言っており、ノードの順序はnderを渡すときに決定されます。したがって、Bは最初のノードではありません。左からAに渡してから、最初にnderAを渡してから、上に移動してnderBを渡します。したがって、両方の定義で同じ結果が得られるようです。

4
mweerden

私が個人的に見つけた この講義 非常に役に立った。

2
c4il

aのルートを持つ最初のバイナリツリーは、正しく構築されていないバイナリツリーだと思います。

ツリーの左側がすべてルートより小さく、ツリーのすべての右側がルート以上になるように実装してください。

適切なトラバーサルは、次のとおりです。リーフノード(ルートノードではない)を使用して可能な限り左

左根右

A B NULL

C D E

ヌルF G

H I NULL

Fはルートまたは左です。よくわかりません

1
Vishal S

どちらの定義でも同じ結果になります。最初の例のletterにだまされないでください-パスに沿った数字を見てください。 2番目の例では、パスを示すのに文字を使用しています。おそらくそれが原因であなたを失っています。

たとえば、最初のツリーのアルゴリズムを使用して2番目のツリーをトラバースする方法を示す順序の例では、「B」の後に「D」を配置しますが、左側の子ノードがまだあるため、そうしないでください。 Dが利用可能(それが最初の項目が「この行が通過する順序それら」)と言う理由です。

1

これは遅いかもしれませんが、後で誰にとっても役立つ可能性があります.. uダミーまたはnullノードを無視する必要はありません。たとえば、Node Gは左nullノードを持っています..このnullノードを考慮すると、すべてのことを行います大丈夫..

1
Ahmad Ibrahem

しかし、定義#1(私の理解)によれば、これは

A, B, D, C, E, F, G, I, H

残念ながら、あなたの理解は間違っています。

ノードに到着したときはいつでも、現在のノードを見る前に、利用可能な左側のノードに降りてから、利用可能な右側のノードを調べる必要があります。 Cの前にDを選択した場合、最初に左側のノードに降下しませんでした。

0
Calyth
void
inorder (NODE root)
{
  if (root != NULL)
    {
      inorder (root->llink);
      printf ("%d\t", root->info);
      inorder (root->rlink);
    }
}

これは、順序トラバーサルを再帰的に定義する最も簡単な方法です。この関数をメイン関数で呼び出して、特定のバイナリツリーの順序トラバーサルを取得します。

0
Chandra Kanth

私によれば、ウィキで述べられているように、インオーダートラバーサルのシーケンスは左ルート右です。

A、B、C、D、E、Fまでは、すでに理解していると思います。今度はルートFの次のノードはGで、左のノードではなく右のノードを持っているため、ルール(左ルート右)のnull-g右に従います。今、私はGの右ノードですが、左ノードがあるので、トラバーサルはGHIになります。これは正しいです。

お役に立てれば。

0
swaps

パッケージデータ構造;

パブリッククラスBinaryTreeTraversal {

public static Node<Integer> node;

public static Node<Integer> sortedArrayToBST(int arr[], int start, int end) {
    if (start > end)
        return null;

    int mid = start + (end - start) / 2;
    Node<Integer> node = new Node<Integer>();
    node.setValue(arr[mid]);

    node.left = sortedArrayToBST(arr, start, mid - 1);
    node.right = sortedArrayToBST(arr, mid + 1, end);
    return node;
}

public static void main(String[] args) {

    int[] test = new int[] { 1, 2, 3, 4, 5, 6, 7 };
    Node<Integer> node = sortedArrayToBST(test, 0, test.length - 1);

    System.out.println("preOrderTraversal >> ");

    preOrderTraversal(node);

    System.out.println("");

    System.out.println("inOrderTraversal >> ");

    inOrderTraversal(node);

    System.out.println("");

    System.out.println("postOrderTraversal >> ");

    postOrderTraversal(node);

}

public static void preOrderTraversal(Node<Integer> node) {

    if (node != null) {

        System.out.print(" " + node.toString());
        preOrderTraversal(node.left);
        preOrderTraversal(node.right);
    }

}

public static void inOrderTraversal(Node<Integer> node) {

    if (node != null) {

        inOrderTraversal(node.left);
        System.out.print(" " + node.toString());
        inOrderTraversal(node.right);
    }

}

public static void postOrderTraversal(Node<Integer> node) {

    if (node != null) {

        postOrderTraversal(node.left);

        postOrderTraversal(node.right);

        System.out.print(" " + node.toString());
    }

}

}

パッケージデータ構造;

パブリッククラスNode {

E value = null;
Node<E> left;
Node<E> right;

public E getValue() {
    return value;
}

public void setValue(E value) {
    this.value = value;
}

public Node<E> getLeft() {
    return left;
}

public void setLeft(Node<E> left) {
    this.left = left;
}

public Node<E> getRight() {
    return right;
}

public void setRight(Node<E> right) {
    this.right = right;
}

@Override
public String toString() {
    return " " +value;
}

}

preOrderTraversal >> 4 2 1 3 6 5 7 inOrderTraversal >> 1 2 3 4 5 6 7 postOrderTraversal >> 1 3 2 5 7 6 4

0
Neel Salpe

インラインツリートラバーサルの場合、トラバーサルの順序は左ノード右であることに注意する必要があります。競合している上記の図の場合、左側のリーフ(子)ノードを読み取る前に親ノードを読み取ると、エラーが発生します。

適切なトラバーサルは次のようになります:リーフノードで可能な限り左(A)、親ノード(B)に戻り、右に移動しますが、Dにはその子が左にあるため、再び下に移動します(C)、バックアップします。 Cの親(D)に、Dの右の子(E)に、ルート(F)に逆戻りし、右の葉(G)に移動し、Gの葉に移動しますが、左の葉ノードがあるため、そこに移動します(H) 、parent(I)に戻ります。

上記のトラバーサルでは、括弧内にリストされているノードを読み取ります。

0
Matt