【问题标题】:Benchmarking Sorting Algorithms Java; Average Run Times are incorrect基准排序算法 Java;平均运行时间不正确
【发布时间】:2021-11-03 04:26:19
【问题描述】:

虽然我了解以下基准测试方法并不理想,但我正在对排序算法进行基准测试以帮助更好地理解算法和数据结构。

我想列出“大”n 500000 和小“n”大小数组 50 的平均运行时间,但我的平均值一直在增加。

我不确定我哪里出错了:

    public class BenchmarkingAlgorithms
    {
        public static void main(String[] args)
        {
            int[] largeUnsortedArray = largeArrayWithRandomInts(500000);

        
      
        bubbleSort(largeUnsortedArray);
        
        selectionSort(largeUnsortedArray);
        insertionSort(largeUnsortedArray);
        benchmarkQuickSort(largeUnsortedArray);
        benchmarkMergeSort(largeUnsortedArray);
        
        
        int[] smallUnsortedArray = smallArrayWithRandomInts(50);

        bubbleSort(smallUnsortedArray);
        selectionSort(smallUnsortedArray);
        insertionSort(smallUnsortedArray);
        benchmarkQuickSort(smallUnsortedArray);
        benchmarkMergeSort(smallUnsortedArray);
    }

    /**
     * Sorting an array of ints in ascending order using bubbleSort
     * Best-Case Complexity: O(n), Average Complexity: O(n^2), Worst-Case Complexity: O(n^2)
     * O(n) is achieved in Best-Case (already sorted array) using the alreadySorted flag
     * @param array
     * @return
     */
    static int[] bubbleSort(int[] array)
    {
         int bubbleSortTime[] = new int[500];
          int x, y;
          for (x = 0; x< 500; x++) {
              
          
        int temp;
        boolean alreadySorted = true;
        long start = System.nanoTime();
       
        {
            for (int i = 0; i < array.length; i++)
        {
          

            for (int j = 0; j < array.length - 1; j++)
            {

                if (array[j] > array[j + 1])
                {
                    alreadySorted = false;
                    temp = array[j + 1];
                    array[j + 1] = array[j];
                    array[j] = temp;
                }
                
            }
            if (alreadySorted == true)
            {
                break;
            }
            
        }
            long end = System.nanoTime();
            
            long bubbleSortRunTime = end - start;
            
            bubbleSortTime[x] = (int) bubbleSortRunTime;
            x++;
            

        }
        // getting array length
        int length = bubbleSortTime.length;
 
        // default sum value.
        int sum = 0;
 
        // sum of all values in array using for loop
        for (int i = 0; i < bubbleSortTime.length; i++) {
            sum += bubbleSortTime[i];
        }
 
        double average = sum / length;
         
        System.out.println("Average of array : "+average + " nano seconds.");
 
    }
        
          

        return array;
          
    
    }

    /**
     * Sorting an array of ints in ascending order using selectionSort
     * Best-Case Complexity: O(n^2), Average Complexity: O(n^2), Worst-Case Complexity: O(n^2)
     * @param array
     * @return
     */
    static int[] selectionSort(int[] array)
    {
        
         int selectionSortTime[] = new int[500];
         int x, y;
         for (x = 0; x< 500; x++) {
          
        int min;
        int pos = 0;
        long start = System.nanoTime();
     
        {
            for (int i = 0; i < array.length - 1; i++)
            {
               
                min = array[i];
                for (int j = i + 1; j < array.length; j++)
                {
                    if (array[j] < min)
                    {
                        min = array[j];
                        pos = j;
                    }
                }
                array[pos] = array[i];
                array[i] = min;
            }
           

        }
        long end = System.nanoTime();
        
        long selectionSortRunTime = end - start;
        
        selectionSortTime[x] = (int) selectionSortRunTime;
        x++;
        

    
    // getting array length
    int length = selectionSortTime.length;

    // default sum value.
    int sum = 0;

    // sum of all values in array using for loop
    for (int i = 0; i < selectionSortTime.length; i++) {
        sum += selectionSortTime[i];
    }

    double average = sum / length;
     
    System.out.println("Average of array : "+average + " nano seconds.");

}
    
        
        return array;
    }

    /**
     * Sorting an array of ints in ascending order using insertionSort
     * Best-Case Complexity: O(n), Average Complexity: O(n^2), Worst-Case Complexity: O(n^2)
     * @param array
     * @return
     */
    static int[] insertionSort(int[] array)
    {
        
        int insertionSortTime[] = new int[500];
      int x, y;
        for (x = 0; x< 500; x++) {
        long start = System.nanoTime();
        int j;

       
        {
            for (int i = 1; i < array.length; i++)
            {
             

                int key = array[i];

                for (j = i - 1; (j >= 0) && (key < array[j]); j--)
                {
                    array[j + 1] = array[j];
                }
                array[j + 1] = key;
            }
          

        }
        long end = System.nanoTime();
    long insertionSortRunTime = end - start;
        
        insertionSortTime[x] = (int) insertionSortRunTime;
        x++;
        

    
    // getting array length
    int length = insertionSortTime.length;

    // default sum value.
    int sum = 0;

    // sum of all values in array using for loop
    for (int i = 0; i < insertionSortTime.length; i++) {
        sum += insertionSortTime[i];
    }

    double average = sum / length;
     
    System.out.println("Average of array : "+average + " nano seconds.");

}
        

        return array;
    }

    /**
     * Sorting an array of ints in ascending order using quickSort
     * Best-Case Complexity: O(n log(n)), Average Complexity: O(n log(n)), Worst-Case Complexity: O(n^2))
     * @param array
     * @return
     */
    static void quickSort(int[] array, int low, int high)
    {
        
        int pivot = array[low + ((high - low) / 2)];
        int i = low;
        int j = high;


            while (i <= j)
            {

                while (array[i] < pivot)
                {
                    i++;
                }
                while (array[j] > pivot)
                {
                    j--;
                }
                if (i <= j)
                {
                    int temp = array[i];
                    array[i] = array[j];
                    array[j] = temp;
                    i++;
                    j--;
                }
            }

            if (low < j)
            {
                quickSort(array, low, j);
            }

            if (i < high)
            {
                quickSort(array, i, high);
            }
        }

    /**
     * Helping method to benchmark quick sort's execution time
     * @param array
     */
    static void benchmarkQuickSort(int[] array)
    { 
        int quickSortTime[] = new int[500];
          int x, y;
          for (x = 0; x< 500; x++) {
        long start = System.nanoTime();
        quickSort(array, 0, array.length - 1);
        long end = System.nanoTime();
        long quickSortRunTime = end - start;
        
        quickSortTime[x] = (int) quickSortRunTime;
        x++;
        

    
    // getting array length
    int length = quickSortTime.length;

    // default sum value.
    int sum = 0;

    // sum of all values in array using for loop
    for (int i = 0; i < quickSortTime.length; i++) {
        sum += quickSortTime[i];
    }

    double average = sum / length;
     
    System.out.println("Average of array : "+average + " nano seconds.");

}
        
    }

    /**
     * Sorting an array of ints in ascending order using mergeSort
     * Best-Case Complexity: O(n log(n)), Average Complexity: O(n log(n)), Worst-Case Complexity: O(n log(n)))
     * @param array
     * @return
     */
    public static int[] mergeSort(int[] array)
    {
        if (array.length == 1)
        {
            return array;
        }

        int[] array1 = new int[(array.length/2)];
        int[] array2 = new int[(array.length-array1.length)];

        System.arraycopy(array, 0, array1, 0, array1.length);
        System.arraycopy(array, array1.length, array2, 0, array2.length);

        mergeSort(array1);
        mergeSort(array2);

        merge(array1, array2, array);
        return array;
    }

    /**
     * Merges 2 sorted arrays of ints
     * @param array1
     * @param array2
     * @param mergedArray
     * @return
     */
    static void merge(int[] array1, int[] array2, int[] mergedArray)
    {
        int array1Index = 0;
        int array2Index = 0;
        int pos = 0;
        while ((array1Index < array1.length) && (array2Index < array2.length))
        {
            if (array1[array1Index] < array2[array2Index])
            {
                mergedArray[pos] = array1[array1Index];
                array1Index++;
                pos++;
            } else
            {
                mergedArray[pos] = array2[array2Index];
                array2Index++;
                pos++;
            }
        }

        if (array1Index < array2Index)
        {
            System.arraycopy(array1, array1Index, mergedArray, pos, array1.length - array1Index);
        }
        else if (array2Index < array1Index) ;
        {
            System.arraycopy(array2, array2Index, mergedArray, pos, array2.length - array2Index);
        }
    }

    /**
     * Helping method to benchmark merge sort's execution time
     * @param array
     */
    static void benchmarkMergeSort(int[] array)
    {
        int mergeSortTime[] = new int[500];
      int x, y;
        for (x = 0; x< 500; x++) {
        long start = System.nanoTime();
        mergeSort(array);
        long end = System.nanoTime();
  long quickSortRunTime = end - start;
        
        mergeSortTime[x] = (int) quickSortRunTime;
        x++;
        

    
    // getting array length
    int length = mergeSortTime.length;

    // default sum value.
    int sum = 0;

    // sum of all values in array using for loop
    for (int i = 0; i < mergeSortTime.length; i++) {
        sum += mergeSortTime[i];
    }

    double average = sum / length;
     
    System.out.println("Average of array : "+average + " nano seconds.");
        }

}

    /**
     * Creates and returns an array with random ints
     * @param size the size of the array to be created
     * @return
     */
    static int[] largeArrayWithRandomInts(int size)
    {
        int[] largeArray = new int[size];

        for (int i = 0; i < size; i++)
        {
            largeArray[i] = (int) (Math.random() * Math.random() * 500000);
        }
        return largeArray;
    }
    
    static int[] smallArrayWithRandomInts(int size)
    {
        int[] smallArray = new int[size];

        for (int i = 0; i < size; i++)
        {
            smallArray[i] = (int) (Math.random() * Math.random() * 50);
        }
        return smallArray;
    }

    /**
     * Prints the elements of  one dimensional array of type int
     * @param array
     */
    static void printArray(int[] array)
    {
        for (int i = 0; i < array.length; i++)
        {
            System.out.print(array[i] + " ");
        }
        System.out.println();
    }

}

