17

さて、関連する他のすべての質問を読みましたが、Java に役立つ質問が見つかりません。他の言語で何ができるかを解読することで、一般的なアイデアを得ることができます。しかし、私はまだそれを理解していません。

問題:レベルソート(再帰を使用して作業しています)を行い、ツリーの一般的な形状で出力したいと思います。

だから私はこれを持っていると言います:

    1 
   / \
  2   3
 /   / \
4   5   6

私のコードは、次のようにレベルの順序を出力します。

1 2 3 4 5 6

私はこのようにそれを印刷したい:

1
2 3
4 5 6

私の仕事をすることについて道徳的なスピーチをする前に... 私はすでに AP Comp Sci プロジェクトを終えており、先生が幅優先探索について言及したとき、これについて興味を持ちました。

それが役立つかどうかはわかりませんが、これまでのところ私のコードは次のとおりです。

/**
  * Calls the levelOrder helper method and prints out in levelOrder.
  */
 public void levelOrder()
 {
  q = new QueueList();
  treeHeight = height();
  levelOrder(myRoot, q, myLevel);
 }

 /**
  * Helper method that uses recursion to print out the tree in 
  * levelOrder
  */
 private void levelOrder(TreeNode root, QueueList q, int curLev)
 {
  System.out.print(curLev);
  if(root == null)
  {
   return;
  }

  if(q.isEmpty())
  {
   System.out.println(root.getValue());
  }
  else
  {
   System.out.print((String)q.dequeue()+", ");
  }

  if(root.getLeft() != null)
  {
   q.enqueue(root.getLeft().getValue());
   System.out.println();
  }
  if(root.getRight() != null)
  {
   q.enqueue(root.getRight().getValue());
   System.out.println();
   curLev++;
  }

  levelOrder(root.getLeft(),q, curLev);
  levelOrder(root.getRight(),q, curLev);
 }

私が理解できることから、ツリーの合計の高さを使用し、レベルカウンターを使用する必要があります...唯一の問題は、levelOrderが再帰を使用してツリーを戻るときにレベルカウンターがカウントし続けることです。

これが多すぎる場合は申し訳ありませんが、いくつかのヒントがあれば幸いです。:)

4

23 に答える 23

29

これがコードです、この質問はインタビューの1つで私に尋ねられました...

public void printTree(TreeNode tmpRoot) {

        Queue<TreeNode> currentLevel = new LinkedList<TreeNode>();
        Queue<TreeNode> nextLevel = new LinkedList<TreeNode>();

        currentLevel.add(tmpRoot);

        while (!currentLevel.isEmpty()) {
            Iterator<TreeNode> iter = currentLevel.iterator();
            while (iter.hasNext()) {
                TreeNode currentNode = iter.next();
                if (currentNode.left != null) {
                    nextLevel.add(currentNode.left);
                }
                if (currentNode.right != null) {
                    nextLevel.add(currentNode.right);
                }
                System.out.print(currentNode.value + " ");
            }
            System.out.println();
            currentLevel = nextLevel;
            nextLevel = new LinkedList<TreeNode>();

        }

    }
于 2012-09-19T08:50:28.497 に答える
13

これが最も簡単な解決策です

public void byLevel(Node root){
     Queue<Node> level  = new LinkedList<>();
     level.add(root);
     while(!level.isEmpty()){
         Node node = level.poll();
         System.out.print(node.item + " ");
         if(node.leftChild!= null)
         level.add(node.leftChild);
         if(node.rightChild!= null)
         level.add(node.rightChild);
     }
}

https://github.com/camluca/Samples/blob/master/Tree.java 私のgithubには、次のようなクラスTreeの他の便利な関数があります。

ツリーの表示

****......................................................****
                            42
            25                              65                              
    12              37              43              87              
9      13      30      --      --      --      --      99      
****......................................................****
Inorder traversal
9 12 13 25 30 37 42 43 65 87 99  
Preorder traversal
42 25 12 9 13 37 30 65 43 87 99  
Postorder traversal
9 13 12 30 37 25 43 99 87 65 42  
By Level
42 25 65 12 37 43 87 9 13 30 99  
于 2012-12-07T15:39:56.250 に答える
8

これが私がそれを行う方法です:

levelOrder(List<TreeNode> n) {
    List<TreeNode> next = new List<TreeNode>();
    foreach(TreeNode t : n) {
        print(t);
        next.Add(t.left);
        next.Add(t.right);
    }
    println();
    levelOrder(next);
}

(本来はリアルコードのつもりでしたが、途中で飽きたので擬似コードです)

于 2010-02-11T01:04:46.587 に答える
5

