java数组查找算法实现比较

标签: JMH Benchmark HashSet 搜索数组
19人阅读 评论(0) 收藏 举报
分类:

java数组查找算法实现比较

本文我们看看java不同数组查找算法,并使用JMH(Java Microbenchmark Harness)比较它们的性能,确定最优算法。

数据准备

我们在数组中随机生成字符串用作示例数据:

String[] seedArray(int length) {
    String[] strings = new String[length];
    Random value = new Random();
    for (int i = 0; i < length; i++) {
        strings[i] = String.valueOf(value.nextInt());
    }
    return strings;
}

为在每个基准测试中使用相同的数组,我们声明一个内部类带有数量及数组,用于JMH测试:

@State(Scope.Benchmark)
public static class SearchData {
    static int count = 1000;
    static String[] strings = seedArray(1000);
}

要使用HMH测试,需引用依赖(gradle脚本):

compile group: 'org.openjdk.jmh', name: 'jmh-core', version: '1.20'
compile group: 'org.openjdk.jmh', name: 'jmh-generator-annprocess', version: '1.20'

基本搜索

三种常用的搜索方法为:数组所谓List查找,数组作为Set查找,循环数组检查每个元素。让我们看看这三种方法:

boolean searchList(String[] strings, String searchString) {
    return Arrays.asList(SearchData.strings)
      .contains(searchString);
}

boolean searchSet(String[] strings, String searchString) {
    Set<String> stringSet = new HashSet<>(Arrays.asList(SearchData.strings));

    return stringSet.contains(searchString);
}

boolean searchLoop(String[] strings, String searchString) {
    for (String string : SearchData.strings) {
        if (string.equals(searchString))
        return true;
    }

    return false;
}

接下来我们使用三个类注解告诉JMH输出平均时间,单位为毫秒,进行5个预热迭代确保测试的可靠性:

@BenchmarkMode(Mode.AverageTime)
@Warmup(iterations = 5)
@OutputTimeUnit(TimeUnit.MICROSECONDS)

然后在循环中运行每个测试:

@Benchmark
public void searchArrayLoop() {
    for (int i = 0; i < SearchData.count; i++) {
        searchLoop(SearchData.strings, "T");
    }
}

@Benchmark
public void searchArrayAllocNewList() {
    for (int i = 0; i < SearchData.count; i++) {
        searchList(SearchData.strings, "T");
    }
}

@Benchmark
public void searchArrayAllocNewSet() {
    for (int i = 0; i < SearchData.count; i++) {
        searchSet(SearchData.strings, "S");
    }
}

每个测试方法运行1000次,结果大概如下:

SearchArrayTest.searchArrayAllocNewList  avgt   20    937.851 ±  14.226  us/op
SearchArrayTest.searchArrayAllocNewSet   avgt   20  14309.122 ± 193.844  us/op
SearchArrayTest.searchArrayLoop          avgt   20    758.060 ±   9.433  us/op

循环方法最有效,但至少部分原因是取决与我们如何使用集合。每次调用searchList()方法创建新的List实例,每次调用searchSet()方法同时会创建新的List和新的HashSet,创建这些对象会有额外的开销,而数组循环没有。

有效搜索

如果我们只创建依次List和Set的实例,然后重用他们,结果如何呢,让我们试试:

public void searchArrayReuseList() {
    List asList = Arrays.asList(SearchData.strings);
    for (int i = 0; i < SearchData.count; i++) {
        asList.contains("T");
    }
}

public void searchArrayReuseSet() {
    Set asSet = new HashSet<>(Arrays.asList(SearchData.strings));
    for (int i = 0; i < SearchData.count; i++) {
        asSet.contains("T");
    }
}

使用同样的JMH注解运行这些方法,并同样包裹在循环中执行并比较,结果有很大的差异:

SearchArrayTest.searchArrayLoop          avgt   20    758.060 ±   9.433  us/op
SearchArrayTest.searchArrayReuseList     avgt   20    837.265 ±  11.283  us/op
SearchArrayTest.searchArrayReuseSet      avgt   20     14.030 ±   0.197  us/op

List比原先稍微快点,Set下降到不足原来的1%!
现在我们删除了每次搜索需要创建新集合的耗时操作,结果有一定意义。搜索hash表,基于Hashset类,时间复杂度为O(1),而数组,基于ArrayList是O(n).

二分查找

这里介绍另一种搜索方法:二分查找。虽然非常高效,但要求数组必须有序。
让我们排序并尝试二分查找:

@Benchmark
public void searchArrayBinarySearch() {
    Arrays.sort(SearchData.strings);
    for (int i = 0; i < SearchData.count; i++) {
        Arrays.binarySearch(SearchData.strings, "T");
    }
}
SearchArrayTest.searchArrayBinarySearch  avgt   20     26.527 ±   0.376  us/op

二分查找非常快,比HashSet稍微差点,最差情况性能为O(logn),介于数组与hash表之间。

总结

我们介绍了集中方式实现搜索数组。基于测试结果,HashSet性能最佳,但必须先创建并存储其中。

查看评论

算法训练 数组查找及替换

算法训练 数组查找及替换  问题描述   给定某整数数组和某一整数b。要求删除数组中可以被b整除的所有元素,同时将该数组各元素按从小到大排序。如果数组元素数值在A到Z的ASCII之间,替换为对应字母。...
  • wangdd_199326
  • wangdd_199326
  • 2017-02-28 19:47:35
  • 284

java程序--对象数组查找与排序

  • 2011年06月14日 13:39
  • 5KB
  • 下载

java数组查找

import java.util.*; /** 面试题: 数组元素查找: 1、普通数组元素查找 2、二分查找 3、面试题:二分查找法运用 4、用java内部函数Arrays.binarySearch数...
  • yangting09032214
  • yangting09032214
  • 2015-07-16 18:38:44
  • 1527

JAVA实现二维数组中的查找(《剑指offer》)

最近在刷《剑指offer》里的编程题,但是网上关于《剑指offer》的解答多半是C或者C++的,而且官方(作者)也是在用C++进行讲解,这里自己用java写了一些题目的解答代码(当然也有部分是借鉴了网...
  • qq_15062527
  • qq_15062527
  • 2015-10-01 14:24:34
  • 1431

java笔试题:数组查找,查找和为最大的子数组

package com.bxh.array; import java.util.ArrayList; import java.util.Arrays; public class findMaxMi...
  • qq_32261399
  • qq_32261399
  • 2017-09-01 15:14:34
  • 154

蓝桥杯 ALGO-50 算法训练 数组查找及替换

问题描述   给定某整数数组和某一整数b。要求删除数组中可以被b整除的所有元素,同时将该数组各元素按从小到大排序。如果数组元素数值在A到Z的ASCII之间,替换为对应字母。元素个数不超过100,b在...
  • liuchuo
  • liuchuo
  • 2017-03-01 13:44:35
  • 304

A*算法实现八数码问题

  • 2010年05月26日 19:54
  • 3KB
  • 下载

数据结构各种排序算法实现及比较

  • 2011年05月09日 19:42
  • 249KB
  • 下载

华为OJ试题

  • 2017年10月23日 16:17
  • 27KB
  • 下载

java算法源码总结

  • 2009年04月23日 18:29
  • 1.06MB
  • 下载
    个人资料
    专栏达人 持之以恒
    等级:
    访问量: 51万+
    积分: 7582
    排名: 3581
    博客专栏
    最新评论