【发布时间】:2017-04-16 16:00:22
【问题描述】:
我正在尝试在二叉搜索树类中实现一个名为 sigma() 的方法。此方法的工作是返回 BST 中差分键的总和。我给出的定义如下:
定义 1. 二叉树中节点的差分键 elements are integers 是节点中的元素,如果节点是 root or 是节点中的元素与其 父母。零节点的差分为 0。参见图 1 差分二叉树的插图。的总和 T 的差分密钥为 9,∑i=1n Δ(i),其中 Δ(i) 表示 节点i和n的差分键,树的大小。
该方法应返回树 sigma(T) 值的总和。所以在这种情况下,sigma(T) 将返回 10-4-2+3+5-3 = 9。我理解所有这些背后的概念,并且可以在纸上轻松地做到这一点,但是将它实现到我的代码中是我的我遇到了麻烦。我需要编写一个包装方法和一个递归的辅助方法来定义sigma()。
这是我目前编写的 BSTree 类(sigma() 位于底部):
package bstreedemo;
import java.util.function.Function;
/**
* A binary search tree <br>
* Requires JDK 1.8 for Function
* @param <E> the tree data type
* @since 12/09/2016
* @see BSTreeAPI
*/
public class BSTree<E extends Comparable<E>> implements BSTreeAPI<E>
{
/**
* the root of this tree
*/
private Node root;
/**
* the number of nodes in this tree
*/
private int size;
/**
* A node of a tree stores a data item and references
* to the child nodes to the left and to the right.
*/
private class Node
{
/**
* the data in this node
*/
public E data;
/**
* A reference to the left subtree rooted at this node.
*/
public Node left;
/**
* A reference to the right subtree rooted at this node
*/
public Node right;
}
/**
* Constructs an empty tree
*/
public BSTree()
{
root = null;
size = 0;
}
@Override
public boolean isEmpty()
{
return size == 0;
}
@Override
public void insert(E item)
{
Node newNode = new Node();
newNode.data = item;
if (size == 0)
{
root = newNode;
size++;
}
else
{
Node tmp = root;
while (true)
{
int d = tmp.data.compareTo(item);
if (d == 0)
{ /* Key already exists. (update) */
tmp.data = item;
return;
}
else if (d>0)
{
if (tmp.left == null)
{ /* If the key is less than tmp */
tmp.left = newNode;
size++;
return;
}
else
{ /* continue searching for insertion pt. */
tmp = tmp.left;
}
}
else
{
if (tmp.right == null)
{/* If the key is greater than tmp */
tmp.right = newNode;
size++;
return;
}
else
{ /* continue searching for insertion point*/
tmp = tmp.right;
}
}
}
}
}
@Override
public boolean inTree(E item)
{
return search(item) != null;
}
@Override
public void remove(E item)
{
Node nodeptr = search(item);
if (nodeptr != null)
{
remove(nodeptr);
size--;
}
}
@Override
public void inorderTraverse(Function func)
{
inorderTraverse(root,func);
}
@Override
public E retrieve(E key) throws BSTreeException
{
if (size == 0)
throw new BSTreeException("Non-empty tree expected on retrieve().");
Node nodeptr = search(key);
if (nodeptr == null)
throw new BSTreeException("Existent key expected on retrieve().");
return nodeptr.data;
}
@Override
public int size()
{
return size;
}
/**
* A recursive auxiliary method for the inorderTraver method that
* @param node a reference to a Node object
* @param func a function that is applied to the data in each
* node as the tree is traversed in order.
*/
private void inorderTraverse(Node node, Function func)
{
if (node != null)
{
inorderTraverse(node.left,func);
func.apply(node.data);
inorderTraverse(node.right,func);
}
}
/**
* An auxiliary method that support the remove method
* @param node a reference to a Node object in this tree
*/
private void remove(Node node)
{
E theData;
Node parent, replacement;
parent = findParent(node);
if (node.left != null)
{
if (node.right != null)
{
replacement = node.right;
while (replacement.left != null)
replacement = replacement.left;
theData = replacement.data;
remove(replacement);
node.data = theData;
return;
}
else
replacement = node.left;
}
else
{
if (node.right != null)
replacement = node.right;
else
replacement = null;
}
if (parent==null)
root = replacement;
else if (parent.left == node)
parent.left = replacement;
else
parent.right = replacement;
}
/**
* An auxiliary method that supports the search method
* @param key a data key
* @return a reference to the Node object whose data has the specified key.
*/
private Node search(E key)
{
Node current = root;
while (current != null)
{
int d = current.data.compareTo(key);
if (d == 0)
return current;
else if (d > 0)
current = current.left;
else
current = current.right;
}
return null;
}
/**
* An auxiliary method that gives a Node reference to the parent node of
* the specified node
* @param node a reference to a Node object
* @return a reference to the parent node of the specified node
*/
private Node findParent(Node node)
{
Node tmp = root;
if (tmp == node)
return null;
while(true)
{
assert tmp.data.compareTo(node.data) != 0;
if (tmp.data.compareTo(node.data)>0)
{
/* this assert is not needed but just
in case there is a bug */
assert tmp.left != null;
if (tmp.left == node)
return tmp;
tmp = tmp.left;
}
else
{
assert tmp.right != null;
if (tmp.right == node)
return tmp;
tmp = tmp.right;
}
}
}
/********************* Method Begins Here **********************/
/**
* A wrapper method for a method that computes the
* sum of the differential keys of this binary search tree.
* @return the sum of the differential keys of this tree.
*/
@Override
public int sigma()
{
if (size == 0)
return 0;
if (root.data.getClass() != Integer.class)
throw new IllegalArgumentException("Keys must be integers");
return (Integer)root.data + sigma(root);
}
/**
* An auxiliary method that recursively computes the sum of
* differential keys in the subtrees of the tree rooted at
* the specified key.
* @param subtreeRoot the root of a subtree of this tree
* @return the sum of the differential keys of the left and
* right subtrees
*/
private int sigma(Node subtreeRoot)
{
if(subtreeRoot == null)
return 0;
if(subtreeRoot.left != null)
{
if(subtreeRoot.right != null)
{
return (Integer)subtreeRoot.data + sigma(subtreeRoot.left) + sigma(subtreeRoot.right);
}
else
return (Integer)subtreeRoot.data + sigma(subtreeRoot.left);
}
if(subtreeRoot.right != null)
return sigma(subtreeRoot.right) - (Integer)subtreeRoot.data;
return (Integer)subtreeRoot.data;
}
/********************* Method Ends Here **********************/
/**
* Determines whether this binary tree is perfect
* @return true if the binary tree is perfect, otherwise false
*/
@Override
public boolean isPerfect()
{
}
/**
* A wrapper method that computes the height of this tree
* @return the height of this tree
*/
@Override
public int height()
{
return height(root);
}
/**
* An auxiliary method that recursively computes
* the height of the subtree rooted at the specified node.
* @param node a root of a subtree
* @return the height of this tree
*/
private int height(Node node)
{
if(node == null)
return 0;
return 1 + Math.max(height(node.left), height(node.right));
}
/**
* Determines whether this binary tree is complete.
* @return true if this binary tree is complete, otherwise false
*/
@Override
public boolean isComplete()
{
}
/**
* An auxiliary method that recursively determines whether
* the index of the subtree rooted at the specified node is
* less than the size of this tree.
* @param node a root of a subtree
* @param index the index of this node
* @return
*/
private boolean isComplete(Node node, int index)
{
}
}
wrapper 方法返回根节点的数据,将其转换为 Integer,与在根节点上执行的辅助方法返回的值相加。
我认为需要考虑三种情况:
-
if(subtreeRoot == null) if(subtreeRoot.left != null && subtreeRoot.right != null) // Parent node has left and right child nodesif(subtreeRoot.left != null || subtreeRoot.right != null) // Parent node has only left or right child node
这是我卡住的地方,案例 2 和 3。我知道目标是从父节点的值中减去左和/或右孩子的值以找到差异的值该子树的键,然后向下递归左和/或右剩余子树执行相同的操作并将结果相加。但我不知道从这里去哪里。我们不允许在项目的方法中添加参数/参数,所以(Node subtreeRoot)是辅助方法唯一允许的参数,而包装器方法不带参数。创建一个 Function 来简化问题是否有用,我的逻辑是否有缺陷等?感谢您提供任何帮助或进一步的解释,因为此时我有点迷茫,而我的教授也无济于事。
【问题讨论】:
-
你以前写过递归代码吗?
-
我们几周前才在课堂上开始递归,我在这个概念上遇到了一些麻烦。 @PM77-1
-
这三种情况不用担心。您应该有一个案例:您所在的子树是否为空。以你的方式思考事情可能适用于二叉树,但想象一下,如果你正在处理一棵可以有任意数量的孩子的树。那就是疯狂。您想要的是使用当前子树及其父级的数据来调用每个递归调用。
标签: java recursion data-structures binary-tree binary-search-tree