简体   繁体   English

在二叉搜索树中找到第n个节点

[英]Finding nth node in binary search tree

Hi all I am working on a class project using binary search trees. 大家好,我正在使用二进制搜索树进行类项目。 I am having trouble trying to find the nth node of the binary search tree. 我在查找二进制搜索树的第n个节点时遇到麻烦。 I understand the concept of using in order traversal and using a counter but I am having trouble putting it into code. 我了解使用顺序遍历和使用计数器的概念,但是我很难将其放入代码中。 If anyone could help it would be greatly appreciated. 如果有人可以帮助,将不胜感激。 Sorry for the long code. 很抱歉输入长代码。 The method in question is the nthElement(int n, BinaryNode<AnyType> t) method. 有问题的方法是nthElement(int n, BinaryNode<AnyType> t)方法。 I am not sure how to increment the counter. 我不确定如何增加计数器。

package proj2;

// BinarySearchTree class
//
// CONSTRUCTION: with no initializer
//
// ******************PUBLIC OPERATIONS*********************
// void insert( x )       --> Insert x
// void remove( x )       --> Remove x
// boolean contains( x )  --> Return true if x is present
// Comparable findMin( )  --> Return smallest item
// Comparable findMax( )  --> Return largest item
// boolean isEmpty( )     --> Return true if empty; else false
// void makeEmpty( )      --> Remove all items
// void printTree( )      --> Print tree in sorted order
// ******************ERRORS********************************
// Throws UnderflowException as appropriate

/**
 * Implements an unbalanced binary search tree.
 * Note that all "matching" is based on the compareTo method.
 * @author Mark Allen Weiss
 */
