【问题标题】:java sorting with comparator and swap function带有比较器和交换功能的java排序
【发布时间】:2011-02-13 11:02:13
【问题描述】:

我需要使用自定义比较器和交换功能来排序功能。我可以自己写一个,但我想知道其他人是否还没有这样做。 Java 运行时包含许多专门的排序函数,用于对原始类型、对象等的数组进行排序,但它们都没有将交换函数作为参数。谷歌搜索也没有找到任何有用的东西。

public interface IntComparator
{
    int compare(int a, int b);
}
public interface IntSwap
{
    void swap(int a, int b);
}
public static void sort(IntComparator compFn, IntSwap swapFn, int off, int len);

【问题讨论】:

  • 自定义交换函数除了交换元素还能做什么?
  • 一个自定义的swap函数可以用来统计需要swap的次数,这对你学习编程很有好处。不过,Java 标准库并不是为这些事情而设计的。
  • 我需要交换两个数组中的索引。我知道我可以对二维数组进行排序,但这会增加所需的内存。每个 java 对象都有相当大的开销(大约 40 个字节),我试图避免它。
  • 除非万不得已,否则不要担心内存使用情况。对于像这样的问题,有额外的内存开销来标记每个对象的初始位置应该没问题。但是,如果您要对如此庞大的数组进行排序,以至于它们几乎无法放入内存中,那么这是一个需要考虑的合理问题。
  • 减少使用的内存量是我想要做的事情的重点。我正在优化较大框架的一部分,该框架将数据从数据库加载到内存,对其进行排序并将其发送到 Jasper Reports。当前数据存储在行中,每行都有值数组。每行可能有几个子报表。子报表由行数组组成……等等。我想将所有数据存储到一个(或多个)大字节数组和几个整数数组中,这些数组包含行/子报表数据开始的数据的索引。这将减少大约 100 倍的内存,还可以减少 CPU 负载(数据可能适合 L2/L3 缓存)

标签: java sorting


【解决方案1】:

这就是我要找的。它基于用于对整数进行排序的 java 运行时算法。通过正确实现 Sortable 接口,它几乎可以对任何东西进行排序。

