【问题标题】:Heterogeneous Binary Search Tree异构二叉搜索树
【发布时间】:2021-10-30 01:14:42
【问题描述】:

我需要构建一个异构(不同类型的元素)BST,并且能够对元素进行排序,但我不知道如何解决这个问题。

我这里有二叉树代码。

This is the node class

public class Node<T> {
  T data;
  Node<T> left;
  Node<T> right;

  Node(T data) {
    this.data = data;
    left = null;
    right = null;
  }
}

这是树类。

public class Tree<T extends Comparable<T>> {
  private Node<T> root;
  StringBuilder result = new StringBuilder();

  public Tree() {
    root = null;
  }

  public Node<T> getRoot() {
    return root;
  }

  /**
   * Method that inserts nodes into the binary tree. If the tree is empty , a new root node is
   * initialized.
   *
   * @param root A node object.
   * @param dataBeingInserted The object to be inserted on the tree.
   * @return The root node object
   */
  private Node<T> insertNode(Node<T> root, T dataBeingInserted) {
    if (root == null) {
      root = new Node<>(dataBeingInserted);
      return root;
    }
   
    if (dataBeingInserted.compareTo(root.data) < 0) {
      root.left = insertNode(root.left, dataBeingInserted);
    } else if (dataBeingInserted.compareTo(root.data) > 0) {
      root.right = insertNode(root.right, dataBeingInserted);
    }
    return root;
  }

  public void insertNode(T dataBeingInserted) {
    root = insertNode(root, dataBeingInserted);
  }

  /**
   * Method that recursively searches for our element through the tree. If the value is present in
   * the root node , or there aren't any nodes in the tree , the method returns the root node. If
   * the value we're looking for is smaller than the root node's value , we search for our value in
   * the left subtree , otherwise we search for it in the right subtree.
   *
   * @param root A node object.
   * @param dataBeingSearched User's value.
   * @return Recursive call of the method.
   */
  private Node<T> searchTree(Node<T> root, T dataBeingSearched) {
    if (root == null || dataBeingSearched.compareTo(root.data) == 0) {
      return root;
    }
    if ((dataBeingSearched.compareTo(root.data) > 0)) {
      return searchTree(root.left, dataBeingSearched);
    }
    return searchTree(root.right, dataBeingSearched);
  }

  public Node searchTree(T dataBeingSearched) {
    return searchTree(root, dataBeingSearched);
  }

  /**
   * An implementation of the In-order traversal. First the left subtree is visited and printed
   * accordingly, then we visit and print the root and after that we visit and print the right
   * subtree.
   *
   * @param root The root node object.
   */
  private String inorderTraversal(Node root) {
    if (root == null) {
      return "";
    }
    inorderTraversal(root.left);
    result.append(root.data).append(" ");
    inorderTraversal(root.right);

    return result.toString();
  }

  public void inorderTraversal() {
    inorderTraversal(root);
  }

}

我的树现在的问题是,每当任何元素与 root 不同时,我都会收到 ClassCastException ,因为发生的情况是 root 定义了树的类型,我无法修复它。

附言 这是给我错误的sn-p(为方便起见,我将发布整个主要方法。)

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Scanner;

public class Main {
  private static final Logger LOGGER = LoggerFactory.getLogger(Main.class);
  private static final Scanner SCANNER = new Scanner(System.in);

  public static void main(String[] args) {
    Tree tree = new Tree<>();
    tree.insertNode(50);
    tree.insertNode("30");
    tree.insertNode('b');
    tree.insertNode(69.3);
    tree.inorderTraversal();
    LOGGER.info("{}", tree.result);
  }
}

例如,第一个插入是一个 Integer ,之后我尝试插入一个 String 并且在那里它给了我 ClassCastException ,说 String 与 Integer 无法比较。

【问题讨论】:

  • 你能添加一个产生上述ClassCastException的sn-p吗?
  • @Izruo 你去。 :)
  • public class Tree&lt;T extends Comparable&lt;T&gt;&gt; 没有为异构树定义类。它为每个 T 类型的树定义一个类。
  • @Stef 是的,所以我理解它的方式是泛型类型允许我构建任何类型的树,但是树中的多种类型仍然看不见,我想不出办法不幸的是,要实现这一点。 (我还是个编程初学者)
  • 现在你已经定义了类 Tree,我想你可以创建一个类 Tree 的对象; Object 是所有类都继承自的通用超类。您将能够在该树中存储任何类的对象;但不是原始类型,例如 int;但这没关系,因为原始类型可以包装到其相应的类中,例如 java.lang.Integer

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