public class BinarySearchTree<AnyType extends Comparable<? super AnyType>>
{
/** The tree root. */
private BinaryNode<AnyType> root;

/** The tree size. */
private int treeSize;

/**
 * Construct the tree.
 */
public BinarySearchTree( )
{
    root = null;
}

/**
 * Insert into the tree; duplicates are ignored.
 * @param x the item to insert.
 */
public void insert( AnyType x )
{
    root = insert( x, root );
}

/**
 * Remove from the tree. Nothing is done if x is not found.
 * @param x the item to remove.
 */
public void remove( AnyType x )
{
    root = remove( x, root );
}

/**
 * Find the smallest item in the tree.
 * @return smallest item or null if empty.
 */
public AnyType findMin( )
{
    if( isEmpty( ) )
        throw new UnderflowException( );
    return findMin( root ).element;
}

/**
 * Find the largest item in the tree.
 * @return the largest item of null if empty.
 */
public AnyType findMax( )
{
    if( isEmpty( ) )
        throw new UnderflowException( );
    return findMax( root ).element;
}

/**
 * Find an item in the tree.
 * @param x the item to search for.
 * @return true if not found.
 */
public boolean contains( AnyType x )
{
    return contains( x, root );
}

/**
 * Count the number of nodes in the tree.
 * @return the tree size.
 */
public int treeSize(){

    treeSize = treeSize(root);
    return treeSize;

}

/**
 * Make the tree logically empty.
 */
public void makeEmpty( )
{
    root = null;
}

/**
 * Test if the tree is logically empty.
 * @return true if empty, false otherwise.
 */
public boolean isEmpty( )
{
    return root == null;
}

/**
 * Print the tree contents in sorted order.
 */
public void printTree( )
{
    if( isEmpty( ) )
        System.out.println( "Empty tree" );
    else
        printTree( root );
}

public BinaryNode<AnyType> nthElement(int n){

    return nthElement(n, root);

}

/**
 * Internal method to insert into a subtree.
 * @param x the item to insert.
 * @param t the node that roots the subtree.
 * @return the new root of the subtree.
 */
private BinaryNode<AnyType> insert( AnyType x, BinaryNode<AnyType> t )
{
    if( t == null )
        return new BinaryNode<AnyType>( x, null, null );

    int compareResult = x.compareTo( t.element );

    if( compareResult < 0 )
        t.left = insert( x, t.left );
    else if( compareResult > 0 )
        t.right = insert( x, t.right );
    else
        ;  // Duplicate; do nothing
    return t;
}

/**
 * Internal method to remove from a subtree.
 * @param x the item to remove.
 * @param t the node that roots the subtree.
 * @return the new root of the subtree.
 */
private BinaryNode<AnyType> remove( AnyType x, BinaryNode<AnyType> t )
{
    if( t == null )
        return t;   // Item not found; do nothing

    int compareResult = x.compareTo( t.element );

    if( compareResult < 0 )
        t.left = remove( x, t.left );
    else if( compareResult > 0 )
        t.right = remove( x, t.right );
    else if( t.left != null && t.right != null ) // Two children
    {
        t.element = findMin( t.right ).element;
        t.right = remove( t.element, t.right );
    }
    else
        t = ( t.left != null ) ? t.left : t.right;
    return t;
}

/**
 * Internal method to find the smallest item in a subtree.
 * @param t the node that roots the subtree.
 * @return node containing the smallest item.
 */
private BinaryNode<AnyType> findMin( BinaryNode<AnyType> t )
{
    if( t == null )
        return null;
    else if( t.left == null )
        return t;
    return findMin( t.left );
}

/**
 * Internal method to find the largest item in a subtree.
 * @param t the node that roots the subtree.
 * @return node containing the largest item.
 */
private BinaryNode<AnyType> findMax( BinaryNode<AnyType> t )
{
    if( t != null )
        while( t.right != null )
            t = t.right;

    return t;
}

/**
 * Internal method to find an item in a subtree.
 * @param x is item to search for.
 * @param t the node that roots the subtree.
 * @return node containing the matched item.
 */
private boolean contains( AnyType x, BinaryNode<AnyType> t )
{
    if( t == null )
        return false;

    int compareResult = x.compareTo( t.element );

    if( compareResult < 0 )
        return contains( x, t.left );
    else if( compareResult > 0 )
        return contains( x, t.right );
    else
        return true;    // Match
}

/**
 * Internal method to print a subtree in sorted order.
 * @param t the node that roots the subtree.
 */
private void printTree( BinaryNode<AnyType> t )
{
    if( t != null )
    {
        printTree( t.left );
        System.out.println( t.element );
        printTree( t.right ); 
    }
}

/**
 * Internal method for traversing the tree in-order.
 * @param t the node that roots the subtree.
 * @return 
 */
  private void nthElement(int n, BinaryNode<AnyType> t){

    int i = t.treeSize;
    if(t.left.treeSize == n){
        System.out.println(t.element);
    }else if(t.left.treeSize > n){
        nthElement(n, t.left);
    }else if(t.left.treeSize < n){
        int k = i - t.left.treeSize;
        nthElement(k, t.right);
    }
}

/** 
 * Internal method for finding tree size.
 * @param t the node that roots the subtree.
 * @return the number of nodes.
 */
private int treeSize(BinaryNode<AnyType> t){

    int size = 1;                                      
    if(t.right != null){
        size = size + treeSize(t.right);        
    }
    if(t.left != null){
        size = size + treeSize(t.left);          
    }
    return t.treeSize = size;
} 

/**
 * Internal method to compute height of a subtree.
 * @param t the node that roots the subtree.
 */
private int height( BinaryNode<AnyType> t )
{
    if( t == null )
        return -1;
    else
        return 1 + Math.max( height( t.left ), height( t.right ) );    
}

// Basic node stored in unbalanced binary search trees
private static class BinaryNode<AnyType>
{
        // Constructors
    BinaryNode( AnyType theElement )
    {
        this( theElement, null, null );
    }

    BinaryNode( AnyType theElement, BinaryNode<AnyType> lt, BinaryNode<AnyType> rt )
    {
        element  = theElement;
        left     = lt;
        right    = rt;
    }

    AnyType element;            // The data in the node
    BinaryNode<AnyType> left;   // Left child
    BinaryNode<AnyType> right;  // Right child
}

    // Test program
public static void main( String [ ] args )
{
    BinarySearchTree<Integer> t = new BinarySearchTree<Integer>( );
    final int NUMS = 10;
    final int GAP  = 1;

    System.out.println( "Checking... (no more output means success)" );

    t.insert(55);
    t.insert(40);
    t.insert(35);
    t.insert(60);
    t.insert(70);
    t.insert(80);

    System.out.println("this is tree size: " + t.treeSize());
    int n = t.root.left.treeSize;
    System.out.println(n);
    t.nthElement(3);

}
}

