【问题标题】:How to use HashSet to find common elements in two Comparable arrays?如何使用 HashSet 查找两个 Comparable 数组中的共同元素?
【发布时间】:2016-02-18 21:29:45
【问题描述】:

EDIT:方法签名

    public Comparable[][] findCommonElements(Comparable[][] collections)

错了。应该是

    public Comparable[] findCommonElements(Comparable[][] collections)

但是在我的 IDE 中更改它会搞砸一切。我几乎觉得我已经超出了我的知识范围,因为我不完全理解 Sets,而 2D 数组把我弄得一团糟。

我需要编写一个算法,它采用两个 Comparable 数组,以 线性时间效率 遍历它们,并显示公共元素。 我读过使用 HashSet 会给我最快的时间效率,但我已经陷入僵局。原因如下:

我们得到了指令和一行代码,即方法签名

public Comparable[][] findCommonElements(Comparable[][] collections)

这意味着我必须返回二维数组“集合”。我通过电子邮件向我的教授发送了关于使用 HashSets 的信息,我得到了批准,但我遇到了这个问题:

"您可以在 findCommonElements 方法中使用 HashSets,但您需要能够计算执行的比较次数。虽然散列通常非常有效,但在发生冲突时会进行一些比较。要做到这一点,您将需要访问您使用的 HashSet 的源代码。您还需要 CommonElements 类中的“getComparisons()”方法来返回比较次数。

两个学期的编程,没学过HashSets、Maps、Tables等。我自己在努力学这个,还没有完全理解碰撞。

我的代码确实采用了两个数组并返回了公共元素,但是我的 return 语句很麻烦,因为我基本上是写了它所以它可以编译(二维 Comparable 数组是参数)。

我是否走在正确的道路上?这是代码:

public class CommonElements {

    static Comparable[] collection1 = {"A", "B", "C", "D", "E"}; //first array
    static Comparable[] collection2 = {"A", "B", "C", "D", "E", "F", "G"}; //second array
    static Comparable[][] collections = {collection1, collection2}; //array to store common elements. 
    static Set<Comparable> commonStuff = new HashSet<>(); //instance of Set containing common elements

    public static void main(String[] args) {

        CommonElements commonElements = new CommonElements(); //create instance of class CommonElements
        commonElements.findCommonElements(collections); //call the find method

    }
    public Comparable[][] findCommonElements(Comparable[][] collections) {

        Set<Comparable> addSet = new HashSet<>(); //instance of Set to add elements to

        for (Comparable x : collection1) { //adding elements from first array to my addSet
            addSet.add(x);
        }
        for (Comparable x : collection2) {
            if (addSet.contains(x)) {
            commonStuff.add(x); //checking for common elements, add to commonStuff Set
            }
        }
        System.out.println(toString(commonStuff)); //print the toString method

        return collections; //return statement, otherwise Java will whine at me
    }
    public String toString(Set<Comparable> commonStuff) { //this method gets rid of the brackets
        String elements = commonStuff.toString(); //make a String and assign it to the Set
        elements = elements.replaceAll("\\[", "").replaceAll("\\]", ""); //replace both brackets with empty space

        return "Common Elements: " + elements; //return the Set as a new String
    }
}

【问题讨论】:

  • 首先,Comparable通用,因此您使用的是 rawtype - 不要。其次,HashSet 比较 equals - TreeSet 比较使用 Comparable。使用其中之一。
  • 感谢您的建议,但是,在阅读 this 之后,它告诉我 HashSet 在时间复杂度上更快。 ??
  • 它们是,但它们只有在你有散列函数时才有效。您拥有Comparables 的事实让我怀疑它不仅仅是Object.hashCode() 实现。
  • 如果必须恰好接收两个Comparable[],为什么要将参数定义为Comparable[][]?改为定义两个Comparable[] 参数。另外,去掉所有的静态字段,将findCommonElements()设为静态。
  • 那么是时候满足要求了。

标签: java arrays hashset comparable


【解决方案1】:

HashSet.add(E e) 如果未能将e 添加到Set,则返回 false,因此我们可以说:

if (addSet.add(x)){
    //the collection did not contain x already
} else {
    //the collection contained x
}

所以你可以这样做:

