给定运行时数据,如何知道排序程序是使用冒泡排序还是插入排序?

2023-12-30

我测量了一个排序程序/算法,并根据运行时数据,将其范围缩小为两种排序算法 - 冒泡排序和插入排序。

有没有办法确定它是哪一个?当然是在不知道代码的情况下。

它们都有相同的时间复杂度,我已经没有主意了。

时间复杂度数据:

  • 排序:O(n) 1000 个数字所需的时间 = 0.0047s
  • 随机未排序:O(n^2) 1000 个数字所需的时间 = 0.021 秒
  • 降序:O(n^2) 1000 个数字所需的时间 = 0.04 秒

提前致谢!


  1. 您用于排序的 1000 个元素太少

    测量的时间太短,无法代表有效的测量(因为大部分时间可能不会被排序本身使用,而是被窗口初始化、打开文件等使用......)。

    您需要至少 100 毫秒或更长的时间(理想情况是 1 秒)。

  2. 如果您有权访问正在排序的数据

    您可以引入对每种类型的排序都具有挑战性的数据集(并且从时间推断使用的算法)...例如,冒泡排序对于逆序排序的数组来说是最慢的...所以传递排序数据升序、降序和随机并比较时间。让我们与时俱进tasc,tdes,trnd假设升序排序,如果涉及冒泡排序,则应该是:

    tasc O(n) < trnd  < tdes O(n^2)
    

    so:

    tasc*n == tdes + margin_of error
    

    所以只是测试一下tdes/tasc接近n...有一定的误差范围...

    因此,您只需要创建一个示例数据,该数据对于特定类型的排序来说很难,而对于其他类型则不然......并且从时间上检测是否是这种情况,直到您发现使用的算法为止。

    这里有一些数据(所有时间都在[ms])我对我的冒泡排序和 asc 有序数据进行了测试:

       n     tasc    tdesc    tasc*n
    1000  0.00321  2.96147  3.205750
    2000  0.00609 11.76799 12.181855
    4000  0.01186 45.58834 47.445111
    

    更清楚我们是否有复杂的运行时间O(n)

    t(O(n)) = c*n
    

    转换为复杂的运行时O(n^2)(假设相同的常数时间c):

    t(O(n^2)) = c*n*n = t(O(n)) * n
    

    这样您就可以比较具有不同复杂性的时间,您只需将所有测量的时间转换为单个常见的复杂性......

  3. 是否可以选择排序数据大小

    那么正如评论中提到的那样,您可以推断出时代的增长率随着增加n(加倍)从中您可以估计复杂性,并从中您可以知道使用了哪种算法。

    因此,让我们假设测量时间为#2然后对于O(n)恒定时间c对于 tasc 应该是相同的(O(n)):

       n     tasc    c=tasc/n
    1000  0.00321 0.000003210
    2000  0.00609 0.000003045 
    4000  0.01186 0.000002965 
    

    对于 tdesc (O(n^2)):

       n     tdesc        tdesc/n^2
    1000   2.96147 0.00000296147000
    2000  11.76799 0.00000294199750
    4000  45.58834 0.00000284927125
    

    如你所见c两次或多或少是相同的tasc,tdesc这意味着他们遵守估计的复杂性O(n),O(n^2)

然而,如果不知道被测试的应用程序做了什么,就很难确定,因为排序可能先于处理……例如,可能会扫描数据以检测形式(排序、随机、几乎排序……),这在以下情况下是可行的:O(n)根据结果​​和数据大小,它可能会选择使用哪种排序算法...因此您的测量可能会测量不同的例程,从而使结果无效...

[edit1] 我有一个疯狂的想法,自动检测复杂性

只需测试所有测量时间与其相应时间之间的恒定时间常数是否大致相同n...这里简单C++/VCL code:

