了解 java 中 ArrayList 的排序方式

Understand how sorting with compare works for an ArrayList in java

提问人:Anish Ghimire 提问时间:8/28/2023 最后编辑:PinoAnish Ghimire 更新时间:8/29/2023 访问量:88

问:

我想了解以下比较器如何按升序为我提供结果:

Comparator<Integer> ints = (i1, i2) -> i1 - i2;

作为实现提供如何给我结果升序? 您能否在 ArrayList 的上下文中使用元素 [5, 4, 1, 2] 进行解释?我正在寻找一些类似的解释:第一个 1 与 4 进行比较,结果是 4-1=3,这是一个正数,arraylist 的当前状态变成这个 [4, 5, 1, 2] 以此类推,得到 [1, 2, 4, 5] 的最终结果。i1-i2

我想了解比较器实现的工作原理。

Java 排序 arraylist 比较器

评论

1赞 Slaw 8/29/2023
请注意,对于足够大的值,此实现容易受到整数溢出/下溢的影响,从而导致不正确的比较。最好只使用 or .也就是说,Shila 的回答很好地解释了这个比较器的实现是如何工作的(尽管实现使用的排序算法可能不同;无论如何,比较器算法无关)。Comparator.naturalOrder()Integer::comparesort

答:

2赞 Pino 8/28/2023 #1

你的方法是错误的:你的短语“第一个 1 与 4 进行比较(依此类推)”描述了一种排序算法,但不知道任何排序算法。背后的想法是,任何排序算法都需要比较项目对,因此 为任何排序算法提供了这种特定功能,包括 ArrayList.sort() 实现的算法(无论它是什么)。未来版本的 Java 可能会实现一种新的、更好的、尚未发明的算法,并且您提供的算法仍然有效且必要。ComparatorComparatorComparatorComparator

4赞 Shila Mosammami 8/29/2023 #2

比较器的比较功能定义了两个元素的顺序。让我们从比较的角度了解减法是如何工作的: 如果您有:

  1. i1 > i2,则 () 为正数。i1 - i2

  2. i1 < i2,则为负数。i1 - i2

  3. i1 == i2,则为零。i1 - i2

    比较器函数的结果:compare

    • 负值表示第一个参数小于第二个参数。
    • 正值表示第一个参数大于第二个参数。
    • 零表示参数相等。

    给定列表 [5, 4, 1, 2] 和比较器,让我们一步一步地看:ints = (i1, i2) -> i1 - i2

    1. 比较 5 和 4:

      • 5 - 4 = 1(正数)
      • 这意味着 5 > 4,因此 5 应该在列表中的 4 之后。
      • 列表变为 [4, 5, 1, 2]。
    2. 比较 5 和 1:

      • 5 - 1 = 4(正数)
      • 这意味着 5 > 1,所以 5 应该在 1 之后。
      • 列表变为 [4, 1, 5, 2]。
    3. 比较 5 和 2:

      • 5 - 2 = 3(正数)
      • 这意味着 5 > 2,所以 5 应该在 2 之后。
      • 列表变为 [4, 1, 2, 5]。
    4. 比较 4 和 1:

      • 4 - 1 = 3(正数)
      • 这意味着 4 > 1,所以 4 应该在 1 之后。
      • 列表变为 [1, 4, 2, 5]。
    5. 比较 4 和 2:

      • 4 - 2 = 2(正数)
      • 这意味着 4 > 2,所以 4 应该在 2 之后。
      • 列表变为 [1, 2, 4, 5]。

此时,列表按升序排序,因此比较停止。

上述步骤假设一个简单的气泡排序,以便进行说明。

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class comparing {
    public static void main(String[] args) {
        // Initialize ArrayList
        List<Integer> numbers = new ArrayList<>();
        numbers.add(5);
        numbers.add(4);
        numbers.add(1);
        numbers.add(2);
        // Print the original list
        System.out.println("\t\t Original list: " + numbers);
        // Custom comparator
        Comparator<Integer> ints = (i1, i2) -> i1 - i2;
        // Sort using the comparator
        numbers.sort(ints);
        // Print the sorted list
        System.out.println("\t\t Sorted list: " + numbers);
    }

}

结果将是:enter image description here

在 ArrayList.sort() 的情况下,底层实现使用 TimSort(MergeSort 和 InsertionSort 的混合体),它不会像示例那样通过反复比较和交换相邻对来排序。

我希望它有所帮助。

评论

1赞 Basil Bourque 8/29/2023
好答案。更好的是提到整数溢出的危险,并在实际工作中建议使用Slaw提到的解决方案。Comparator.naturalOrder()Integer::compare
0赞 Sören 8/29/2023
不应该有第 6 步比较 1 和 2 吗?在这种情况下,它们恰好是正确的顺序,但没有什么可以保证的。
0赞 Shila Mosammami 8/29/2023
ArrayList.sort() 方法不会像您提供的示例那样通过重复比较和交换相邻对来排序。这将是 Bubble Sort 算法背后的一个基本思想,这不是 Java 的 ArrayList.sort() 使用的。您的分步过程仅交换对,但 TimSort 将列表分解为更小的块,对这些块进行排序,然后将它们合并在一起。因此,除了简单的相邻对之外,还会有许多比较。你是对的,1 和 2 之间会有比较。
1赞 Anish Ghimire 8/30/2023
谢谢你的详细解释,希拉。我现在更清楚了。
0赞 Shila Mosammami 8/30/2023
欢迎您@AnishGhimire
0赞 hermit 8/29/2023 #3

我想您想了解排序算法如何在内部使用比较器。那么,让我们看看如何使用 Comparator' 对列表进行排序。Collections.sort()

让我们看一下 JDK,具体看看插入排序如何使用比较器。

这是用于插入排序的 JDK 代码片段,用于对列表进行排序。Collections.sort()size < 7

for (int i=low; i<high; i++){
    for (int j=i; j>low && c.compare(dest[j-1], dest[j])>0; j--)
        swap(dest, j, j-1);
    }

   //remaining logic
}

我们可以看到,排序算法使用该方法来决定排序顺序。c.compare()

假设这是我的比较器函数:

class MyComparator implements Comparator<Integer> {
   @Override
   public int compare(Integer x, Integer y) {
       return x - y;
   }
}

排序算法将计算每个元素。而且,只有当上面的表达式大于 0 时,它才会交换左右值。即 if OR > .c.compare(dest[j-1], dest[j]) > 0x > ydest[j-1]dest[j]

因此,交换后,基本上是按升序对列表进行排序。smaller element in the right comes to left and greater element goes to right side

如果我们在方法中这样做,则将使用类似的逻辑以相反的顺序(降序)进行排序。y-xcompare()

评论

0赞 Anish Ghimire 8/30/2023
这个答案对于更多地了解比较器的内部细节非常有帮助,并准确地回答了我的问题。谢谢。
0赞 hermit 8/30/2023
很高兴它帮助了@AnishGhimire。你能接受它作为答案吗?对于其他学习者来说,找出最相关的答案会很有帮助。