実際のJavaコードでAnonの提案を共有し、いくつかのキーの問題を修正することを考えました(再帰の終了条件がないため、スタックへの追加が停止することはなく、受信した配列でnullをチェックしないとnullになります)ポインター例外)。

また、Eric Hauser が示唆するように例外はありません。これは、ループするコレクションを変更するのではなく、新しいコレクションを変更するためです。

ここに行きます:

public void levelOrder(List<TreeNode> n) {
    List<TreeNode> next = new ArrayList<TreeNode>();
    for (TreeNode t : n) {
        if (t != null) {
            System.out.print(t.getValue());
            next.add(t.getLeftChild());
            next.add(t.getRightChild());
        }
    }
    System.out.println();
    if(next.size() > 0)levelOrder(next);
}
于 2012-02-10T06:44:46.440 に答える
2

以下のメソッドは、レベルごとにすべてのノードを含む ArrayList の ArrayList を返します:-

 public ArrayList<ArrayList<Integer>> levelOrder(TreeNode root) {

    ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>(); 
    if(root == null) return result;
    Queue q1 = new LinkedList();
    Queue q2 = new LinkedList();

    ArrayList<Integer> list = new ArrayList<Integer>();
    q1.add(root);

    while(!q1.isEmpty() || !q2.isEmpty()){

        while(!q1.isEmpty()){
            TreeNode temp = (TreeNode)q1.poll();
            list.add(temp.val);
            if(temp.left != null) q2.add(temp.left);
            if(temp.right != null) q2.add(temp.right);
        }
        if(list.size() > 0)result.add(new ArrayList<Integer>(list));
        list.clear();
        while(!q2.isEmpty()){
            TreeNode temp = (TreeNode)q2.poll();
            list.add(temp.val);
            if(temp.left != null) q1.add(temp.left);
            if(temp.right != null) q1.add(temp.right);
        }
        if(list.size() > 0)result.add(new ArrayList<Integer>(list));
        list.clear();
    }
    return result;
}
于 2015-01-08T16:35:33.053 に答える
1

答えは近いです....私が見ることができる唯一の問題は、ツリーの特定の位置にノードがない場合、そのポインターをnullに設定することです。nullポインタをリストに入れようとするとどうなりますか?

これが私が最近の任務のためにしたことです。それは完璧に動作します。任意のルートから使用できます。

  //Prints the tree in level order
  public void printTree(){
    printTree(root);
  }

 public void printTree(TreeNode tmpRoot){

    //If the first node isn't null....continue on
    if(tmpRoot != null){

        Queue<TreeNode> currentLevel = new LinkedList<TreeNode>(); //Queue that holds the nodes on the current level
        Queue<TreeNode> nextLevel = new LinkedList<TreeNode>();     //Queue the stores the nodes for the next level

        int treeHeight = height(tmpRoot);     //Stores the height of the current tree
        int levelTotal = 0;  //keeps track of the total levels printed so we don't  pass the height and print a billion "null"s

        //put the root on the currnt level's queue
        currentLevel.add(tmpRoot);

        //while there is still another level to print and we haven't gone past the tree's height
        while(!currentLevel.isEmpty()&& (levelTotal< treeHeight)){

            //Print the next node on the level, add its childen to the next level's queue, and dequeue the node...do this until the current level has been printed
            while(!currentLevel.isEmpty()){

                //Print the current value
                System.out.print(currentLevel.peek().getValue()+" ");

                //If there is a left pointer, put the node on the nextLevel's stack. If there is no ponter, add a node with a null value to the next level's stack
                tmpRoot = currentLevel.peek().getLeft();
                if(tmpRoot != null)
                    nextLevel.add(tmpRoot);
                else
                    nextLevel.add(new TreeNode(null));

                //If there is a right pointer, put the node on the nextLevel's stack. If there is no ponter, add a node with a null value to the next level's stack
                tmpRoot = currentLevel.remove().getRight();
                if(tmpRoot != null)
                    nextLevel.add(tmpRoot);
                else
                    nextLevel.add(new TreeNode(null));

            }//end while(!currentLevel.isEmpty())

            //populate the currentLevel queue with items from the next level
            while(!nextLevel.isEmpty()){
                currentLevel.add(nextLevel.remove());
            }

            //Print a blank line to show height
            System.out.println("");

            //flag that we are working on the next level
            levelTotal++;

        }//end while(!currentLevel.isEmpty())

    }//end if(tmpRoot != null)

}//end method printTree

public int height(){
    return height(getRoot());
}