【解决方案1】:

我认为,cmets 彻底阐述了比较任何两个对象是不可能的。但是,您仍然可以通过将比较与树逻辑解耦来实现这样的树。

相反,每个客户都会遇到与您现在面临的完全相同的问题,但有些客户可能有适合他们的特定解决方案。我们稍后会对此进行研究。

首先,Java 已经定义了一个Comparator 接口,它与Comparable 一起使用。

package java.util;

public interface Comparator<T> {
    int compare(T o1, T o2);
}

同时,让我们重新思考一下树形界面。基本上,要求规定它应该能够接受几乎任何对象,所以它必须有一个类似的方法

public void add(Object data);

此时,没有理由使用泛型,因为我们实际上无法做出任何限制。即使树中还有其他对象,它应该仍然能够接受任何对象。

因此,我们可以做类似的事情

public class Tree {

    private Comparator<Object> comparator;
    private Node root;

    public Tree(Comparator<Object> comparator) {
        this.comparator = Objects.requireNonNull(comparator);
    }

    public void add(Object data) {
        root = insertNode(root, data);
    }

    private void insertData(Node root, Object dataBeingInserted) {
        // see below
    }

}

Node 类没有重大变化,只是它不再是通用的。现在,在insertNode 方法中比较两个对象时,我们只需参考Comparator 实例,而不是自己进行比较。

if (comparator.compare(dataBeingInserted, root.data) < 0) {
    root.left = insertNode(root.left, dataBeingInserted);
} else if (comparator.compare(dataBeingInserted, root.data) > 0) {
    root.right = insertNode(root.right, dataBeingInserted);
}

客户端可以将此Tree 实现与Comparator 一起使用,他/她将其限制为她/他知道可能发生的类型。

public static void main(String[] args) {
    Tree t = new Tree((o1, o2) -> {
        if (o1 instanceof Number && o2 instanceof String) {
            // numbers before strings
            return -1;
        }
        if (o1 instanceof Integer && o2 instanceof Integer) {
            return ((Integer) o1).compareTo((Integer) o2);
        }
        if (o1 instanceof String && o2 instanceof String) {
            return ((String) o1).compareTo((String) o2);
        }
        throw new ClassCastException("incompatible types: " + o1.getClass().getCanonicalName()
                + ", " + o2.getClass().getCanonicalName());
    });
    t.add("Hello");
    t.add(Integer.valueOf(1337));
}

正如ClassCastException 所指出的,此解决方案仍然无法固有地处理任何可能的类型。但是,这个Tree 实现可以用于处理各种类型的异构组合(只要客户端定义了适当的Comparator)。

【讨论】:

  • 问题是我必须使用泛型并混合数据类型。不应该出现类型无法比较的情况。 cs.usfca.edu/~galles/visualization/BST.html 在这个网站上,我正在尝试做的事情。
  • @JebvamUst 该网站有一个文本输入字段,因此它只接受String 值。如果它识别出一个数字,它会在它前面加上零,以便它可以将它作为String 处理。 54.2 之类的值在输入字段中被简单地禁止,因此它不必处理解释数字以正确排序。总之,这是客户端限制树可以处理的类型集的完美示例。
  • 那么总的来说,我不可能在二叉树中对多种类型的数据进行排序?
  • @JebvamUst 我查看了该网站的source code 并且可以证实我的假设。输入字段的值通过专有函数Algorithm.prototype.normalizeNumber 放入,保证其结果为4个字符的字符串。
  • @JebvamUst 正如我在回答中所展示的那样,可能有多种类型。但是,正如您问题的 cmets 已经指出的那样,一次处理每种类型是不可能的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-08
  • 2021-02-07
  • 2016-11-06
  • 1970-01-01
  • 1970-01-01
  • 2010-10-26
相关资源
最近更新 更多