公共类排序{ 公共静态无效排序(Sortable sortable,int off,int len){ // 对最小数组进行插入排序 如果 (len off && sortable.compare(j - 1, j) > 0; j--) { sortable.swap(j, j - 1); } } 返回; } // Choose a partition element, v int m = off + (len >> 1); // Small arrays, middle element if (len > 7) { int l = off; int n = off + len - 1; if (len > 40) { // Big arrays, pseudomedian of 9 int s = len / 8; l = med3(sortable, l, l + s, l + 2 * s); m = med3(sortable, m - s, m, m + s); n = med3(sortable, n - 2 * s, n - s, n); } m = med3(sortable, l, m, n); // Mid-size, med of 3 } // Establish Invariant: v* (<v)* (>v)* v* int a = off, b = a, c = off + len - 1, d = c; while (true) { while (b <= c && sortable.compare(b, m) <= 0) { if (sortable.compare(b, m) == 0) { sortable.swap(a, b); m = a; a++; } b++; } while (c >= b && sortable.compare(c, m) >= 0) { if (sortable.compare(c, m) == 0) { sortable.swap(c, d); m = d; d--; } c--; } if (b > c) { break; } sortable.swap(b++, c--); } // Swap partition elements back to middle int s, n = off + len; s = Math.min(a - off, b - a); vecswap(sortable, off, b - s, s); s = Math.min(d - c, n - d - 1); vecswap(sortable, b, n - s, s); // Recursively sort non-partition-elements if ((s = b - a) > 1) { sort(sortable, off, s); } if ((s = d - c) > 1) { sort(sortable, n - s, s); } } private static int med3(Sortable sortable, int a, int b, int c) { return sortable.compare(a, b) < 0 ? (sortable.compare(b, c) < 0 ? b : sortable.compare(a, c) < 0 ? c : a) : sortable.compare(b, c) > 0 ? b : sortable.compare(a, c) > 0 ? c : a; } private static void vecswap(Sortable sortable, int a, int b, int n) { for (int i = 0; i < n; i++, a++, b++) { sortable.swap(a, b); } }

}

【讨论】:

    【解决方案2】:

    我需要交换两个数组中的索引。我知道我可以对二维数组进行排序,但这会增加所需的内存。

    没有。如果我理解正确,它不会导致任何开销。

    请记住,Java 不会将数组或对象直接存储在变量(或数组!)中。它存储引用。即使从数组中引用的每个元素都是 40 字节大,它也会作为引用存储在数组中。

    因此,我建议您使用内置的排序机制。他们不会对大量数据进行洗牌,只会对参考资料进行洗牌。

    【讨论】:

    • 1.我正在使用享元模式来减少使用的内存,我正在排序的对象是在需要时创建然后处理的。这就是为什么我不能使用对对象进行排序的函数。 2. java 排序函数,排序整数(和其他原始类型)不能使用比较器。我使用整数数组作为对包含数据的字节数组的引用。 3. 每个对象有两个引用。这就是为什么我需要交换功能,当交换两个项目时,我需要同时更新它们。
    • 在java中,二维数组由一维数组组成,每个数组都是一个对象。如果数组的最后一维很小,则会导致次要的内存开销。例如 int[2][1000] 需要 (1000*4+40)*2+40=8120 字节内存(开销仅为 1.5%), int[1000][2] 需要 (2*4+40)*1000 +40 =46040 字节内存(巨大开销 475%)。
    • 杰克是对的——开销可能很大。考虑使用两个大字节数组,例如每个 10^6 个元素。在内存中,这只有 10^6 * 16 位。然而,在 64 位机器上存储 10^6 个数组,每个数组只包含两个字节,每个元素需要一个指针(64 位)和一些数据(另外一个 64 位)!那是 128 * 10^6 位。开销是 8 倍,这对于大数据可能很重要。
    【解决方案3】:

    因为sort() 的Object 数组是稳定的,所以您可以在自定义Comparator 中获得有用的信息。这个在按String 长度排序时计算交换。

    import java.util.Arrays;
    import java.util.Comparator;
    
    /** @see http://stackoverflow.com/questions/4983746 */
    public class SortTest {
    
        private static class LengthComparator implements Comparator<String> {
    
            private int count;
    
            public int compare(String s1, String s2) {
                int a = s1.length();
                int b = s2.length();
                if (a < b) {
                    return -1;
                } else if (a > b) {
                    count++;
                    return 1;
                } else {
                    return 0;
                }
            }
        }
    
        public static void main(String[] args) throws Exception {
            String[] sa = {"One", "Two", "Three", "Four", "Five"};
            System.out.println(Arrays.toString(sa));
            LengthComparator byLength = new LengthComparator();
            Arrays.sort(sa, byLength);
            System.out.println(Arrays.toString(sa));
            System.out.println(byLength.count);
        }
    }
    

    控制台:

    [一二三四五] 【一二四五三】 2

    【讨论】:

      【解决方案4】:

      关于交换:Java 按值传递参数,因此方法 swap(int a, int b) 和 swap(Object a, Object b) 不能按预期工作。

      【讨论】:

      • 当然有。这是交换功能的简单实现。 class IntSwapImpl implements IntSwap { private final int[] ba; IntSwapImpl(int[] ba) { this.ba = ba; } @Override public void swap(int a, int b) { int v = ba[a]; ba[a] = ba[b]; ba[b] = v; } }
      • 好的,您将索引作为参数而不是实际值传递。我的误解。
      【解决方案5】:

      如果你提出这些接口,至少在他们应该做的事情上添加一些 cmets。从我得到的讨论中,你想要这样的东西:

      /**
       * A Sortable represents a indexed collection of comparable
       * elements.
       * It does not offer direct access to its elements, only
       * comparison and swapping by indices.
       *
       * In the method specifications we are using this[i] to
       * mean the 
       */
      public interface Sortable {
      
          /**
           * Compares two elements by their indices.
           * @return -1 if this[first] < this[second],
           *          0 if this[first] = this[second]
           *          1 if this[first] > this[second]
           * @throws IndexOutOfBoundsException if one
           *      or both indices are outside of the
           *      limits of this sequence.
           */
          public int compare(int first, int second);
      
          /**
           * Swaps two elements by their indices.
           * This is roughly equivalent to this sequence:
           * <pre>
           *   temp = this[first];
           *   this[first] = this[second];
           *   this[second] = temp;
           * </pre>
           */
          public void swap(int first, int second);
      
      }
      
      interface Sorter {
         /**
          * sorts an interval of a sequence.
          * @param sequence the sequence to be sorted.
          * @param off the start of the interval to be sorted.
          * @param the length of the interval to be sorted.
          */
         public void sort(Sortable sequence, int off, int len);
      }
      

      然后你可以让你的排序算法实现Sorter,而你的数据结构实现Sortable。 当然,可以将 Sortable 的两个函数拆分为 IndexComparator 和 IndexSwapper(不是 Int... 就像您命名它们),但它们都直接耦合到您的数据结构(由您的两个数组组成)。

      【讨论】:

        猜你喜欢
        • 2021-04-09
        • 1970-01-01
        • 1970-01-01
        • 2018-05-16
        • 1970-01-01
        • 2011-05-10
        • 2018-10-01
        • 1970-01-01
        • 2011-12-02
        相关资源
        最近更新 更多