为啥冒泡排序是 O(n^2)?

Posted

技术标签:

【中文标题】为啥冒泡排序是 O(n^2)?【英文标题】:Why is bubble sort O(n^2)?为什么冒泡排序是 O(n^2)? 【发布时间】:2012-07-13 17:34:57 【问题描述】:
for (int front = 1; front < intArray.length; front++)

    for (int i = 0; i  < intArray.length - front; i++)
    
        if (intArray[i] > intArray[i + 1])
        
            int temp = intArray[i];
            intArray[i] = intArray[i + 1];
            intArray[i + 1] = temp;
        
    

内部循环正在迭代:n + (n-1) + (n-2) + (n-3) + ... + 1 次。

外部循环正在迭代:n 次。

所以你得到 n *(数字 1 到 n 的总和)

那不是 n * ( n*(n+1)/2 ) = n * ( (n^2) + n/2 )

这将是 (n^3) + (n^2)/2 = O(n^3) 吗?

我很肯定我做错了。为什么不是 O(n^3)?

【问题讨论】:

您将外部n 数了两次。您的内部循环本身是 O(n)。 不要吹毛求疵,但您显示的算法是 Selection sort 而不是 Bubble sort 上周,我写了一篇关于渐近复杂性的文章,巧合的是,我以冒泡排序为例。试一试 :-) (en.algoritmy.net/article/44682/Asymptotic-complexity)。你的错误是,正如 Henk 所说的那样,内循环是 O(n)。 O(n^2) - 算术顺序的总和是两个循环的复杂度。 我同意,这不是冒泡排序 添加评论,因为此处显示的算法是编辑后的冒泡排序。我读了 cmets 并感到困惑,但相信现在已经解决了。 【参考方案1】:

这是另一个加速冒泡排序的版本,当我们只使用一个变量 swapped 来提前终止第一个 for 循环时。您可以获得更好的时间复杂度。

#include <stdio.h>
#include <stdbool.h>
#define MAX 10

int list[MAX] = 1,8,4,6,0,3,5,2,7,9;

void display()
   int i;
   printf("[");

   for(i = 0; i < MAX; i++)
      printf("%d ",list[i]);
   

   printf("]\n");


void bubbleSort() 
   int temp;
   int i,j;

   bool swapped = false;       

   // 1st loop
   for(i = 0; i < MAX-1; i++)  
      swapped = false;

      // 2nd loop
      for(j = 0; j < MAX-1-i; j++) 
         printf("     Compare: [ %d, %d ] ", list[j],list[j+1]);

         if(list[j] > list[j+1]) 
            temp = list[j];
            list[j] = list[j+1];
            list[j+1] = temp;

            swapped = true;
         

      

      if(!swapped) 
         break;
      

      printf("Loop number %d#: ",(i+1)); 
      display();                     
   



main()
   printf("Before: ");
   display();
   printf("\n");

   bubbleSort();
   printf("\nAfter: ");
   display();

【讨论】:

【参考方案2】:
k=1(sigma k)n = n(n+1)/2
because:
  s = 1 +  2    + ... + (n-1) + n
  s = n + (n-1) + ... + 2     + 1
+)
===================================
  2s = n*(n+1)
   s = n(n+1)/2
in bubble sort, 
(n-1) + (n-2) + ... + 1 + 0 times compares 
which means, k=0(sigma k)n-1
, k=0(sigma k)n-1 equals [k=1(sigma k)n] - n
therefore, n(n+1)/2 - n = n(n-1)/2
which is 1/2(n^2-n) => O(1/2(n^2-n))
in big O notation, we remove constant, so
O(n^2-n)
n^2 is larger than n
O(n^2)

【讨论】:

【参考方案3】:

你基本上如何计算 N...

每行:+1

每个循环 *N

所以你开始添加数字到你的第一个循环,现在你有 N+1,你继续前进,你最终得到 N*N 或 N^2 时间加上一些数字。拉出这个数字,因为它与 N 相比通常微不足道。

N 几乎是循环中所有项目的表示,类似于 1,2,3...N。所以它只是代表一个数字,而不是循环多少次。

【讨论】:

【参考方案4】:

正如您所说,您的内部循环总共迭代 n + (n-1) + (n-2) + (n-3) + ... + 1 次。所以它是 O(n + (n-1) + (n-2) + (n-3) + ... + 1) = O(n(n+1)/2) = O(n^2)

【讨论】:

啊,刚刚经历了啊哈时刻。泰。 求解 (n*(n+1))/2 for n=5 得到 15,而不是 5^2=25。不一样。 那么我可以把它写成 O((n*(n+1))/2) 和 O(n^2) 吗?【参考方案5】:

内循环迭代n次(最坏情况):

for(int i = front; i < intArray.length; i++)

外层循环迭代n次:

for(int front = 0; front < intArray.length; front++)

因此 O(n^2)

【讨论】:

【参考方案6】:

你是正确的,外循环迭代 n 次,内循环也迭代 n 次,但是你重复计算了工作。如果您通过将顶层循环的每次迭代完成的工作相加来计算完成的总工作量,您会得到第一次迭代没有工作 n 工作,第二次工作 n - 1,第三次工作 n - 2 等等,因为第 i顶层循环的迭代让内部循环执行n - i 工作。

或者,您可以通过将完成的工作量乘以内部循环乘以循环运行的总次数来计算完成的工作。内循环每次迭代做 O(n) 次工作,外循环运行 O(n) 次迭代,所以总工作量是 O(n2)。

尝试将这两种策略结合起来是错误的。确实,外循环第一次工作 n,然后是 n - 1,然后是 n - 2,等等。但是,您不要将此工作乘以 n 来得到总数。这将计算每次迭代 n 次。相反,您可以将它们加在一起。

希望这会有所帮助!

【讨论】:

可能值得补充的是,Big O 描述了与输入大小成正比的算法的增长率,这不一定与所采用的确切迭代量相同让算法运行。 准确地说 BubbleSort 完成了 (n-1)*(n-1) 次迭代吗?因此 N^2 次迭代。这就是时间复杂度。我的假设是否正确? 冒泡排序不做 (n-1)*(n-1),它做外循环 (n-1) : 内循环 [(n-1),(n-2),( n-3),...,(2),(1)] 所以你可以说冒泡排序迭代内部循环 [(n-1),(n-2),(n-3),..., (2),(1)] 次。这是n(n-1)/2次,不是N^2次,但是正如用户“user849425”在上面的评论中建议的那样,Big O不是迭代次数。 大 O 符号太混乱了。内循环是 O(n-i) 而不是 O(n)

以上是关于为啥冒泡排序是 O(n^2)?的主要内容,如果未能解决你的问题,请参考以下文章

冒泡排序算法实现

冒泡排序为什么最佳负责度为O(n)

关于排序_重点是冒泡

冒泡排序和选择排序的Java实现

冒泡排序和选择排序的Java实现

1golang之冒泡排序