public int height(TreeNode tmpRoot){

    if (tmpRoot == null)
        return 0;
    int leftHeight = height(tmpRoot.getLeft());
    int rightHeight = height(tmpRoot.getRight());

    if(leftHeight >= rightHeight)
        return leftHeight + 1;
    else
        return rightHeight + 1;
 }
于 2010-12-01T06:21:30.080 に答える
1

レベルを追跡するために 2 つのキューを使用して、これを試してください。

public static void printByLevel(Node root){
    LinkedList<Node> curLevel = new LinkedList<Node>();
    LinkedList<Node> nextLevel = curLevel;

    StringBuilder sb = new StringBuilder();
    curLevel.add(root);
    sb.append(root.data + "\n");

    while(nextLevel.size() > 0){
        nextLevel = new LinkedList<Node>();
        for (int i = 0; i < curLevel.size(); i++){
            Node cur = curLevel.get(i);
            if (cur.left != null) {
                nextLevel.add(cur.left);
                sb.append(cur.left.data + " ");
            }
            if (cur.right != null) {
                nextLevel.add(cur.right);
                sb.append(cur.right.data + " ");
            }
        }
        if (nextLevel.size() > 0) {
            sb.append("\n");
            curLevel = nextLevel;

        } 
    }
    System.out.println(sb.toString());
}
于 2014-05-05T08:57:43.010 に答える
1

解決策

ここに直接的な解決策を書きました。詳細な回答、デモ コード、および説明が必要な場合は、回答の残りの見出しをスキップして確認できます。

public static <T> void printLevelOrder(TreeNode<T> root) {
    System.out.println("Tree;");
    System.out.println("*****");

    // null check
    if(root == null) {
        System.out.printf(" Empty\n");
        return;
    }

    MyQueue<TreeNode<T>> queue = new MyQueue<>();
    queue.enqueue(root);

    while(!queue.isEmpty()) {
        handleLevel(queue);
    }
}

// process each level
private static <T> void handleLevel(MyQueue<TreeNode<T>> queue) {
    int size = queue.size();

    for(int i = 0; i < size; i++) {
        TreeNode<T> temp = queue.dequeue();
        System.out.printf("%s ", temp.data);
        queue.enqueue(temp.left);
        queue.enqueue(temp.right);
    }

    System.out.printf("\n");
}

B - 説明

ツリーをレベル順に出力するには、単純なキューの実装を使用して各レベルを処理する必要があります。私のデモでは、MyQueueという非常に最小限の単純なキュー クラスを作成しました。

public メソッドは、ツリーのルートを表すパラメーターとしてオブジェクト インスタンスルートprintLevelOrderを受け取ります。プライベート メソッドは、インスタンスをパラメーターとして受け取ります。TreeNode<T>handleLevelMyQueue

各レベルで、handleLevelメソッドはキューのサイズと同じだけキューをデキューします。このプロセスは、そのレベルの要素と正確に等しいキューのサイズでのみ実行され、改行文字が出力に配置されるため、レベルの制限は制御されます。

C - TreeNode クラス

public class TreeNode<T> {

    T data;
    TreeNode<T> left;
    TreeNode<T> right;

    public TreeNode(T data) {
        this.data = data;;
    }

}

D - MyQueue クラス : シンプルなキューの実装

public class MyQueue<T> {

    private static class Node<T> {

        T data;
        Node next;

        public Node(T data) {
            this(data, null);
        }

        public Node(T data, Node<T> next) {
            this.data = data;
            this.next = next;
        }

    }

    private Node head;
    private Node tail;
    private int size;

    public MyQueue() {
        head = null;
        tail = null;
    }

    public int size() {
        return size;
    }

    public void enqueue(T data) {
        if(data == null)
            return;

        if(head == null)
            head = tail = new Node(data);
        else {
            tail.next = new Node(data);
            tail = tail.next;
        }

        size++;
    }

    public T dequeue() {

        if(tail != null) {
            T temp = (T) head.data;
            head = head.next;

            size--;

            return temp;
        }

        return null;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public void printQueue() {
        System.out.println("Queue: ");
        if(head == null)
            return;
        else {
            Node<T> temp = head;
            while(temp != null) {
                System.out.printf("%s ", temp.data);
                temp = temp.next;
            }
        }
        System.out.printf("%n");
    }
}

E - DEMO : ツリーをレベル順で印刷

public class LevelOrderPrintDemo {

    public static void main(String[] args) {
        // root level
        TreeNode<Integer> root = new TreeNode<>(1);

        // level 1
        root.left           = new TreeNode<>(2);
        root.right          = new TreeNode<>(3);

        // level 2
        root.left.left      = new TreeNode<>(4);

        root.right.left     = new TreeNode<>(5);
        root.right.right    = new TreeNode<>(6);

        /*
         *      1      root
         *     / \
         *    2   3    level-1
         *   /   / \
         *  4   5   6  level-2
         */

        printLevelOrder(root);
    }

