我一直在尝试为二叉搜索树编写一个递归字符串方法,该树返回带有预订路径信息的树的多行表示。
每个节点都应以一系列<节点开头。和>显示从根到该节点的路径的字符。我不确定如何使用每个连续调用一个字符扩展的字符串前缀参数。
该方法应该能够重现这个例子:
树:
15
/ \
12 18
/ / \
10 16 20
\ \
11 17
预期打印输出:
15
<12
<<10
<<>11
>18
><16
><>17
>>20
我是递归的新手,到目前为止我的实际打印输出在经过数小时的代码处理后还不够接近:
18
<17
<10
>15
<11
>12
16
20
这是我的树节点类正常工作:
/**
* A single binary tree node.
* <p>
* Each node has both a left or right child, which can be null.
*/
public class TreeNode<E> {
private E data;
private TreeNode<E> left;
private TreeNode<E> right;
/**
* Constructs a new node with the given data and references to the
* given left and right nodes.
*/
public TreeNode(E data, TreeNode<E> left, TreeNode<E> right) {
this.data = data;
this.left = left;
this.right = right;
}
/**
* Constructs a new node containing the given data.
* Its left and right references will be set to null.
*/
public TreeNode(E data) {
this(data, null, null);
}
/** Returns the item currently stored in this node. */
public E getData() {
return data;
}
/** Overwrites the item stored in this Node with the given data item. */
public void setData(E data) {
this.data = data;
}
/**
* Returns this Node's left child.
* If there is no left left, returns null.
*/
public TreeNode<E> getLeft() {
return left;
}
/** Causes this Node to point to the given left child Node. */
public void setLeft(TreeNode<E> left) {
this.left = left;
}
/**
* Returns this nodes right child.
* If there is no right child, returns null.
*/
public TreeNode<E> getRight() {
return right;
}
/** Causes this Node to point to the given right child Node. */
public void setRight(TreeNode<E> right) {
this.right = right;
}
}
这是我的二分查找树类,底部附近有toFullString()方法:
import java.util.*;
/**
* A binary search tree (BST) is a sorted ADT that uses a binary
* tree to keep all elements in sorted order. If the tree is
* balanced, performance is very good: O(n lg n) for most operations.
* If unbalanced, it performs more like a linked list: O(n).
*/
public class BinarySearchTree<E extends Comparable<E>> {
private TreeNode<E> root = null;
private int size = 0;
/** Creates an empty tree. */
public BinarySearchTree() {
}
public BinarySearchTree(Collection<E> col) {
List<E> list = new ArrayList<E>(col);
Collections.shuffle(list);
for (int i = 0; i < list.size() ; i++) {
add(list.get(i));
}
}
/** Adds the given item to this BST. */
public void add(E item) {
this.size++;
if (this.root == null) {
//tree is empty, so just add item
this.root = new TreeNode<E>(item);
}else {
//find where to insert, with pointer to parent node
TreeNode<E> parent = null;
TreeNode<E> curr = this.root;
boolean wentLeft = true;
while (curr != null) { //will execute at least once
parent = curr;
if (item.compareTo(curr.getData()) <= 0) {
curr = curr.getLeft();
wentLeft = true;
}else {
curr = curr.getRight();
wentLeft = false;
}
}
//now add new node on appropriate side of parent
curr = new TreeNode<E>(item);
if (wentLeft) {
parent.setLeft(curr);
}else {
parent.setRight(curr);
}
}
}
/** Returns the greatest (earliest right-most node) of the given tree. */
private E findMax(TreeNode<E> n) {
if (n == null) {
return null;
}else if (n.getRight() == null) {
//can't go right any more, so this is max value
return n.getData();
}else {
return findMax(n.getRight());
}
}
/**
* Returns item from tree that is equivalent (according to compareTo)
* to the given item. If item is not in tree, returns null.
*/
public E get(E item) {
return get(item, this.root);
}
/** Finds it in the subtree rooted at the given node. */
private E get(E item, TreeNode<E> node) {
if (node == null) {
return null;
}else if (item.compareTo(node.getData()) < 0) {
return get(item, node.getLeft());
}else if (item.compareTo(node.getData()) > 0) {
return get(item, node.getRight());
}else {
//found it!
return node.getData();
}
}
/**
* Removes the first equivalent item found in the tree.
* If item does not exist to be removed, throws IllegalArgumentException().
*/
public void remove(E item) {
this.root = remove(item, this.root);
}
private TreeNode<E> remove(E item, TreeNode<E> node) {
if (node == null) {
//didn't find item
throw new IllegalArgumentException(item + " not found in tree.");
}else if (item.compareTo(node.getData()) < 0) {
//go to left, saving resulting changes made to left tree
node.setLeft(remove(item, node.getLeft()));
return node;
}else if (item.compareTo(node.getData()) > 0) {
//go to right, saving any resulting changes
node.setRight(remove(item, node.getRight()));
return node;
}else {
//found node to be removed!
if (node.getLeft() == null && node.getRight() == null) {
//leaf node
return null;
}else if (node.getRight() == null) {
//has only a left child
return node.getLeft();
}else if (node.getLeft() == null) {
//has only a right child
return node.getRight();
}else {
//two children, so replace the contents of this node with max of left tree
E max = findMax(node.getLeft()); //get max value
node.setLeft(remove(max, node.getLeft())); //and remove its node from tree
node.setData(max);
return node;
}
}
}
/** Returns the number of elements currently in this BST. */
public int size() {
return this.size;
}
/**
* Returns a single-line representation of this BST's contents.
* Specifically, this is a comma-separated list of all elements in their
* natural Comparable ordering. The list is surrounded by [] characters.
*/
@Override
public String toString() {
return "[" + toString(this.root) + "]";
}
private String toString(TreeNode<E> n) {
//would have been simpler to use Iterator... but not implemented yet.
if (n == null) {
return "";
}else {
String str = "";
str += toString(n.getLeft());
if (!str.isEmpty()) {
str += ", ";
}
str += n.getData();
if (n.getRight() != null) {
str += ", ";
str += toString(n.getRight());
}
return str;
}
}
public String toFullString() {
StringBuilder sb = new StringBuilder();
toFullString(root, sb);
return sb.toString();
}
/**
* Preorder traversal of the tree that builds a string representation
* in the given StringBuilder.
* @param n root of subtree to be traversed
* @param sb StringBuilder in which to create a string representation
*/
private void toFullString(TreeNode<E> n, StringBuilder sb)
{
if (n == null)
{
return;
}
sb.append(n.getData().toString());
sb.append("\n");
if (n.getLeft() != null) {
sb.append("<");
} else if (n.getRight() != null) {
sb.append(">");
}
if (n.getLeft() != null || n.getRight() != null)
{
toFullString(n.getLeft(), sb);
toFullString(n.getRight(), sb);
}
}
/**
* Tests the BST.
*/
public static void main(String[] args) {
Collection collection = new ArrayList();
collection.add(15);
collection.add(12);
collection.add(18);
collection.add(10);
collection.add(16);
collection.add(20);
collection.add(11);
collection.add(17);
BinarySearchTree bst = new BinarySearchTree(collection);
//System.out.println(bst);
String temp = bst.toFullString();
System.out.println(temp);
}
}
非常感谢任何有关递归toFullString方法的帮助。
答案 0 :(得分:3)
在设计递归解决方案时,您需要考虑两个级别。
由于我们打印出树中的每个项目,因此每个递归调用内部都会有一个print语句。但是,每行中打印的字符串包含有关到达当前节点的先前步骤的信息。我们如何处理这些信息?它需要从先前的递归调用传递到下一个调用。
以下是一组可能的规则:
<
,然后递归操作左节点。>
,并递归操作右侧节点。我们将<
和>
添加到哪里?我们需要一个参数来传递从递归调用到调用的递归中发生的当前先前步骤。您不希望在遍历树时简单地打印出<
和>
,因为您需要记住当前的一组步骤,以便将前缀打印到每个节点。可能有第二个辅助方法采用与原始toFullString()
相同的参数,但是可以使用自定义的第三个参数来承载当前的一组先前步骤。
所以逻辑可能看起来像这样:
""
,因为root最初没有任何步骤可以访问它。toFullString()
,并将<
添加到当前前缀字符串中,该字符串将被传递。toFullString()
,并将>
添加到当前前缀字符串中,该字符串将被传递。