漂亮打印二叉树 - 从C ++转换为Java

时间:2011-02-13 09:50:22

标签: java c++ tree binary-tree pretty-print

有人可以根据以下类作为Node类帮助实现Java中this website中的代码:

public class Node<A extends Comparable<A>> {
Node<A> left, right;
A data;

public Node(A data){
    this.data = data;
}
}

代码用于漂亮打印二进制树:

    #include <fstream>
#include <iostream>
#include <deque>
#include <iomanip>
#include <sstream>
#include <string>
#include <cmath>
using namespace std;

struct BinaryTree {
  BinaryTree *left, *right;
  int data;
  BinaryTree(int val) : left(NULL), right(NULL), data(val) { }
};

// Find the maximum height of the binary tree
int maxHeight(BinaryTree *p) {
  if (!p) return 0;
  int leftHeight = maxHeight(p->left);
  int rightHeight = maxHeight(p->right);
  return (leftHeight > rightHeight) ? leftHeight + 1: rightHeight + 1;
}

// Convert an integer value to string
string intToString(int val) {
  ostringstream ss;
  ss << val;
  return ss.str();
}

// Print the arm branches (eg, /    \ ) on a line
void printBranches(int branchLen, int nodeSpaceLen, int startLen, int nodesInThisLevel, const deque<BinaryTree*>& nodesQueue, ostream& out) {
  deque<BinaryTree*>::const_iterator iter = nodesQueue.begin();
  for (int i = 0; i < nodesInThisLevel / 2; i++) {
    out << ((i == 0) ? setw(startLen-1) : setw(nodeSpaceLen-2)) << "" << ((*iter++) ? "/" : " ");
    out << setw(2*branchLen+2) << "" << ((*iter++) ? "\\" : " ");
  }
  out << endl;
}

// Print the branches and node (eg, ___10___ )
void printNodes(int branchLen, int nodeSpaceLen, int startLen, int nodesInThisLevel, const deque<BinaryTree*>& nodesQueue, ostream& out) {
  deque<BinaryTree*>::const_iterator iter = nodesQueue.begin();
  for (int i = 0; i < nodesInThisLevel; i++, iter++) {
    out << ((i == 0) ? setw(startLen) : setw(nodeSpaceLen)) << "" << ((*iter && (*iter)->left) ? setfill('_') : setfill(' '));
    out << setw(branchLen+2) << ((*iter) ? intToString((*iter)->data) : "");
    out << ((*iter && (*iter)->right) ? setfill('_') : setfill(' ')) << setw(branchLen) << "" << setfill(' ');
  }
  out << endl;
}

// Print the leaves only (just for the bottom row)
void printLeaves(int indentSpace, int level, int nodesInThisLevel, const deque<BinaryTree*>& nodesQueue, ostream& out) {
  deque<BinaryTree*>::const_iterator iter = nodesQueue.begin();
  for (int i = 0; i < nodesInThisLevel; i++, iter++) {
    out << ((i == 0) ? setw(indentSpace+2) : setw(2*level+2)) << ((*iter) ? intToString((*iter)->data) : "");
  }
  out << endl;
}

// Pretty formatting of a binary tree to the output stream
// @ param
// level  Control how wide you want the tree to sparse (eg, level 1 has the minimum space between nodes, while level 2 has a larger space between nodes)
// indentSpace  Change this to add some indent space to the left (eg, indentSpace of 0 means the lowest level of the left node will stick to the left margin)
void printPretty(BinaryTree *root, int level, int indentSpace, ostream& out) {
  int h = maxHeight(root);
  int nodesInThisLevel = 1;

  int branchLen = 2*((int)pow(2.0,h)-1) - (3-level)*(int)pow(2.0,h-1);  // eq of the length of branch for each node of each level
  int nodeSpaceLen = 2 + (level+1)*(int)pow(2.0,h);  // distance between left neighbor node's right arm and right neighbor node's left arm
  int startLen = branchLen + (3-level) + indentSpace;  // starting space to the first node to print of each level (for the left most node of each level only)

  deque<BinaryTree*> nodesQueue;
  nodesQueue.push_back(root);
  for (int r = 1; r < h; r++) {
    printBranches(branchLen, nodeSpaceLen, startLen, nodesInThisLevel, nodesQueue, out);
    branchLen = branchLen/2 - 1;
    nodeSpaceLen = nodeSpaceLen/2 + 1;
    startLen = branchLen + (3-level) + indentSpace;
    printNodes(branchLen, nodeSpaceLen, startLen, nodesInThisLevel, nodesQueue, out);

    for (int i = 0; i < nodesInThisLevel; i++) {
      BinaryTree *currNode = nodesQueue.front();
      nodesQueue.pop_front();
      if (currNode) {
          nodesQueue.push_back(currNode->left);
          nodesQueue.push_back(currNode->right);
      } else {
        nodesQueue.push_back(NULL);
        nodesQueue.push_back(NULL);
      }
    }
    nodesInThisLevel *= 2;
  }
  printBranches(branchLen, nodeSpaceLen, startLen, nodesInThisLevel, nodesQueue, out);
  printLeaves(indentSpace, level, nodesInThisLevel, nodesQueue, out);
}

