java sort 效率_性能对比:collections.sort vs treeSet sort vs java8 stream.sorted

0 写在前面的话

在项目中有一个排序问题,考虑到未来需要排序的数据量可能很大,想用一个性能较好的排序算法,现在有三套解决方法:jdk提供的集合的sort方法(Collections.sort)、一个可排序的数据结构TreeSet、Java8中流的排序(stream.sorted)。

我们都知道,TreeSet的底层是用红黑树实现的,它在调用集合上的add方法时,会始终保持集合中的数据排序,而Collection s.Sort()方法则会对整个集合数据进行排序,其底层有两种sort方法:legacyMergeSort(一种老的归并排序,默认是不使用,在未来版本会被移除)和TimSort.sort(这是一种归并排序merge sort和插入排序insertion sort的排序算法,如果待排序的数据大小小于32,直接使用二分插入排序),所以TreeSet的add()的时间复杂度为log(N),Collection的时间复杂度为O(n*log(N)。但如果要排序相同大小的数据,那么TreeSet排序和Collections.sort的复杂性是相同的,因为使用TreeSet时会add n次。

补充下 TimSort 的算法思想:为了减少对升序部分的回溯和对降序部分的性能倒退,将输入按其升序和降序特点进行了分区。排序的输入的单位不是一个个单独的数字,而是一个个的块-分区。其中每一个分区叫一个run。针对这些 run 序列,每次拿一个 run 出来按规则进行合并。每次合并会将两个 run合并成一个 run。合并的结果保存到栈中。合并直到消耗掉所有的 run,这时将栈上剩余的 run合并到只剩一个 run 为止。这时这个仅剩的 run 便是排好序的结果。

1 排序方法性能对比

本文主要是对三者排序方法的性能对比实验,所以不深究底层代码实现,直接上测试代码:

import com.google.common.base.Ticker;

import com.google.common.collect.Lists;

import org.junit.Test;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import java.util.Collections;

import java.util.List;

import java.util.TreeSet;

import java.util.stream.Collectors;

/**

* @author ming.zhou

* @date 2018/8/29

*/

public class TestSetSort {

private static final Logger LOGGER = LoggerFactory.getLogger(TestSetSort.class);

private static final int SIZE = 1000;

private List init(){

List datas = Lists.newArrayList();

for (int i = 0; i < SIZE; i ++){

datas.add(i);

}

Collections.shuffle(datas);

return datas;

}

@Test

public void testCollectionSort(){

List datas = init();

long startTime = Ticker.systemTicker().read();

Collections.sort(datas);

LOGGER.info("sorted data by collections, result : {}", datas);

LOGGER.info("collection sort use time : {}", (Ticker.systemTicker().read() - startTime) / 1000);

}

@Test

public void testTreeSet(){

List datas = init();

long startTime = Ticker.systemTicker().read();

TreeSet treeSet = new TreeSet<>(datas);

LOGGER.info("sorted data by treeSet, result : {}", treeSet);

LOGGER.info("tree set sort use time : {}", (Ticker.systemTicker().read() - startTime) / 1000);

}

@Test

public void testJava8Sort(){

List datas = init();

long startTime = Ticker.systemTicker().read();

List result = datas.stream()

.sorted()

.collect(Collectors.toList());

LOGGER.info("sorted by java8 stream, result : {}", result);

LOGGER.info("java8 stream sort use time : {}", (Ticker.systemTicker().read() - startTime) / 1000);

}

}

实验结果:

size : 1000

collection sort use time : 2257

tree set sort use time : 29412

java8 stream sort use time : 121645

size : 10000

collection sort use time : 39461

tree set sort use time : 45831

java8 stream sort use time : 113569

size : 10000 * 10

collection sort use time : 263307

tree set sort use time : 202949

java8 stream sort use time : 424212

size : 10000 * 100

collection sort use time : 2578863

tree set sort use time : 2646424

java8 stream sort use time : 924681

2 总结:

我们可以看到Collections.sort比TreeSet的性能要更好些,分析后可能是由于TreeSet在红黑树中新插入节点也需要消耗一定的时间,且每次插入后需要对原有的集合进行修改以使得新集合底层仍然是红黑树。 而且TreeSet只能使用一个比较器,但你却可以为Collection提供不同的比较器。Java8的流排序的效率相比前两个就有点低了,但Java8的流排序可以省去构造冗长的比较器,编写更简洁的代码。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值