【问题标题】:Deriving Time Complexity from an algorithm [duplicate]从算法推导时间复杂度
【发布时间】:2017-09-24 06:18:25
【问题描述】:

我正在尝试了解算法的时间复杂度。我的教授已经把它推到了大 O 之外,并希望我们能够推导出数学函数的算法。我很难概念化这是如何完成的并且正在寻求帮助。在我的课堂笔记中,提供了一个选择排序算法(如下面的代码所示)。笔记提出了以下问题:“导出一个函数 f(n),它对应于 minIndex 或 nums 的任何位置在最坏情况下被修改的总次数。 现在笔记告诉我答案是 f(n)= 1/2n^2 + 5/2n + 3。我想知道是否有人可以解释这是怎么发生的。

我的教授告诉我们计算内循环中的操作并找出解决办法。所以我相信在最坏的情况下,在内部循环中 if 语句总是执行,这意味着我们运行循环 n-i-1 次,我通过取 n 得到这些值(for循环必须小于的边界并减去它由起始条件 (i+1)。然后我查看外部循环,我看到它从 i 开始直到它到达 n-1,所以它可以写成 (n-1)-i 或就像内部循环一样循环,n-i-1。进一步看,外部循环中有三个修改,所以我们得到 (n-i-1)+3 (我可以把它写成 (n-i+2) 吗?

内循环最坏情况下的修改次数: n-i-1

外循环在最坏情况下的修改次数: (n-i-1)+3

现在我想知道你如何计算完成的两个不同的修改并变成 f(n)= 1/2n^2 + 5/2n + 3。

public static void selectionSort(int[] nums) {

        int n = nums.length;
        int minIndex;

        for(int i = 0; i < n-1; i++) {
            //find the index of themin number.
            minIndex = i;

            for(int j = i+1; j < n; j++) {
                if(nums[j] < nums[minIndex]) {
                    minIndex = j;
                }
                int temp = nums[i];
                nums[i] = nums[minIndex];
                nums[minIndex] = temp;
            }
        }
}

【问题讨论】:

    标签: java algorithm loops for-loop code-analysis


    【解决方案1】:

    外循环运行多少次?
    n - 1

    对于外循环的每次迭代,内循环运行多少次?
    n - 1 次下降到1 次,随着外循环的进行,平均而言:
    ((n - 1) + 1) / 2 = n / 2 次。

    那么,内循环总共运行了多少次
    (n - 1) * (n / 2) = n^2 / 2 - n / 2。。 p>

    minIndex被修改了多少次?
    每个外循环一次 + 每个内循环一次:
    (n - 1) + (n^2 / 2 - n / 2) = n^2 / 2 + n / 2 - 1 次。

    nums的位置被修改了多少次?
    每个内循环两次:
    2 * (n^2 / 2 - n / 2) = n^2 - n 次。

    修改是多少?
    (n^2 / 2 + n / 2 - 1) + (n^2 - n) = (3*n^2 - n) / 2 - 1
    1½n² - ½n - 1


    这和你说的你的笔记有不同的答案,所以让我们证明一下。

    首先,我们添加调试打印,即打印任何修改,包括修改号。

    public static void selectionSort(int[] nums) {
                                                  int mod = 0;
        int n = nums.length;
        int minIndex;
    
        for(int i = 0; i < n-1; i++) {
            //find the index of themin number.
            minIndex = i;                         System.out.printf("%2d: minIndex = %d%n", ++mod, i);
    
            for(int j = i+1; j < n; j++) {
                if(nums[j] < nums[minIndex]) {
                    minIndex = j;                 System.out.printf("%2d: minIndex = %d%n", ++mod, j);
                }
                int temp = nums[i];
                nums[i] = nums[minIndex];         System.out.printf("%2d: nums[%d] = %d%n", ++mod, i, nums[minIndex]);
                nums[minIndex] = temp;            System.out.printf("%2d: nums[%d] = %d%n", ++mod, minIndex, temp);
            }
        }
    }
    

    最坏的情况是对一个递减数字数组进行排序,所以让我们尝试 3 个数字:

    int[] nums = { 3, 2, 1 };
    selectionSort(nums);
    System.out.println(Arrays.toString(nums));
    

    我们希望 (3*n^2 - n) / 2 - 1 = (3*3^2 - 3) / 2 - 1 = 24 / 2 - 1 = 11 修改。

     1: minIndex = 0
     2: minIndex = 1
     3: nums[0] = 2
     4: nums[1] = 3
     5: minIndex = 2
     6: nums[0] = 1
     7: nums[2] = 2
     8: minIndex = 1
     9: minIndex = 2
    10: nums[1] = 2
    11: nums[2] = 3
    [1, 2, 3]
    

    是的,11 处修改。

    让我们试试 9:

    int[] nums = { 9, 8, 7, 6, 5, 4, 3, 2, 1 };
    

    (3*n^2 - n) / 2 - 1 = (3*9^2 - 9) / 2 - 1 = 234 / 2 - 1 = 116 修改。

      1: minIndex = 0
      2: minIndex = 1
      3: nums[0] = 8
      4: nums[1] = 9
      5: minIndex = 2
      6: nums[0] = 7
          . . .
    111: nums[6] = 7
    112: nums[8] = 8
    113: minIndex = 7
    114: minIndex = 8
    115: nums[7] = 8
    116: nums[8] = 9
    [1, 2, 3, 4, 5, 6, 7, 8, 9]
    

    是的,116 次修改。

    由经验证据验证的公式:
    f(n) = (3*n^2 - n) / 2 - 1

    【讨论】:

    • 感谢您的解释!非常彻底,真的帮助我了解发生了什么!
    • @AhmedKidwai 如果您发现答案有用,您应该点击答案左侧的向上箭头。 --- 您还应该通过单击复选标记来接受答案,以便其他人可以看到您的问题得到了满意的回答。
    猜你喜欢
    • 2012-05-09
    • 1970-01-01
    • 1970-01-01
    • 2021-09-19
    • 1970-01-01
    • 1970-01-01
    • 2010-10-17
    • 2013-12-31
    相关资源
    最近更新 更多