繁体   English   中英

使用数组列表的排序算法

[英]Sorting algorithms with array lists

我目前正在研究使用数组列表的排序算法。 我在 GitHub 上看到一个项目,用一个大数组中的新(大)元素覆盖小数组中的第一个(最小)元素,然后对小数组进行排序。

这是提供的解决方案:

public int findLarger() throws IndexingError {
    int[] array = getArray();
    int k = getIndex();
    if (k <= 0 || k > array.length) {
        throw new IndexingError();
    }
    int[] smallArray = new int[k];
    for (int index = k; index < array.length; index++){
         if (array[index] > smallArray[0]){
             smallArray[0] = array[index];
             Arrays.sort(smallArray);
         }
    }
    return smallArray[0];
}

但是我很难理解我创建的这个方法是否通过使用另一个变量而不是另一个数组更“有效”?

public int findLarger() throws IndexingError {
    int[] array = getArray();
    int max = array[0];
    for (int i = 0; i < k; i++) {
        if (max < array[i]) {
            max = array[i];
        }
    } 
    return max;
}


public abstract class Search {
private int[] array; 
private int k; 

Search(int[] array, int k) {
    this.array = array;
    this.k = k;
}

public int[] getArray() {
    return array;
}
int getIndex() { return k; }

abstract public int findElement() throws IndexingError;
}

编辑:

if (array.length == 0 )
            throw new RuntimeException("Array can't be empty");

        int max = array[0];
        for (int i = 0; i < array.length; i++) {
            if (max < array[i]) {
                max = array[i];
            }
        } // end of obvious solution method
        return max;
    }

第一个实现真的很糟糕,为什么一个排序 (O n log n) 甚至最糟糕的几个array.length-k次,找到一个集合的最小值 (O(n)) 是很糟糕的。

所以是的,具有单个变量的版本,存储当前最小值是正确的方法。 (请注意,使用array[0]初始化最大值对空输入没有抵抗力)

另一方面,正如其他人评论的那样,这两种算法没有使用相同的单元格,因此目前无法比较。 如果在你的第二个实现中,你像第一个一样从k迭代到array.length ,你得到比第一个更好的实现。

这是一个很难回答的问题,原因有二:

  • 首先,方法#1 和方法#2 不做同样的事情,所以比较它们的效率没有意义。
  • 其次,方法#1 实际做什么有点难以准确确定,并且不清楚它实际做什么与它应该做什么相同。 也就是说,方法#1 不仅仅是对不同问题的解决方案; 我怀疑这是对不同问题的不正确解决方案

让我解释。 方法#2 非常简单:它从子array[0..k]找到最大元素。 方法 #1 显然不会这样做:它只从子array[k..n]读取数据。

它也显然没有从该子smallArray找到最大值,因为它将数据放入smallArray ,对其进行排序,然后从索引 0 中返回值; 最大值将在索引k - 1 但在指数值为0也不是最小的,因为数据只被投入smallArray如果它比已经存在更大

可以使用示例来研究方法 #1 的实际行为。 为方便起见,我更改了签名以将arrayk作为参数:

  • findLarger(new int[] { 1, 2, 3, 4, 5, 6, 7 }, 3)是 5:4, 5, 6, 7 中的第三大。

  • findLarger(new int[] { 1, 2, 3, 7, 6, 5, 4 }, 3)也是 5:7, 6, 5, 4 中的第三大。

  • findLarger(new int[] { 7, 6, 5, 4, 3, 2, 1 }, 3)是 2:4, 3, 2, 1 中的第三大。

  • findLarger(new int[] { 1, 2, 3, 7, 6, 5, 4 }, 1)是 7:2, 3, 7, 6, 5, 4 中的第一大。

对于这些示例,它始终返回子array[k..n]中的第k个最大元素。 但是,在其他情况下,它不会:

  • findLarger(new int[] { -1, -2, -3, -4, -5, -6 }, 2)是 0,不是 -3, -4, -5, -6 之一。
  • findLarger(new int[] { 1, 2, 3, 4, 5, 6, 7 }, 5)是 0,不是 6、7 之一。

因此,方法 #1 所做的完整说明是:它返回子array[k..n]k个最大的正元素,如果该子数组包含少于k正数,则返回 0 返回 0 的特殊情况,以及将k用于两个不相关的目的,表明该方法应该解决返回第k个最大元素的更直接的问题,但它写错了。

对此的进一步证据是,对算法的一个非常简单的更改使其无条件返回第k个最大元素:不是用零初始化smallArray ,而是从array复制前k元素并对其进行排序。

    // changed: copy first k elements from array, and sort
    int[] smallArray = Arrays.copyOfRange(array, 0, k);
    Arrays.sort(smallArray);

    for (int index = k; index < array.length; index++){
         if (array[index] > smallArray[0]){
             smallArray[0] = array[index];
             Arrays.sort(smallArray);
         }
    }
    return smallArray[0];

更多的证据是与另一个 Stack Overflow 问题中的代码的相似性,它旨在找到第k个最大的元素,并且执行copyOfRangesort而不仅仅是new int[k]


所以现在我们可以谈谈方法#1 的固定版本的替代方案的效率。

  • 方法#1 的时间复杂度是 O( nk log k )。

  • 通过在内部循环中更改Arrays.sort以在 O( k ) 时间内将第一个元素移动到其正确位置,可以将方法 #1 改进为 O( nk ); 这是有效的,因为只有第一个元素会乱序,所以完全排序是不必要的。

  • 找到第k个最大元素的显而易见的方法是对数组进行排序并返回索引n - k处的值。 这需要 O( n log n ) 时间; 方法#1 仅在k log k < log n时更好,即当kn相比较小时。

  • 你可以做得更好 - quickselect算法平均只需要 O( n ) 时间,这显然是这个问题的最佳选择。 然而,它具有为O(n²)的罕见的最坏情况复杂。

暂无
暂无

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

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