public Comparable[] findCommonElements(){
    Set<Comparable> collectionSet1 = new HashSet<>(Arrays.asList(collection1));
    Set<Comparable> collectionSet2 = new HashSet<>(Arrays.asList(collection2));
    for (Comparable x : collectionSet1){
        if (!collectionSet2.add(x)){
            commonStuff.add(x);
        }
    }
    return commonStuff.toArray(); //convert HashSet to an array
}

请注意,您需要import java.util.Arrays;

【讨论】:

  • Set#retainAll() 怎么样?摆脱循环
  • @Eashi 我不确定我是否关注。
  • collectionSet1.retainAll(collectionSet2) 将collectionset1修改为只保存两个集合的共同元素,也称为两个集合的交集。
  • @Eashi 我现在看到了。我猜那会奏效。虽然如果它返回一个新的集合而不是修改自己会更好,所以你可以这样做commonStuff=collectionSet1.retainAll(collectionSet2);
  • 是的,我知道。如果你想要,你需要先制作一个副本,但在这种情况下,你已经制作了数组的副本。
【解决方案2】:

编辑我忘了提到我导入了 Apache Commons Array Utils。很有用。

我想通了。感谢你的帮助。我有一个调用类实例 3 次的 main 方法和 3 个测试方法,但这些都无关紧要。这就是给我带来麻烦的地方,现在它可以工作了。 :-)

public int getComparisons() {
        return comparisons;
    } //method to return number of comparisons
    public static Comparable[] findCommonElements(Comparable[][] collections) {
        /*
        I LEARNED THAT WE HAD TO USE MORE THAN TWO ARRAYS, SO IT WAS BACK
        TO THE DRAWING BOARD FOR ME. I FIGURED IT OUT, THOUGH.
        */
        Comparable[] arr1 = collections[0]; //set initial values to 1 Dimensional arrays so the test methods can read their respective values
        Comparable[] arr2 = collections[1];
        Comparable[] arr3 = collections[2];

        /*
        THE FOLLOWING BLOCK OF CODE TAKES ALL THE PERMUTATIONS OF THE 3 ARRAYS (i.e. 1,2,3; 1,3,2; 2,1,3, etc),
        DETERMINES WHICH ARRAY IS THE SHORTEST, AND ADDS THE LONGER TWO ARRAYS TO A QUERY ARRAY.
         */
        if(arr1.length < arr2.length && arr1.length < arr3.length || arr2.length <= arr3.length) { //shortest array will become hash array. the other two will become a combined query array.
            hashArray = arr1;  //these will be utilized below to put into Sets
            queryArray = ArrayUtils.addAll(arr2, arr3);
        }
        else if(arr2.length < arr1.length && arr2.length < arr3.length || arr1.length <= arr3.length) {
            hashArray = arr2;
            queryArray = ArrayUtils.addAll(arr1, arr3);
        }
        else if(arr3.length < arr1.length && arr3.length < arr2.length || arr1.length <= arr2.length) {
            hashArray = arr3;
            queryArray = ArrayUtils.addAll(arr1, arr2);
        }
        HashSet<Comparable> intersectionSet = new HashSet<>(); //initialize Sets
        HashSet<Comparable> arrayToHash = new HashSet<>();
        for(Comparable element : hashArray) { //add shorter array to hashedArray Set
            arrayToHash.add(element);
        }
        //NOTE FROM THE JAVADOC ON THE IMPLEMENTATION OF .contains() USING HASHSET COMPARISONS
        /**
         * <p>This class offers constant time performance for the basic operations
         * (<tt>add</tt>, <tt>remove</tt>, <tt>contains</tt> and <tt>size</tt>),
         * assuming the hash function disperses the elements properly among the
         * buckets.
         */
        for(Comparable element : queryArray) {
            if(element != null) {
                comparisons++; // increment comparisons with each search
            }
            if(arrayToHash.contains(element)) { //search for matches and add to intersectionSet (.contains uses the equals method to determine if an object is within array)
                intersectionSet.add(element);
            }
        }
        return intersectionSet.toArray(new Comparable[0]); //return Set as Array defined in method signature
    }

【讨论】:

    猜你喜欢
    • 2020-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-10
    • 2021-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多