我感谢任何见解。随时准备学习新事物。

【问题讨论】:

  • double average = sum / length; 为什么要把这个打印出来作为平均时间?
  • 这是因为我试图将排序的每个时间分配给数组中的一个空间,并且我想对数组进行平均。我想简单地打印出大 n 和小 n 这些算法的平均运行时间。
  • 我希望它运行 500 次迭代,每个 n 大小。 500000 和 50。

标签: java algorithm sorting runtime


【解决方案1】:

你的方法有很多问题。

  1. 您正在通过取bubbleSortTime 中 500 个元素的平均值来计算和打印中间时间。对于第一次运行,不要除以 bubbleSortTime.length(即 500),而应该除以 x + 1 以获得到目前为止您已完成的运行的平均值。
  2. 由于System.nanoTime() 的工作方式,您正在分别对每次运行进行计时,舍入到大约 50 纳秒(请参阅 javadocs)。您应该做的是将开始时间存储到一个变量中,然后在一个循环中运行您想要计时 X 次的代码(通常 100-1000 次就足够了,更多的运行将给出更精确的结果),然后记录结束时间,最后将经过的时间除以 X,得到定时代码的平均运行时间。
  3. 在开始计时代码之前,您应该至少运行一次计时代码。这将导致加载所有类和所需的系统库,这可能是一次稍慢的操作。

【讨论】:

  • 好的,对于 1) 我应该将此长度更改为 x +1?双重平均 = 总和 / 长度;
  • 我还以为我将每次都存储到数组中,然后对数组进行平均。这是不准确的吗?我只是想找到具有大 n 和小 n 的每个算法的平均值。然而,我一直在打印随机平均值,这些平均值是负数,而且需要很长时间。这是正常的吗?
  • 第 1 点说明了您当前时间不正确(并且还在增加)的主要原因。第 2 点和第 3 点告诉您应该如何做才能获得合理的结果,如果您使 X 足够大,甚至可以跳过第 3 点。因此,纯粹遵循第 2 点,您只会对算法的 X 次运行进行计时,并从中计算平均值。正如您所提到的,这更准确,因为您在 100-1000 次运行中只计算一次时间,而不是 100-1000 次。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-28
  • 2020-10-09
  • 1970-01-01
相关资源
最近更新 更多