找到k - 最小元素(Java代码)

时间:2014-07-09 16:06:39

标签: java arrays

我想解决以下问题:给定n个元素的未排序数组,找到前k个最小元素。为此,我想构建一个大小为k的最大堆(来自数组的最后k个元素),然后扫描数组中的其余元素。如果我找到比我的根元素更小的元素,我交换两个元素然后我堆积我的堆。此解决方案应该在O(nlogk)时间和地点有效。但是我无法解决它(我有索引超出绑定的异常)。我试着调试它,但我不知道我的错误在哪里。这是我的代码:

public class KSmallest {
    private static int[] a;
    private static int n;

    public static void buildheap(int []a){
        n=a.length-1;
        for(int i=n;i>=0;i--){
            maxheap(a,i);
        }
        for (int i = n-1; i >= 0; i--) {
            if(a[i]<a[start]){
                exchange(i, 0);
                maxheap(a, 0);
            }
        }
    }

    public static void exchange(int i, int j){
        int t=a[i];
        a[i]=a[j];
        a[j]=t;
    }

    public static void sort(int []a0){
        a=a0;
        for(int i=n; i>0; i--){
            exchange(0, i);
            n=n-1;
            maxheap(a, 0);
        }
    }

    public static void main(String[] args) {
        int []a1={4,1,3,2,7, 2, 1, 4};
        int start = a1.length-k;
        for(int i=start;i<a1.length;i++){
            System.out.print(a1[i] + " ");
        }
        System.out.println();
        //sort(a1);
        for(int i=start;i<a1.length;i++){
            System.out.print(a1[i] + " ");
        }
    }
}

我正在为此奋斗两天,所以我希望有人可以提供帮助。

3 个答案:

答案 0 :(得分:1)

我知道这是一个学习练习,所以请随意忽略这个答案。但如果有人在现实世界中需要这样做,你就可以使用这个n * log(n)解决方案。

public static Collection<Integer> findKSmallest(Collection<Integer> data, int k) {
    assert k > 0;
    assert k <= data.size();
    ArrayList<Integer> dataAsList = new ArrayList<Integer>(data);
    Collections.sort(dataAsList);
    return dataAsList.subList(0, k);
}

答案 1 :(得分:1)

首先要注意的是变量名称不是很有意义......'a','a0','i','j','k','n','t'以及作为可变的静态变量,它总是一个噩梦。

无论如何我运行了代码并在exchange()方法中得到了NullPointerException。

正在发生的事情是buildheap()方法有一个名为'a'的参数,它与用于类变量的名称相同,所以当它将'a'传递给maxheap()然后传递给while()时,它传递的是类变量而不是参数。

尝试将此行添加为buildheap()方法的第一行:

KSmallest.a = a;

修改 我不确定这是否真的有效,但它会阻止NPE。

对所有变量使用有意义的名称,就像你用'左',右'''最大'等一样,会有很大的帮助,一些额外的字符不会浪费树木!

同时尽量避免使用可变的静态变量。通过使用'final'关键字将它们保持为常量,并且 - 按惯例 - 使它们全部大写。或者使用实例变量来删除静态关键字,这就是更多的OOP范例。

无论如何祝你好运! :)

答案 2 :(得分:1)

编写堆数据结构是一种很好的做法。我正在使用优先级队列,这在Java中很容易获得最小堆。对于这个问题,我需要一个最大堆,所以我使用比较器来创建一个最大堆。

public class KLowestElements {

/*comparator to create max heap*/
static class MaxHeapComparator implements Comparator<Integer> {
    @Override
    public int compare(Integer a, Integer b) {
        return b.compareTo(a);
    }
}

public static void main(String[] args) {
    //sample input
    int[] input = { 11, 2, 23, 34, 5};

    // heap size
    int k = 3;
    MaxHeapComparator maxHeapComparator = new MaxHeapComparator();
    PriorityQueue<Integer> maxHeap = new PriorityQueue<>(k,
            maxHeapComparator);

     //Loop Invariant: If heap size is k, compare top element with next 
     //element in the array. If element is smaller than the top element, 
     //remove the top integer and insert element from array. 
     for (int i = 0; i < input.length; i++) {
        if (maxHeap.size() < k) {
            maxHeap.add(input[i]);
        } else if (maxHeap.peek() > input[i]) {
            maxHeap.remove();
            maxHeap.add(input[i]);
        }
    }

    //print values 
    for (int i : maxHeap) {
        System.out.print(i + " ");
    }
}
}