【问题标题】:Sorting matched arrays in Java在Java中对匹配的数组进行排序
【发布时间】:2010-09-11 20:26:41
【问题描述】:

假设我有两个数组(在 Java 中),

int[] 数字;和 int[] 颜色;

数字中的每个第 i 个元素都对应于其颜色中的第 i 个元素。 例如,数字 = {4,2,1} 颜色 = {0x11、0x24、0x01};表示数字 4 是颜色 0x11,数字 2 是 0x24,等等。

我想对 numbers 数组进行排序,但仍然保留它,以便每个元素与其颜色对匹配。

例如。数字 = {1,2,4}; 颜色 = {0x01,0x24,0x11};

最干净、最简单的方法是什么?数组有几千个项目,所以最好放在适当的位置,但不是必需的。做一个 Arrays.sort() 和一个自定义比较器有意义吗?最好尽可能使用库函数。

注意:我知道“最佳”解决方案是为这两个元素创建一个类并使用自定义比较器。这个问题的目的是询问人们最快的编码方式。想象一下,在一场编程比赛中,你不会想要制作所有这些额外的类、比较器的匿名类等。更好的是,忘记 Java;你将如何用 C 编写代码?

【问题讨论】:

    标签: java sorting list


    【解决方案1】:

    如果您使用索引保留第三个数组并对其进行排序,则可以将 sort() 与自定义比较器一起使用,从而使数据保持不变。

    Java 代码示例:

    Integer[] idx = new Integer[numbers.length];
    for( int i = 0 ; i < idx.length; i++ ) idx[i] = i;              
    Arrays.sort(idx, new Comparator<Integer>() {
        public int compare(Integer i1, Integer i2) {                        
            return Double.compare(numbers[i1], numbers[i2]);
        }                   
    });
    
    // numbers[idx[i]] is the sorted number at index i
    // colors[idx[i]] is the sorted color at index i
    

    请注意,您必须使用Integer 而不是int,否则您不能使用自定义比较器。

    【讨论】:

    • 这是最快的方法......它不干净,但它是最快的编码。
    【解决方案2】:

    似乎最干净的做法是创建一个实现 Comparable 的自定义属性类。例如:

    class Color implements Comparable {
      private int number;
      private int color;
    
      // (snip ctor, setters, etc.)
    
      public int getNumber() {
        return number;
      }
      public int getColor() {
        return color;
      }
    
      public int compareTo(Color other) {
        if (this.getNumber() == other.getNumber) {
          return 0;
        } else if (this.getNumber() > other.getNumber) {
          return 1;
        } else {
          return -1;
        }
      }
    }
    

    然后您可以将排序算法与排序逻辑分开(如果您使用 List 而不是数组,则可以使用 Collections.sort),最重要的是,您不必担心以某种方式从两个数组中取出同步。

    【讨论】:

    • 是的,这是您在正常情况或应用程序中会执行的操作。但是在像编程比赛这样你需要快速编写代码的地方,我敢打赌你不会想写这些多余的东西。
    • 相反,这花了我大约一分钟的时间来写,这比我尝试保持两个数组同步并说服自己我做对了要少得多.
    • 你绝对应该创建一个自定义类。这是迄今为止最快的方法。如果花费的时间太长,请投资学习如何使用好的 IDE。
    【解决方案3】:

    如果您愿意分配一些额外的空间,您可以生成另一个数组,将其称为 extra,其元素如下:

    extra = [0,1,...,numbers.length-1]
    

    然后您可以使用带有自定义比较器的 Arrays.sort() 对这个额外的数组进行排序(在比较元素 i 和 j 时,实际上比较的是 numbers[extra[i]] 和 numbers[extra[j]])。这样,在对额外数组进行排序后,extra[0] 将包含最小数字的索引,并且由于数字和颜色没有移动,因此包含相应的颜色。
    这不是很好,但它可以完成工作,我真的想不出更简单的方法。

    顺便说一句,在比赛中我通常发现 C++ 模板对和漂亮的地图是必不可少的;)

    【讨论】:

    • 顺便说一句,您需要一个 Integer 数组而不是 int 数组才能使用自定义比较器。当您仅限于 Arrays.sort 时,基本类型只能根据其自然顺序进行排序。
    • 哦,对不起。这些天我对 Java 有点生疏了。
    【解决方案4】:

    为什么不引入一个对象来表示数字和颜色并为此实现比较器功能?

    另外,你真的需要一个数组,为什么不使用从 Collection 派生的东西?

    【讨论】:

    • 这种情况经常出现。我希望能够快速编写代码,而不需要额外的代码,例如在编程比赛中。
    【解决方案5】:

    我喜欢@tovare 的解决方案。制作一个指针数组:

    int ptr[] = { 1, 2, 3 };
    

    然后当您对数字进行排序时,交换 ptr 中的值而不是数字中的值。然后通过ptr数组访问,比如

    for (int i = 0; i < ptr.length; i++)
    {
       printf("%d %d\n", numbers[ptr[i]], colors[ptr[i]]);
    }
    

    更新:好的,看来其他人已经打败了我。我没有 XP。

    【讨论】:

      【解决方案6】:

      说明使用第三个索引数组的示例。不确定这是否是最好的实现。


      import java.util.*;

      public class Sort {
      
          private static void printTable(String caption, Integer[] numbers, 
                      Integer[] colors, Integer[] sortOrder){
      
              System.out.println(caption+
                      "\nNo   Num   Color"+
                      "\n----------------");
      
              for(int i=0;i<sortOrder.length;i++){
                  System.out.printf("%x    %d     %d\n", 
                          i,numbers[sortOrder[i]],colors[sortOrder[i]]);
      
              }
          }
      
      
          public static void main(String[] args) {
      
              final Integer[] numbers = {1,4,3,4,2,6};
              final Integer[] colors  = {0x50,0x34,0x00,0xfe,0xff,0xff};
              Integer[] sortOrder = new Integer[numbers.length];
      
              // Create index array.
              for(int i=0; i<sortOrder.length; i++){
                  sortOrder[i] = i;
              }
              printTable("\nNot sorted",numbers, colors, sortOrder);
      
              Arrays.sort(sortOrder,new Comparator<Integer>() {   
                  public int compare(Integer a, Integer b){
                      return numbers[b]-numbers[a];
                  }});
              printTable("\nSorted by numbers",numbers, colors, sortOrder);
      
              Arrays.sort(sortOrder,new Comparator<Integer>() {   
                  public int compare(Integer a, Integer b){
                      return colors[b]-colors[a];
                  }});
              printTable("\nSorted by colors",numbers, colors, sortOrder);
          }
      }
      

      输出应如下所示:

      未排序 没有数字颜色 ---------------- 0 1 80 1 4 52 2 3 0 3 4 254 4 2 255 5 6 255 按数字排序 没有数字颜色 ---------------- 0 6 255 1 4 52 2 4 254 3 3 0 4 2 255 5 1 80 按颜色排序 没有数字颜色 ---------------- 0 6 255 1 2 255 2 4 254 3 1 80 4 4 52 5 3 0

      【讨论】:

        【解决方案7】:

        一个快速的技巧是将两个数组与位移结合起来。制作一个 long 数组,使最高有效 32 位是数字,最低有效 32 位是颜色。使用排序方法,然后解包。

        【讨论】:

          【解决方案8】:

          编写自己的排序方法就足够了吗?一个简单的冒泡排序可能会很快编码(并且正确)。不需要额外的类或比较器。

          【讨论】:

          • 记住唐纳德。 D. Knuth/ The Art of Computer Programming 第 3 卷 - 排序、搜索和动态实现最优算法将......令人印象深刻! :-)
          【解决方案9】:

          感谢@tovare 以获得原始最佳答案。

          我在下面的回答通过 Maven 依赖 {net.mintern : primitive : 1.2.2} 从这个答案中删除了(现在)不必要的自动装箱:https://stackoverflow.com/a/27095994/257299

          int[] idx = new int[numbers.length];
          for( int i = 0 ; i < idx.length; i++ ) idx[i] = i;
          final boolean isStableSort = false;
          Primitive.sort(idx,
                         (i1, i2) -> Double.compare(numbers[i1], numbers[i2]),
                         isStableSort);
          
          // numbers[idx[i]] is the sorted number at index i
          // colors[idx[i]] is the sorted color at index i
          

          【讨论】:

            【解决方案10】:

            我猜您希望在尝试避免使用对象数组的同时优化性能(这会导致痛苦的 GC 事件)。 不幸的是,没有通用的解决方案,我想。 但是,对于您的具体情况,其中数字彼此不同,可能只需要创建两个数组。

            /**
             * work only for array of different numbers
             */
            private void sortPairArray(int[] numbers, int[] colors) {
                int[] tmpNumbers = Arrays.copyOf(numbers, numbers.length);
                int[] tmpColors = Arrays.copyOf(colors, colors.length);
                Arrays.sort(numbers);
                for (int i = 0; i < tmpNumbers.length; i++) {
                    int number = tmpNumbers[i];
                    int index = Arrays.binarySearch(numbers, number); // surely this will be found
                    colors[index] = tmpColors[i];
                }
            }
            

            两个排序后的数组可以用Int2IntOpenHashMap代替,这样运行速度更快,但内存使用量可能翻倍。

            【讨论】:

              【解决方案11】:

              您需要按颜色数组在数字数组中的相关项对颜色数组进行排序。指定一个比较数字的比较器,并将其用作颜色数组的比较。

              【讨论】:

                【解决方案12】:

                在 C 中最简单的方法是冒泡排序 + 双指针。当然最快的是快速排序+两个指针。当然,第二个指针维护了两个数组之间的相关性。

                我宁愿将存储在两个数组中的值定义为结构,并在单个数组中使用该结构。然后对它使用快速排序。您可以通过调用比较函数来编写通用版本的排序,然后可以为每个结构编写该函数,但是您已经知道了:)

                【讨论】:

                  【解决方案13】:

                  使用TreeMap

                  【讨论】:

                    猜你喜欢
                    • 2012-02-14
                    • 1970-01-01
                    • 1970-01-01
                    • 2016-01-24
                    • 1970-01-01
                    • 1970-01-01
                    • 2020-04-09
                    • 2013-06-21
                    • 2021-07-14
                    相关资源
                    最近更新 更多