    public static <T> void printLevelOrder(TreeNode<T> root) {
        System.out.println("Tree;");
        System.out.println("*****");

        // null check
        if(root == null) {
            System.out.printf(" Empty\n");
            return;
        }

        MyQueue<TreeNode<T>> queue = new MyQueue<>();
        queue.enqueue(root);

        while(!queue.isEmpty()) {
            handleLevel(queue);
        }
    }

    // process each level
    private static <T> void handleLevel(MyQueue<TreeNode<T>> queue) {
        int size = queue.size();

        for(int i = 0; i < size; i++) {
            TreeNode<T> temp = queue.dequeue();
            System.out.printf("%s ", temp.data);
            queue.enqueue(temp.left);
            queue.enqueue(temp.right);
        }

        System.out.printf("\n");
    }

}

F - サンプル入力

    1      // root
   / \
  2   3    // level-1
 /   / \
4   5   6  // level-2

G - サンプル出力

Tree;
*****
1 
2 3 
4 5 6 
于 2016-08-20T16:53:46.733 に答える
1
public class PrintATreeLevelByLevel {
public static class Node{
    int data;
    public Node left;
    public Node right;

    public Node(int data){
        this.data = data;
        this.left = null;
        this.right = null;

    }
}

public void printATreeLevelByLevel(Node n){
    Queue<Node> queue =  new LinkedList<Node>();
    queue.add(n);
    int node = 1; //because at root
    int child = 0; //initialize it with 0 
    while(queue.size() != 0){
        Node n1 = queue.remove();
        node--;
        System.err.print(n1.data +" ");

        if(n1.left !=null){
            queue.add(n1.left);
            child ++;
        }
        if(n1.right != null){
            queue.add(n1.right);
            child ++;
        }
        if( node == 0){
            System.err.println();
            node = child ;
            child = 0;
        }

    }


}

public static void main(String[]args){
    PrintATreeLevelByLevel obj = new PrintATreeLevelByLevel();
    Node node1 = new Node(1);
    Node node2 = new Node(2);
    Node node3 = new Node(3);
    Node node4 = new Node(4);
    Node node5 = new Node(5);
    Node node6 = new Node(6);
    Node node7 = new Node(7);
    Node node8 = new Node(8);

    node4.left = node2;
    node4.right = node6;
    node2.left = node1;
//  node2.right = node3;
    node6.left = node5;
    node6.right = node7;
    node1.left = node8;
    obj.printATreeLevelByLevel(node4);
}

}

于 2014-03-02T16:20:27.370 に答える
1

私は Anon のコードの単純さがとても気に入っています。そのエレガント。しかし、洗練されたコードが常に直感的に把握しやすいコードに変換されるとは限りませんそこで、Log(n) より多くのスペースを必要とする同様のアプローチを示しますが、深さ優先検索 (ツリーの長さを下っていく) に最も慣れている人にとってはより自然に読めるはずです。

次のコード スニペットは、リスト内の特定のレベルに属するノードを設定し、そのリストをツリーのすべてのレベルを保持するリストに配置します。したがって、List<List<BinaryNode<T>>>以下に表示されます。残りはかなり自明であるはずです。

public static final <T extends Comparable<T>> void printTreeInLevelOrder(
        BinaryTree<T> tree) {
    BinaryNode<T> root = tree.getRoot();
    List<List<BinaryNode<T>>> levels = new ArrayList<List<BinaryNode<T>>>();
    addNodesToLevels(root, levels, 0);
    for(List<BinaryNode<T>> level: levels){
        for(BinaryNode<T> node: level){
            System.out.print(node+ " ");
        }
        System.out.println();
    }
}

private static final <T extends Comparable<T>> void addNodesToLevels(
        BinaryNode<T> node, List<List<BinaryNode<T>>> levels, int level) {
    if(null == node){
        return;
    }

    List<BinaryNode<T>> levelNodes;
    if(levels.size() == level){
        levelNodes = new ArrayList<BinaryNode<T>>();
        levels.add(level, levelNodes);
    }
    else{
        levelNodes = levels.get(level);
    }

    levelNodes.add(node);
    addNodesToLevels(node.getLeftChild(), levels, level+1);
    addNodesToLevels(node.getRightChild(), levels, level+1);
}
于 2011-07-04T04:41:16.370 に答える
0
public void printAllLevels(BNode node, int h){
    int i;
    for(i=1;i<=h;i++){
        printLevel(node,i);
        System.out.println();
    }
}

public void printLevel(BNode node, int level){
    if (node==null)
        return;
    if (level==1)
        System.out.print(node.value + " ");
        else if (level>1){
            printLevel(node.left, level-1);
            printLevel(node.right, level-1);
        }
}

public int height(BNode node) {
    if (node == null) {
        return 0;
    } else {
        return 1 + Math.max(height(node.left),
                height(node.right));
    }
}

まず第一に、私はこのソリューションの功績を認めたくありません。これは誰かの関数の修正であり、解決策を提供するために調整しました。

ここでは 3 つの関数を使用しています。