EDIT: I have modified the nthElement(int n, BinaryNode<AnyType> t) and treeSize(BinaryNode<AnyType t> methods. The problem now is that I get a NullPointerException for anything any number I put in other than 2 and 3. 编辑:我已经修改了nthElement(int n, BinaryNode<AnyType> t)treeSize(BinaryNode<AnyType t>方法。现在的问题是,我输入2和3以外的任何数字都会得到NullPointerException

Problem is you need both a count and node to be returned from the recursive function--or multiple functions. 问题是您需要从递归函数(或多个函数)中返回计数和节点。 I'll do it in a way that would get you in trouble if you turned it in :) 如果您上交,我会以一种麻烦的方式来解决:)

Object nthElement(int n, BinaryNode t)
{
    // We are on the correct node, return it.
    if(n == 1) // I'll make this 1 based, so passing in 1 returns the first element. 
         return t;

    // Check the left side of the tree.
    if(t.left != null) {
        Object o=nthElement(n-1, t.left);
        // we found the correct node.
        if(o instanceof BinaryNode)
            return o;
        // we didn't find it but let's count the ones we found. (This is the "Trick")
        n=(Integer)o;
    }
    // We have no more children, let's just return our current count.
    if(t.right == null)
        return n;

    // Recurse right
    return(nthElement(n-1, t.right);
}

This is untested hand-coded and I often make huge logical errors on quick untested code, but the concept is sound. 这是未经测试的手工编码,我经常在未经测试的快速代码上犯下巨大的逻辑错误,但是这个概念很合理。 Any teacher worth his salt will probably fail this answer since the return value has two completely different unrelated types and I'm modifying a parameter, but I want to leave you with some of the fun! 任何值得一试的老师都可能会失败,因为返回值具有两种完全不同的不相关类型,并且我正在修改参数,但是我想给您一些乐趣!

The usage would have to check the return value, if it's an instanceof BinaryNode, great if not the tree didn't have enough nodes. 用法必须检查返回值(如果它是BinaryNode的实例),如果不是树没有足够的节点,那就太好了。

Also just for fun, I think that -(int)nthElement(0, t) counts the number of nodes in the tree. 同样出于娱乐目的,我认为-(int)nthElement(0,t)会计算树中的节点数。

A "Real" recursive solution would return a new mutable object with a BinaryNode and a count. “真实”递归解决方案将返回一个具有BinaryNode和一个计数的新可变对象。 As it is passed around you would modify the count, subtracting 1 for each node visited, when you hit 0 you return the object and extract it's "BinaryNode" 当它传递时,您将修改计数,对访问的每个节点减去1,当您单击0时,将返回对象并提取其“ BinaryNode”

Your simplest (but least efficient) method would be something like: 您最简单(但效率最低)的方法如下所示:

// Ignoring the possibility that there may not be n elements in the tree.
int leftSize = treeSize(t.left);
// If the size of the left tree is greater than n then the nth element must be up the left branch.
if ( leftSize >= n ) {
  return nthElement(n-1, t.left);
} else {
  // Otherwise it must be up the right branch.
  return nthElement(n-leftSize, t.right);
}

However, it may be better to implement an Iterator and just step through it n times. 但是,最好实现一个Iterator并将其逐步执行n次。

This works okay for me. 这对我来说很好。 Traverse the tree in order while keeping a count. 在保持计数的同时按顺序遍历树。

    int c = 0;
    public void findNth(int n, IntTree t) {

    if(!IntTree.isEmpty(t)) {
        findNth(n, t.left);
        c++;
        if(c==n)
            System.out.println("The element on position "+n+" is " + IntTree.value(t));
        findNth(n, t.right);

    }

I was struck solving this problem for two days. 我为解决这个问题感到震惊了两天。 I was able to print the nth to last element. 我能够打印第n个元素到最后一个元素。 But had difficulties returning it. 但是很难归还。 Finally able to solve using the below code: 终于能够使用以下代码解决:

    public class BinarySearchTree {

    Node root;

    public Node findNth(int n){
        if(root == null)
            return null;

        NodeCounter myNode = new NodeCounter();

        findNth(root,n, myNode);
        return myNode.node;
    }


    private void findNth(Node head, int n, NodeCounter nodeObj){

        if(head == null)
            return;

        findNth(head.left, n ,nodeObj);
        nodeObj.counter = nodeObj.counter + 1;
        if(n == nodeObj.counter){
            nodeObj.node = head;
            return;
        }
        if(n > nodeObj.counter)
            findNth(head.right,n,nodeObj);

    }

}

private class NodeCounter{
        Node node;
        int counter = 0;
}
class Node{
    Node left;
    Node right;
    int data;

    public Node getLeft() {
        return left;
    }

    public Node getRight() {
        return right;
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM