【问题标题】:Implement Heap with generics in Java在 Java 中使用泛型实现堆
【发布时间】:2021-08-12 22:55:43
【问题描述】:

我想实现一个基于数组的堆。然而,这个堆应该可以用一个数组来调用,要么只包含实现 Comparable 接口的元素,要么用一个额外的 Comparator (因此,如果没有给出 Comparator,则假定每个元素都可以相互比较)。然后我想检查它的有效性。它不起作用,因为无法调用扩展 Comparable 的 heapCondition。

public class Heap <T>{
Object[] tree;
Comparator<T> comparator;

public <T extends Comparable<T>> Heap(T[] tree){
    this.tree = tree;
}

public Heap(T[] tree, Comparator<T> comparator){
    this.tree = tree;
    this.comparator = comparator;
}

/**
 * defines the heapCondition default is set so the Heap is a minHeap (parent is smaller than their children)
 * @param parent parent node
 * @param child child node
 */
public <T extends Comparable<T>> boolean heapCondition(T parent, T child){
    return parent.compareTo(child) < 0;
}

public boolean heapCondition(T parent, T child){
    if(comparator == null){
        // go into the heap condition where to Comparable is assumed
        heapCondition(parent,child);
    }
    return comparator.compare(parent,child) < 0;
}


/**
 * @return boolean whether or not the current tree fulfills the Heap condition
 *
 */
private boolean valid(){
    for(int i = 0; 2*i+2 < tree.length; i++){
        // returns false if the condition is not met for one of the children
        return !(!heapCondition((T) tree[i], (T) tree[2*i+1]) || !heapCondition((T) tree[i],(T) tree[2*i+2]));
    }
    return true;
}
}

【问题讨论】:

    标签: java arrays generics heap comparable


    【解决方案1】:

    在您的实现中Heap &lt;T&gt;public &lt;T extends Comparable&lt;T&gt;&gt; boolean heapCondition 不是同一个Ts。通用方法从类定义中创建其他 Tshadows T。这就是为什么你的public boolean heapCondition 不能打电话给public &lt;T ...&gt; boolean heapCondition

    实际上,当Comparator == nullT 为其他任何类时,您不能要求TComparablejava.util.TreeMap 实现了类似的东西。当Comparator == null 时,它使用compareTo。但是这个逻辑是通过使用运行时强制转换并在对象不是Comparable 时抛出ClassCastException 来完成的。这是java.util.TreeMap的JavaDoc

         /**
         * Constructs a new, empty tree map, using the natural ordering of its
         * keys.  All keys inserted into the map must implement the {@link
         * Comparable} interface.  Furthermore, all such keys must be
         * <em>mutually comparable</em>: {@code k1.compareTo(k2)} must not throw
         * a {@code ClassCastException} for any keys {@code k1} and
         * {@code k2} in the map.  If the user attempts to put a key into the
         * map that violates this constraint (for example, the user attempts to
         * put a string key into a map whose keys are integers), the
         * {@code put(Object key, Object value)} call will throw a
         * {@code ClassCastException}.
         */
        public TreeMap() {
            comparator = null;
        }
    

    这里是getEntry 实现,它将元素转换为Comparable

        final Entry<K,V> getEntry(Object key) {
            // Offload comparator-based version for sake of performance
            if (comparator != null)
                return getEntryUsingComparator(key);
            if (key == null)
                throw new NullPointerException();
            @SuppressWarnings("unchecked")
            Comparable<? super K> k = (Comparable<? super K>) key;
        ...
    

    解决方案

    您需要删除除Heap &lt;T&gt; 定义之外的所有泛型。此外,当您的comparator == null 时,您不会返回结果,从而进行无限递归。在您的 valid 方法中,您总是在第一次迭代后返回。

    这是你的堆的样子。

    class Heap<T> {
        T[] tree;
        Comparator<? super T> comparator;
    
        public Heap(T[] tree) {
            this.tree = tree;
            this.comparator = null;
        }
    
        public Heap(T[] tree, Comparator<? super T> comparator) {
            this.tree = tree;
            this.comparator = comparator;
        }
    
        /**
         * defines the heapCondition default is set so the Heap is a minHeap (parent is smaller than their children)
         *
         * @param parent parent node
         * @param child  child node
         */
        public boolean heapConditionComparable(T parent, T child) {
            @SuppressWarnings("unchecked")
            Comparable<? super T> comparableParent = (Comparable<? super T>) parent;
            return comparableParent.compareTo(child) < 0;
        }
    
        public boolean heapCondition(T parent, T child) {
            if (comparator == null) {
                // go into the heap condition where to Comparable is assumed
                return heapConditionComparable(parent, child);
            }
            return comparator.compare(parent, child) < 0;
        }
    
    
        /**
         * @return boolean whether or not the current tree fulfills the Heap condition
         */
        boolean valid() {
            for (int i = 0; i < (tree.length - 2) / 2; ++i) {
                // returns false if the condition is not met for one of the children
                if (!(!heapCondition(tree[i], tree[2 * i + 1]) || !heapCondition(tree[i], tree[2 * i + 2]))) {
                    return false;
                }
            }
            return true;
        }
    }
    

    【讨论】:

      【解决方案2】:

      您可以查看处理类似问题的TreeMap,但我认为它的方法不是很优雅。我会使用静态工厂方法来更好地控制类型,并为自然排序分配一个默认比较器。这样您就不必担心要调用哪种比较方法:

      public static <T> Heap<T> create(T[] tree, Comparator<T> comparator) {
          return new Heap<>(tree, comparator);
      }
      
      public static <T extends Comparable<T>> Heap<T> create(T[] tree) {
          return new Heap<>(tree, Comparator.naturalOrder());
      }
      
      private Heap(T[] tree, Comparator<T> comparator) {
          this.tree = tree;
          this.comparator = comparator;
      }
      
      public boolean heapCondition(T parent, T child) {
          return comparator.compare(parent, child) < 0;
      }
      

      【讨论】:

        猜你喜欢
        • 2012-07-01
        • 2012-12-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多