Simple-Java-Question-1

Java中如何高效地去确定一个Array中是否包含了某个值

怎么去一个数组(没有排序)是否包含了一个值,这在Java一个非常频繁、有用的操作。这在Stack Overflow中也是被提问量最高的问题之一。根据问题的赞最高的回答显示,这个问题可以有好几种不同的算法,但是算法的复杂度是不同的。接下来,我将会展示每种方法的算法复杂度

 

1.1 四中不同的方法去检查一个Array钟是否包含了某个值

1) 使用List:


public static boolean useList(String[] arr, String targetValue) {

    return Arrays.asList(arr).contains(targetValue);

}

 

2)使用Set:


public static boolean useSet(String[] arr, String targetValue) {

    Set set = new HashSet(Arrays.asList(arr));

    return set.contains(targetValue);

}

 

3)使用一个简单的循环


public static boolean useLoop(String[] arr, String targetValue) {

    for(String s: arr){

        if(s.equals(targetValue))

        return true;

    }

    return false;

}

 

4)使用Array.binarySearch():*下面的代码是错的,数组是已经被完成了排序,因为binarySearch()只能用于已经被排序好的数组,你可以看到使用下面的代码得到的结果非常怪异


public static boolean useArraysBinarySearch(String[] arr, String targetValue)

{

    int a = Arrays.binarySearch(arr, targetValue);

    if(a > 0)

        return true;

    else

        return false;

}

 

1.2 时间复杂度

大约的时间开销可以使用下面的代码获取。基本的思路就是使用一个大小为5、1K、10K的数组去查找,这种方法可能不是特别精确,但是这个思路非常简单

数组大小为5:


public static void main(String[] args) {
    String[] arr = new String[] { "CD", "BC", "EF", "DE", "AB"};

    //use list
    long startTime = System.nanoTime();
    for (int i = 0; i < 100000; i++) {
        useList(arr, "A");
    }
    long endTime = System.nanoTime();
    long duration = endTime - startTime;
    System.out.println("useList: " + duration / 1000000);


    //use set
    startTime = System.nanoTime();
    for (int i = 0; i < 100000; i++) {
        useSet(arr, "A");
    }
    endTime = System.nanoTime();
    duration = endTime - startTime;
    System.out.println("useSet: " + duration / 1000000);


    //use loop
    startTime = System.nanoTime();
    for (int i = 0; i < 100000; i++) {
        useLoop(arr, "A");
    }
    endTime = System.nanoTime();
    duration = endTime - startTime;
    System.out.println("useLoop: " + duration / 1000000);


    //use Arrays.binarySearch()
    startTime = System.nanoTime();
    for (int i = 0; i < 100000; i++) {
        useArraysBinarySearch(arr, "A");
    }
    endTime = System.nanoTime();
    duration = endTime - startTime;
    System.out.println("useArrayBinary: " + duration / 1000000);
}

 

结果:


useList: 13

useSet: 72

useLoop: 5

useArraysBinarySearch: 9


 

数组大小为1000:


String[] arr = new String[1000];

Random s = new Random();

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

    arr[i] = String.valueOf(s.nextInt());

}

 

结果:


useList: 112

useSet: 2055

useLoop: 99

useArrayBinary: 12


 

数组大小为10000:


String[] arr = new String[10000];

Random s = new Random();

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

    arr[i] = String.valueOf(s.nextInt());

}

 

结果:


useList: 1590

useSet: 23819

useLoop: 1526

useArrayBinary: 12


 

 

结果很清楚,使用简单的循环比使用collection效率更高,许多开发者喜欢使用List,但是效率并没有简单循环高。在对collection操作之前,需要将数组的内容push到collection中,这就需要将数组中所有的元素都读一遍。

如果使用userArrayBinary()方法,就需要将数组进行排序,但是实际情况中,很多数组都没有排序,那么就不能使用这个方法。

事实上,如果你真的需要检查一个数组/集合是否包含一个值,一个排序过得List或者tree可以在时间复杂度为O(log(n))内搞定它,或者使用hashset,时间复杂度为O(1)

 

你可能感兴趣的:(java)