  1. まず、木の高さを計算します。
  2. 次に、ツリーの特定のレベルを出力する関数があります。
  3. ツリーの高さとツリーのレベルを出力する関数を使用して、ツリーをトラバースし、3 番目の関数を使用してツリーのすべてのレベルを反復して出力します。

これが役立つことを願っています。

編集: レベル順トラバーサルですべてのノードを印刷するためのこのソリューションの時間の複雑さは O(n) ではありません。その理由は、レベルを下げるたびに、同じノードに何度もアクセスすることになるからです。

O(n) ソリューションをお探しの場合は、Queues を使用する方が良いと思います。

于 2012-02-17T01:36:39.453 に答える
0

上位のソリューションは、各ノードの子のみを一緒に出力します。説明によると、これは間違っています。

必要なのは、同じ行にまとめられた同じレベルのすべてのノードです。

1) BFS を適用する

2) ノードの高さを、ノードのリストであるレベルを保持するマップに格納します。

3) マップを繰り返し処理し、結果を出力します。

以下の Java コードを参照してください。

public void printByLevel(Node root){
    Queue<Node> q = new LinkedBlockingQueue<Node>();
    root.visited = true;
    root.height=1;
    q.add(root);
    //Node height - list of nodes with same level
    Map<Integer, List<Node>> buckets = new HashMap<Integer, List<Node>>();
    addToBuckets(buckets, root);
    while (!q.isEmpty()){
        Node r = q.poll();

        if (r.adjacent!=null)
        for (Node n : r.adjacent){
            if (!n.visited){
                n.height = r.height+1; //adjust new height
                addToBuckets(buckets, n);
                n.visited = true;
                q.add(n);
            }
        }
    }

    //iterate over buckets and print each list
    printMap(buckets);

}

//helper method that adds to Buckets list
private void addToBuckets(Map<Integer, List<Node>> buckets, Node n){
        List<Node> currlist = buckets.get(n.height);
    if (currlist==null)
    {
        List<Node> list = new ArrayList<Node>();
        list.add(n);
        buckets.put(n.height, list);
    }
    else{
        currlist.add(n);
    }

}

//prints the Map
private void printMap(Map<Integer, List<Node>> buckets){
    for (Entry<Integer, List<Node>> e : buckets.entrySet()){
        for (Node n : e.getValue()){
            System.out.print(n.value + " ");
        }
    System.out.println();
}
于 2013-10-05T20:18:50.773 に答える
0

これは、1 つのキュー自体を使用することで実現できると思います。これは、キューを 1 つだけ使用する Java 実装です。BFSに基づいて...

public void BFSPrint()
{
    Queue<Node> q = new LinkedList<Node>();
    q.offer(root);
    BFSPrint(q);
}

private void BFSPrint(Queue<Node> q)
{
    if(q.isEmpty())
        return;
    int qLen = q.size(),i=0;
     /*limiting it to q size when it is passed, 
       this will make it print in next lines. if we use iterator instead, 
       we will again have same output as question, because iterator 
       will end only q empties*/
    while(i<qLen) 
        {
        Node current = q.remove();
        System.out.print(current.data+" ");
        if(current.left!=null)
            q.offer(current.left);
        if(current.right!=null)
            q.offer(current.right);
        i++;
    }
    System.out.println();
    BFSPrint(q);

}
于 2012-10-04T07:12:02.850 に答える
0
        Queue<Node> queue = new LinkedList<>();
        queue.add(root);

        Node leftMost = null;
        while (!queue.isEmpty()) {
            Node node = queue.poll();

            if (leftMost == node) {
                System.out.println();
                leftMost = null;
            }

            System.out.print(node.getData() + " ");

            Node left = node.getLeft();
            if (left != null) {
                queue.add(left);
                if (leftMost == null) {
                    leftMost = left;
                }
            }

            Node right = node.getRight();
            if (right != null) {
                queue.add(right);

                if (leftMost == null) {
                    leftMost = right;
                }
            }
        }
于 2017-11-17T20:24:13.753 に答える