简体   繁体   English

Java-如何比较泛型类型?

[英]Java-How do I compare generic types?

Here's the code for a generic binary search tree. 这是通用二进制搜索树的代码。 Now, it runs and compiles perfectly, but with one problem that I only noticed now, after I have finished this class. 现在,它可以完美运行并编译,但是在完成本课后,我才注意到一个问题。 The problem is that the insert method uses compareTo()(when it comes to comparing the nodes' elements) to decide where to place the next node in the tree according to its' value. 问题在于,insert方法使用compareTo()(在比较节点元素时)根据其值决定将下一个节点放置在树中的位置。 And for instance for an input of: 例如,输入:

1, 112, 2 1,112,2

instead of getting this tree: 而不是得到这棵树:

 1  
  \   
    2    
     \    
     112

What I end up getting is: 我最终得到的是:

       1
         \
          2
         / 
        112

Because probably the comparison is done in a lexicographically way and so it see 2 > 112. 因为比较可能是按字典顺序进行的,所以它看到2> 112。

Here's the code for the Tree class: 这是Tree类的代码:

import java.util.*;
import java.io.*;
import java.lang.*;

public class Tree<T extends Comparable<T>>
    { private Node<T> root = null;
    static String S="";

    public Tree()
        {File file=new File("date.in.txt");

            try 
            { Scanner input = new Scanner( file );
            while(input.hasNext())
                 insert((T)input.next());} 

            catch (FileNotFoundException ex) 
                { System.out.printf("ERROR: %s!\n", ex); } }


    public void show(){ printLevelOrder(maxDepth()); }

    public void printLevelOrder(int depth) 
        { for (int i = 1; i <= depth; i++) 
            { System.out.print("Level " + (i-1) + ": ");
            String levelNodes = printLevel(root, i);
            System.out.print(levelNodes + "\n"); } }

    public String printLevel(Node<T> t, int level) 
        { if (t == null) 
            return "";
        if (level == 1) 
            return t.element + " ";
         else if (level > 1) 
            { String leftStr = printLevel(t.left, level - 1);
            String rightStr = printLevel(t.right, level - 1);
            return leftStr + rightStr; }
        else 
          return ""; }


    int maxDepth(){ return maxDepth2(root); }

    int maxDepth2(Node<T> node) 
        { if (node == null) 
            return (0);
         else 
            { int leftDepth = maxDepth2(node.left);
            int rightDepth = maxDepth2(node.right);

            if (leftDepth > rightDepth )
                return (leftDepth + 1);
            else
                return (rightDepth + 1); } }


    public String toString(){ return this.InOrder(); }


    public String InOrder(){ inOrder2(root); return S; }

    public void inOrder2(Node<T> root) 
        { if(root !=  null)   
            { inOrder2(root.left);    
            S=S+root.element+" ";  
            inOrder2(root.right); } }


    public boolean insert(T element)  // I N S E R T    M E T H O D
        { if (isEmpty()) 
            { root = new Node<T>(element);
            return true; }

         Node<T> current = root; 
         Node<T> parent;         

         do 
            { parent = current;

             if (element.compareTo(current.element)<0) 
                 current = current.left; 
              else if (element.compareTo(current.element)>0) 
                 current = current.right; 
              else 
                 return false; } 
             while (current != null);

         Node<T> node = new Node<T>(element);


             if ( element.compareTo(parent.element)>0  ) 
                 parent.right = node;
          else 
             parent.left = node;

         return true; } 


    public boolean isEmpty() { return root == null; }


    private static class Node<T extends Comparable<T>>   
        { Node<T> left  = null;
        Node<T> right = null;
        final T element;

        Node(T element) { this.element = element; } } }

And here's the main: 这是主要的:

import java.util.*;
import java.io.*;

public class Main 
    {public static void main(String[]args)
        {Tree <Double> T=new Tree<>(); } }

Now I did a little bit of research and asked here and there, and I got wind of something called comparator but I haven't quite used one before and I'm not sure how to implement it. 现在,我做了一些研究,并在这里和那里问了一些,我有点喜欢比较器,但是我以前还没有用过,所以我不确定如何实现它。 Now if you got any solution to how to fix this, or what to add/do, I'm all eyes and ears homies. 现在,如果您对如何解决此问题或添加/执行操作有任何解决方案,那么我就是耳目一新。

Your line insert((T)input.next()); 您的行insert((T)input.next()); doesn't make sense - input.next() is a String , but you're casting it to a T even though T isn't associated with a real type at this point. 没道理input.next()String ,但是您现在将其强制转换为T即使此时T与实际类型都不相关。 When constructing a Tree a caller could, for instance, say new Tree<Integer> making that line, in essence, insert((Integer)input.next()); 例如,在构造Tree ,调用者可以说new Tree<Integer>进行该行,本质上是insert((Integer)input.next()); , which is broken. ,它已损坏。

If your goal is for Tree to always contain String s, just remove the generic T type from Tree and just use String . 如果您的目标是让Tree始终包含String ,则只需从Tree删除通用T类型,然后使用String If you actually want to support arbitrary types you need to move the file-reading behavior out of the Tree constructor (eg into a static method that returns a Tree<String> ). 如果您实际上想支持任意类型,则需要将文件读取行为移出Tree构造函数(例如,移到返回Tree<String>的静态方法中)。

For example: 例如:

public static Tree<String> readFromFile(Path file) throws FileNotFoundException {
  try (Scanner input = new Scanner(file)) {
    Tree<String> tree = new Tree<>();
    while(input.hasNext()) {
      tree.insert(input.next());
    }
    return tree;
  }
}

Notice that I used Path instead of File , the try-with-resources pattern, and I don't suppress the exception, instead the caller (likely the main method) should handle the exception properly (likely by reporting the file doesn't exist and exiting). 请注意,我使用Path而不是File ,使用try-with-resources模式,并且我不抑制异常,而是调用方(可能是main方法)应正确处理异常(可能是通过报告文件不存在)然后退出)。 Alternatively adding a catch block like so: 或者像这样添加一个catch块:

catch (IOException e) {
  throw new RuntimeException("Could not open " + file, e);
}

would avoid forcing callers to handle the exception. 避免强迫调用者处理该异常。


Now that we've cleaned up the Tree type, your ordering question is likely simpler to answer. 现在我们已经清理了Tree类型,您的订购问题可能更容易回答。 If you intend to order the elements as integers, convert the inputs to Integers, eg 如果打算将元素排序为整数,则将输入转换为Integers,例如

public static Tree<Integer> readIntsFromFile(Path file) throws FileNotFoundException {
  ...
  tree.insert(Integer.valueOf(input.next()));
  ...
}

This will order the tree based on the integer ordering, rather than the strings' lexicographic ordering. 这将根据整数顺序而不是字符串的字典顺序对树进行排序。 This is what I'd suggest you do. 这就是我建议你做的。 It's straightforward and does what you want. 它很简单,可以做您想要的。


If you really want a Tree<String> but you want to order them as if they were integers you need a custom Comparator , as you mention. 如果您确实想要Tree<String>但想要整数一样对它们进行排序,则需要一个自定义的Comparator ,如上所述。 You would then need to pass the Comparator into the Tree 's constructor, and call comparator.compare(element, current.element) where you currently call element.compareTo(current.element) . 然后,您需要将Comparator传递到Tree的构造函数中,并在当前调用element.compareTo(current.element)地方调用element.compareTo(current.element) comparator.compare(element, current.element) element.compareTo(current.element)

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

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