二进制搜索树差分键的总和

时间:2016-12-01 21:08:00

标签: java recursion data-structures binary-tree binary-search-tree

我正在尝试将名为sigma()的方法实现到二叉搜索树类中。此方法的作用是返回BST中差分键的总和。我给出的定义如下:

  

定义1.二叉树中节点的差分密钥   如果节点是,则元素是整数是节点中的元素   root或是节点中元素与其之间的区别   家长。空节点的差异为0.有关,请参见图1   差异二叉树的例证。总和   T的差分键是9,Σ i = 1 n Δ(i),其中Δ(i)表示   节点i和n的差分密钥,树的大小。

enter image description here

该方法应返回树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,添加到在根节点上执行的辅助方法返回的值。

我认为有三种情况需要考虑:

  1. if(subtreeRoot == null)
  2. if(subtreeRoot.left != null && subtreeRoot.right != null) // Parent node has left and right child nodes

  3. if(subtreeRoot.left != null || subtreeRoot.right != null) // Parent node has only left or right child node

  4. 这就是我陷入困境的情况,例如2和3.我知道目标是从父节点的值中减去左子和/或右子的值以找到值(s )对于该子树的差分密钥,然后递归执行相同操作的左和/或右剩余子树并将结果相加。但我不知道从哪里开始。我们不允许为项目的方法添加参数/参数,因此(Node subtreeRoot)是辅助方法允许的唯一参数,而包装器方法不带参数。创建函数&lt;&gt;是否有用简化问题,是我的逻辑缺陷等?任何帮助或进一步的解释都是值得赞赏的,因为我此时有点失落,而我的教授没有任何帮助。

2 个答案:

答案 0 :(得分:1)

正如MrMcGreg已经指出的那样,你正在使主逻辑变得复杂。

  • 基本情况:如果传入的树为NULL,则返回0
  • 递归:返回总和
    • 节点值减去父节点值
    • sigma(左孩子)
    • sigma(右孩子)

由于节点没有与其父节点的链接,因此您的递归函数需要将父节点的值传递给例程。您将获得从此伪代码派生的代码:

int sigma_aux (node root, int parent_val) {
    if !node
        return 0
    else
        root_val = root->data
        return root_val - parent_val +
               sigma_aux(root->left , root_val) +
               sigma_aux(root->right, root_val)

那是 it ;只是一个基本案例和一个递归案例。用铅笔和纸跟踪它,直到你理解它为止 - 然后在代码的上下文中实现它。

OP写道:

  

...类似

return (Integer) subtreeRoot.data - (Integer) root.data + 
    sigma(subtreeRoot.left) + sigma(subtreeRoot.right);
     

?我不明白如何获取父节点的值。一世   认为父节点是传入的子树节点   辅助方法,它的子节点是subtreeRoot.left和   subtreeRoot.right

控制传递给辅助方法的内容;不要把你的第一个概念作为给定的。这是你感到困惑的地方。简化:顶级 sigma 的唯一真正目的是将树根的数据传递给 sigma_aux ,并执行最顶层的计算以返回到外部世界。

int sigma(node root){        root_val = root-&gt; data;

在此之后,它看起来就像 sigma_aux

答案 1 :(得分:1)

你必须是我班上的某个人......无论如何,你必须使用 findParent 方法,因为你没有通过 sigma中的父节点方法

 private int sigma(Node subtreeRoot) {
    int tot = 0;
    if (subtreeRoot == null) {
        return 0;
    }
    if (findParent(subtreeRoot) == null) {
        tot = sigma(subtreeRoot.left) + sigma(subtreeRoot.right);
    } else{
        tot = (Integer) subtreeRoot.data - (Integer) findParent(subtreeRoot).data
                + sigma(subtreeRoot.left) + sigma(subtreeRoot.right);
    }
    return tot;
}

使用 findParent 方法的if语句是因为该方法将返回null,因为subtreeRoot是树的根,因此它没有父级。然后,当您为左右孩子调用 sigma 方法时,他们将按照else语句进行操作。

我坚持 isPerfect 方法。如果我创建一个aux方法并使用递归,我可以做到,但我们不应该这样做......