int main() {
  BinaryTree *root = new BinaryTree(30);
  root->left = new BinaryTree(20);
  root->right = new BinaryTree(40);
  root->left->left = new BinaryTree(10);
  root->left->right = new BinaryTree(25);
  root->right->left = new BinaryTree(35);
  root->right->right = new BinaryTree(50);
  root->left->left->left = new BinaryTree(5);
  root->left->left->right = new BinaryTree(15);
  root->left->right->right = new BinaryTree(28);
  root->right->right->left = new BinaryTree(41);

  cout << "Tree pretty print with level=1 and indentSpace=0\n\n";
  // Output to console
  printPretty(root, 1, 0, cout);

  cout << "\n\nTree pretty print with level=5 and indentSpace=3,\noutput to file \"tree_pretty.txt\".\n\n";
  // Create a file and output to that file
  ofstream fout("tree_pretty.txt");
  // Now print a tree that's more spread out to the file
  printPretty(root, 5, 0, fout);

  return 0;
}

http://www.ihas1337code.com/2010/09/how-to-pretty-print-binary-tree.html

1 个答案:

答案 0 :(得分:3)

Java中没有直接替换setw和setfill方法。但是,您可以创建一个包装PrintStream的新对象,并在写入某些输出时添加所需的填充。例如:

import java.io.PrintStream;
import java.util.Arrays;

public class PaddedWriter {
    private int width = 0;
    private char fillChar = ' ';
    private final PrintStream writer;
    public PaddedWriter(PrintStream writer) {
        this.writer = writer;
    }
    void setw(int i) {
        width = i;
    }
    void setfill(char c) {
        fillChar = c;
    }
    void write(String str) {
        write(str.toCharArray());
    }
    void write(char[] buf) {
        if (buf.length < width) {
            char[] pad = new char[width - buf.length];
            Arrays.fill( pad, fillChar );
            writer.print(pad);
        }
        writer.print( buf );
        setw(0);
    }
    void write() {
        char[] pad = new char[width];
        Arrays.fill( pad, fillChar );
        writer.print(pad);
        setw(0);
    }
    void endl() {
        writer.println();
        setw(0);
    }
}

使用PaddedWriter类可以重新实现http://www.ihas1337code.com/2010/09/how-to-pretty-print-binary-tree.html中的代码,如下所示:

import java.util.Deque;
import java.util.Iterator;
import java.util.LinkedList;


public class BinaryTree<T> {
    final T data;
    BinaryTree<T> left;
    BinaryTree<T> right;
    public BinaryTree(T t) {
        data  = t;
    }

    public void setLeft(BinaryTree<T> t) {
        left = t;
    }
    public void setRight(BinaryTree<T> t) {
        right = t;
    }

    public BinaryTree<T> getLeft() {
        return left;
    }
    public BinaryTree<T> getRight() {
        return right;
    }
    @Override
    public String toString() {
        if (data == null) {
            return "null";
        } else {
            return data.toString();
        }
    }


    // Search for the deepest part of the tree
    private static <T>int maxHeight(BinaryTree<T> t) {
        if (t == null)  return 0;
        int leftHeight = maxHeight( t.getLeft() );
        int rightHeight = maxHeight( t.getRight() );
        return (leftHeight > rightHeight) ? leftHeight+1: rightHeight+1;
    }

    // Pretty formatting of a binary tree to the output stream
    public static <T>void printPretty(BinaryTree<T> tree, int level, int indentSpace, PaddedWriter out) {
        int h = maxHeight( tree );
        int nodesInThisLevel = 1;
        int branchLen = 2*((int)Math.pow( 2.0, h )-1) - (3-level) *(int)Math.pow( 2.0, h-1 );
        int nodeSpaceLen = 2+(level+1)*(int)Math.pow(2.0,h);
        int startLen = branchLen + (3-level) + indentSpace;

        Deque<BinaryTree<T>> nodesQueue = new LinkedList<BinaryTree<T>>();
        nodesQueue.offerLast( tree );
        for (int r = 1; r < h; r++) {
            printBranches( branchLen, nodeSpaceLen, startLen, nodesInThisLevel, nodesQueue, out );
            branchLen = branchLen/2 - 1;
            nodeSpaceLen = nodeSpaceLen/2 + 1;
            startLen = branchLen + (3-level) + indentSpace;
            printNodes(branchLen, nodeSpaceLen, startLen, nodesInThisLevel, nodesQueue, out);

            for (int i = 0; i < nodesInThisLevel; i++) {
                BinaryTree<T> currNode = nodesQueue.pollFirst();
                if (currNode!=null) {
                    nodesQueue.offerLast( currNode.getLeft() );
                    nodesQueue.offerLast( currNode.getRight() );
                } else {
                    nodesQueue.offerLast( null );
                    nodesQueue.offerLast( null );
                }
            }
            nodesInThisLevel *= 2;
        }
        printBranches(branchLen, nodeSpaceLen, startLen, nodesInThisLevel, nodesQueue, out);
        printLeaves(indentSpace, level, nodesInThisLevel, nodesQueue, out);
    }