//$$---- Form CPP ----
//---------------------------------------------------------------------------
#include <vcl.h>
#include <math.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
double factorial[]= // n[-],t[ms]
    {
     11,0.008,
     12,0.012,
     13,0.013,
     14,0.014,
     15,0.016,
     16,0.014,
     17,0.015,
     18,0.017,
     19,0.019,
     20,0.016,
     21,0.017,
     22,0.019,
     23,0.021,
     24,0.023,
     25,0.025,
     26,0.027,
     27,0.029,
     28,0.032,
     29,0.034,
     30,0.037,
     31,0.039,
     32,0.034,
     33,0.037,
     34,0.039,
     35,0.041,
     36,0.039,
     37,0.041,
     38,0.044,
     39,0.046,
     40,0.041,
     41,0.044,
     42,0.046,
     43,0.049,
     44,0.048,
     45,0.050,
     46,0.054,
     47,0.056,
     48,0.056,
     49,0.060,
     50,0.063,
     51,0.066,
     52,0.065,
     53,0.069,
     54,0.072,
     55,0.076,
     56,0.077,
     57,0.162,
     58,0.095,
     59,0.093,
     60,0.089,
     61,0.093,
     62,0.098,
     63,0.096,
     64,0.090,
     65,0.100,
     66,0.104,
     67,0.111,
     68,0.100,
     69,0.121,
     70,0.109,
     71,0.119,
     72,0.104,
     73,0.124,
     74,0.113,
     75,0.118,
     76,0.118,
     77,0.123,
     78,0.129,
     79,0.133,
     80,0.121,
     81,0.119,
     82,0.131,
     83,0.150,
     84,0.141,
     85,0.148,
     86,0.154,
     87,0.163,
     88,0.211,
     89,0.151,
     90,0.157,
     91,0.166,
     92,0.161,
     93,0.169,
     94,0.173,
     95,0.188,
     96,0.181,
     97,0.187,
     98,0.194,
     99,0.201,
    100,0.185,
    101,0.191,
    102,0.202,
    103,0.207,
    104,0.242,
    105,0.210,
    106,0.215,
    107,0.221,
    108,0.217,
    109,0.226,
    110,0.232,
    111,0.240,
    112,0.213,
    113,0.231,
    114,0.240,
    115,0.252,
    116,0.248,
    117,0.598,
    118,0.259,
    119,0.261,
    120,0.254,
    121,0.263,
    122,0.270,
    123,0.281,
    124,0.290,
    125,0.322,
    126,0.303,
    127,0.313,
    128,0.307,
      0,0.000
    };
//---------------------------------------------------------------------------
double sort_asc[]=
    {
    1000,0.00321,
    2000,0.00609,
    4000,0.01186,
       0,0.000
    };
//---------------------------------------------------------------------------
double sort_desc[]=
    {
    1000, 2.96147,
    2000,11.76799,
    4000,45.58834,
       0,0.000
    };
//---------------------------------------------------------------------------
double sort_rand[]=
    {
    1000, 3.205750,
    2000,12.181855,
    4000,47.445111,
       0,0.000
    };
//---------------------------------------------------------------------------
double div(double a,double b){ return (fabs(b)>1e-10)?a/b:0.0; }
//---------------------------------------------------------------------------
AnsiString get_complexity(double *dat)  // expect dat[] = { n0,t(n0), n1,t(n1), ... , 0,0 }
    {
    AnsiString O="O(?)";
    int i,e;
    double t,n,c,c0,c1,a,dc=1e+10;
    #define testbeg for (e=1,i=0;dat[i]>0.5;){ n=dat[i]; i++; t=dat[i]; i++;
    #define testend(s) if ((c<=0.0)||(n<2.0)) continue; if (e){ e=0; c0=c; c1=c; } if (c0>c) c0=c; if (c1<c) c1=c; } a=fabs(1.0-div(c0,c1)); if (dc>=a){ dc=a; O=s; }


    testbeg;            c=div(t,n);                 testend("O(n)");
    testbeg;            c=div(t,n*n);               testend("O(n^2)");
    testbeg;            c=div(t,n*n*n);             testend("O(n^3)");
    testbeg;            c=div(t,n*n*n*n);           testend("O(n^4)");
    testbeg; a=log(n);  c=div(t,a);                 testend("O(log(n))");
    testbeg; a=log(n);  c=div(t,a*a);               testend("O(log^2(n))");
    testbeg; a=log(n);  c=div(t,a*a*a);             testend("O(log^3(n))");
    testbeg; a=log(n);  c=div(t,a*a*a*a);           testend("O(log^4(n))");
    testbeg; a=log(n);  c=div(t,n*a);               testend("O(n.log(n))");
    testbeg; a=log(n);  c=div(t,n*n*a);             testend("O(n^2.log(n))");
    testbeg; a=log(n);  c=div(t,n*n*n*a);           testend("O(n^3.log(n))");
    testbeg; a=log(n);  c=div(t,n*n*n*n*a);         testend("O(n^4.log(n))");
    testbeg; a=log(n);  c=div(t,n*a*a);             testend("O(n.log^2(n))");
    testbeg; a=log(n);  c=div(t,n*n*a*a);           testend("O(n^2.log^2(n))");
    testbeg; a=log(n);  c=div(t,n*n*n*a*a);         testend("O(n^3.log^2(n))");
    testbeg; a=log(n);  c=div(t,n*n*n*n*a*a);       testend("O(n^4.log^2(n))");
    testbeg; a=log(n);  c=div(t,n*a*a*a);           testend("O(n.log^3(n))");
    testbeg; a=log(n);  c=div(t,n*n*a*a*a);         testend("O(n^2.log^3(n))");
    testbeg; a=log(n);  c=div(t,n*n*n*a*a*a);       testend("O(n^3.log^3(n))");
    testbeg; a=log(n);  c=div(t,n*n*n*n*a*a*a);     testend("O(n^4.log^3(n))");
    testbeg; a=log(n);  c=div(t,n*a*a*a*a);         testend("O(n.log^4(n))");
    testbeg; a=log(n);  c=div(t,n*n*a*a*a*a);       testend("O(n^2.log^4(n))");
    testbeg; a=log(n);  c=div(t,n*n*n*a*a*a*a);     testend("O(n^3.log^4(n))");
    testbeg; a=log(n);  c=div(t,n*n*n*n*a*a*a*a);   testend("O(n^4.log^4(n))");

    #undef testend
    #undef testbeg
    return O+AnsiString().sprintf(" error = %.6lf",dc);
    }
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
    {
    mm_log->Lines->Clear();
    mm_log->Lines->Add("factorial "+get_complexity(factorial));
    mm_log->Lines->Add("sort asc  "+get_complexity(sort_asc));
    mm_log->Lines->Add("sort desc "+get_complexity(sort_desc));
    mm_log->Lines->Add("sort rand "+get_complexity(sort_rand));
    }