    private static <T>void printBranches(int branchLen, int nodeSpaceLen, int startLen, int nodesInThisLevel, Deque<BinaryTree<T>> nodesQueue, PaddedWriter out) {
        Iterator<BinaryTree<T>> iterator = nodesQueue.iterator();
        for (int i = 0; i < nodesInThisLevel/2; i++) {
            if (i == 0) {
                out.setw(startLen-1);
            } else {
                out.setw(nodeSpaceLen-2);
            }
            out.write();
            BinaryTree<T> next = iterator.next();
            if (next != null) {
                out.write( "/" );
            } else {
                out.write(" ");
            }
            out.setw(2*branchLen+2);
            out.write();
            next = iterator.next();
            if (next != null) {
                out.write( "\\" );
            } else {
                out.write( " " );
            }
        }
        out.endl();
    }

    // Print the branches and node (eg, ___10___ )
    private static <T>void printNodes(int branchLen, int nodeSpaceLen, int startLen, int nodesInThisLevel, Deque<BinaryTree<T>> nodesQueue, PaddedWriter out) {
        Iterator<BinaryTree<T>> iterator = nodesQueue.iterator();
        BinaryTree<T> currentNode;
        for (int i = 0 ; i < nodesInThisLevel; i++) {
            currentNode = iterator.next();
            if (i == 0) {
                out.setw(startLen );
            } else {
                out.setw(nodeSpaceLen );
            }
            out.write();
            if (currentNode != null && currentNode.getLeft() != null) {
                out.setfill( '_' );
            } else {
                out.setfill( ' ' );
            }
            out.setw( branchLen+2 );
            if (currentNode != null) {
                out.write(currentNode.toString());
            } else {
                out.write();
            }
            if (currentNode != null && currentNode.getRight() != null) {
                out.setfill( '_' );
            } else {
                out.setfill( ' ' );
            }
            out.setw(branchLen);
            out.write();
            out.setfill(' ');
        }
        out.endl();
    }

    // Print the leaves only (just for the bottom row)
    private static <T>void printLeaves(int indentSpace, int level, int nodesInThisLevel, Deque<BinaryTree<T>> nodesQueue, PaddedWriter out) {
        Iterator<BinaryTree<T>> iterator = nodesQueue.iterator();
        BinaryTree<T> currentNode;
        for (int i = 0; i < nodesInThisLevel; i++) {
            currentNode = iterator.next();
            if (i == 0) {
                out.setw(indentSpace+2);
            } else {
                out.setw(2*level+2);
            }
            if (currentNode !=null) {
                out.write(currentNode.toString());
            } else {
                out.write();
            }
        }
        out.endl();
    }

}

可以使用此课程进行测试:

public class Tester {
    public static void main( String[] args ) {

        BinaryTree<Integer> root = new BinaryTree<Integer>(30);
        root.setLeft(new BinaryTree<Integer>(20));
        root.setRight(new BinaryTree<Integer>(40));
        root.getLeft().setLeft(new BinaryTree<Integer>(10));
        root.getLeft().setRight(new BinaryTree<Integer>(25));
        root.getRight().setLeft(new BinaryTree<Integer>(35));
        root.getRight().setRight(new BinaryTree<Integer>(50));
        root.getLeft().getLeft().setLeft(new BinaryTree<Integer>(5));
        root.getLeft().getLeft().setRight(new BinaryTree<Integer>(15));
        root.getLeft().getRight().setRight(new BinaryTree<Integer>(28));
        root.getRight().getRight().setLeft(new BinaryTree<Integer>(41));


        BinaryTree.printPretty( root, 1, 0, new PaddedWriter( System.out ) );
    }



}

如果使用此代码,您可能需要考虑的一点是,在计算间距时不考虑节点的宽度。因此,如果您添加了一个包含123456789的节点,它将无法正常打印。