//-------------------------------------------------------------------------

与我的相关时间测量快速精确 bigint 阶乘 https://stackoverflow.com/a/18333853/2521214我只使用了 8 毫秒以上的较大时间,以及上面的排序测量,输出如下:

factorial O(n.log^2(n)) error = 0.665782
sort asc  O(n) error = 0.076324
sort desc O(n^2) error = 0.037886
sort rand O(n^2) error = 0.075000

该代码仅测试少数支持的复杂性并输出错误率最低的复杂性(c不同之间的恒定时间n)...

只需忽略 VCL 内容并将 AnsiString 转换为您想要的任何字符串或输出...

[edit2]我为此向我的应用程序添加了 gfx 输出(图表),该输出显示了我的一些测量数据中的噪声,例如阶乘:

并对其进行一些过滤:

输出的复杂度更适合这个阶乘O(n^1.4)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

给定运行时数据,如何知道排序程序是使用冒泡排序还是插入排序? 的相关文章

  • 如何计算 3D Morton 数(交织 3 个整数的位)

    我正在寻找一种快速计算 3D Morton 数的方法 这个网站 http www graphics stanford edu seander bithacks html InterleaveBMN有一个基于幻数的技巧来处理 2D Morto
  • c# GDI边缘空白检测算法

    我正在寻找解决方案检测边缘空白c 位图 来自 c 托管 GDI 库 图像将是透明的 or white 大多数 400x 图片的尺寸为 8000x8000px 边缘周围有大约 2000px 的空白 找出边缘的最有效方法是什么 x y 高度和宽
  • 使用什么算法来确定使系统达到“零”状态所需的最小操作数?

    这是一种更通用的问题 不是特定于语言的 有关要使用的想法和算法的更多信息 系统如下 它登记朋友群体之间的小额贷款 Alice and Bill要去吃午饭 比尔的卡坏了 所以爱丽丝支付了他的餐费 10 美元 第二天Bill and Charl
  • JavaScript 中的埃拉托斯特尼筛法对大量数据无限运行

    我一直在尝试写埃拉托斯特尼筛法 http en wikipedia org wiki Sieve of EratosthenesJavaScript 中的算法 基本上我只是按照以下步骤操作 创建从 2 到 n 1 的连续整数列表 令第一个素
  • 使用 dc.js 按条形值对条形图中的条形进行排序(排序)

    如何通过维度的计算值而不是维度本身的名称对 dc js 示例中的 x 轴 维度 进行排序 例如 请考虑序数条形图的 dc js 示例 https github com dc js dc js blob master web examples
  • Java按日期升序对列表对象进行排序[重复]

    这个问题在这里已经有答案了 我想按一个参数对对象列表进行排序 其日期格式为 YYYY MM DD HH mm 按升序排列 我找不到正确的解决方案 在 python 中使用 lambda 很容易对其进行排序 但在 Java 中我遇到了问题 f
  • 为什么 Dijkstra 算法使用减密钥?

    Dijkstra 教给我的算法如下 while pqueue is not empty distance node pqueue delete min if node has been visited continue else mark
  • 排序矩阵的选择算法

    这是谷歌面试问题 给定一个 N N 矩阵 所有行均已排序 所有列均已排序 找到矩阵的第 K 个最大元素 在 n 2 中执行它很简单 我们可以使用堆或合并排序 n lg n 对它进行排序 然后得到它 但是有没有更好的方法 比 n lg n 更
  • 你能用 C# 编写一个同样优雅的排列函数吗?

    我非常喜欢这个 6 行解决方案 并尝试在 C 中复制它 基本上 它会排列数组的元素 def permute xs pre if len xs 0 yield pre for i x in enumerate xs for y in perm
  • 大 ר 符号到底代表什么?

    我真的很困惑大 O 大 Omega 和大 Theta 表示法之间的区别 我知道大 O 是上限 大 Omega 是下限 但是大 theta 到底代表什么 我读过这意味着紧束缚 但是 这是什么意思 首先我们来了解一下什么是大O 大Theta和大
  • Java 中查看 ArrayList 是否包含对象的最有效方法

    我有一个 Java 对象的 ArrayList 这些对象有四个字段 我用其中两个字段来将对象视为与另一个对象相等 我正在寻找最有效的方法 给定这两个字段 以查看数组是否包含该对象 问题在于这些类是基于 XSD 对象生成的 因此我无法修改类本
  • 实时战略战争游戏人工智能算法

    我正在设计一款实时策略战争游戏 其中 AI 将负责控制大型六边形地图上的大量单位 可能超过 1000 个 一个单位有许多行动点 可以用于移动 攻击敌方单位或各种特殊行动 例如建造新单位 例如 一辆拥有 5 个行动点的坦克可以花费 3 个行动
  • 如何在 JavaScript 中对关联数组进行排序?

    我需要为我的一个项目通过 JS 对关联数组进行排序 我发现这个函数在 Firefox 中运行得很好 但不幸的是它在 IE8 OPERA CHROME 中不起作用 无法找到使其在其他浏览器中运行的方法 或者找到另一个适合该目的的函数 我真的很
  • 寻找公共子集的算法

    I have N number of sets Si of Numbers each of a different size Let m1 m2 mn be the sizes of respective sets mi Si and M
  • while循环的时间复杂度是多少?

    我正在尝试找出 while 循环的时间复杂度 但我不知道从哪里开始 我了解如何找到 for 循环的复杂性类别 但是当涉及到 while 循环时 我完全迷失了 关于从哪里开始有什么建议 提示吗 这是一个问题的示例 x 0 A n some a
  • 查找最接近点的多边形顶点的索引

    Heading 我需要找到最接近点的多边形的索引 所以在这种情况下 输出将是 4 和 0 这样 如果添加了红点 我就知 道将顶点放置在数组中的位置 有谁知道从哪里开始 抱歉 如果标题有误导性 我不知道如何正确表达它 In this case
  • 找到一个数字所属的一组范围

    我有一个 200k 行的数字范围列表 例如开始位置 停止位置 该列表包括除了非重叠的重叠之外的所有类型的重叠 列表看起来像这样 3 5 10 30 15 25 5 15 25 35 我需要找到给定数字所属的范围 并对 100k 个数字重复该
  • 双枢轴快速排序和快速排序有什么区别?

    我以前从未见过双枢轴快速排序 是快速排序的升级版吗 双枢轴快速排序和快速排序有什么区别 我在 Java 文档中找到了这个 排序算法是双枢轴快速排序 作者 弗拉基米尔 雅罗斯拉夫斯基 乔恩 本特利和约书亚 布洛赫 这个算法 在许多数据集上提供
  • Java中的对象池模式

    所以我实现了自己的对象池模式 它工作得很好并且符合预期 从列表中返回我的 老师 对象 并在没有对象时创建它们 我的问题 返回的对象 Teacher 然后需要被转换为它的专门子类之一 例如 生物老师 获得这种功能的最佳方法是什么 编辑 抱歉
  • 对 Java 中的对象数组进行排序

    我正在开发一个报告模块 显示花费的时间和任务数量 这些值在 Java Bean 中设置 bean 对象存储在数组中 我使用单独的查询来获取时间和任务数量 现在我必须根据时间和任务数量对数组进行排序 下面的代码仅比较字符串 if list i

随机推荐