算法的时间复杂度推导方法

算法的时间复杂度推导方法

独立博客地址:chugang.net

语句频度

语句频度是指语句的重复执行次数。

推导大O阶方法

方法
  1. 用常数1取代运行时间中的所有加法常数。
  2. 在修改后的运行次数函数中,只保留最高阶项。
  3. 如果最高阶项存在且不是1,则去除与这个项相乘的乘数。
常数阶举例运用

右侧注释中的 num 表示语句执行的次数。

int sum = 0, n = 100;       /* num = 1 */
sum = (n+1) * n / 2;        /* num = 1 */
printf("%d", sum);          /* num = 1 */

这段代码的运行次数函数是 f(n) = 1 + 1 + 1 ,根据“推导大O阶方法”中的第一条规则,把
1 + 1 + 11 替换,运行次数函数变成了 f(n) = 1。该函数只有常数项,只需使用规
则1就可以推导出它即这段代码的时间复杂度是 O(1)

假如 sum = (n+1) * n / 2 执行3次,将上面的代码修改为:

int sum = 0, n = 100;       /* num = 1 */
sum = (n+1) * n / 2;        /* num = 1 */
sum = (n+1) * n / 2;        /* num = 1 */
sum = (n+1) * n / 2;        /* num = 1 */
printf("%d", sum);          /* num = 1 */

这段代码的运行次数函数是 f(n) = 1 + 1 + 1 + 1 + 1 。 按照推导大O阶第一条规则,用1取代
所有的加法常数,这段代码的运行次数函数是 f(n) = 1。这段代码的时间复杂度依然是 f(n) = O(1)

所有这类代码的时间复杂度都是 O(1)O(1)叫做常数阶。不存在 O(2)O(9) 这类写法。

线性阶举例运用

code-3

int i;
for(i = 0; i < n; i++){
    // 时间复杂度为O(1)的代码
}

code-3的运行次数函数是 f(n) = n * 1。加法常数为0个,跳过规则一。变量n的最高阶是 n * 1,无
其他项,跳过规则二。n * 1中的系数本来就是1,也可以直接跳过规则三,得到code-3的时间复杂度是
f(n) = O(n)

code-4

int i;
for(i = 0; i < n; i++){
    // 时间复杂度为O(1)的代码
}

int j;
for(j = 0; j < m; j++){
    // 时间复杂度为O(1)的代码
}

code-4的运行次数函数是f(n) = n * 1 + m * 1。直接跳过规则一。n * 1 + m * 1有两个变量,
但次数都是1,任何一项 n * 1m * 1 都可视为最高价,根据推导规则二“保留最高阶”,得出
运行次数函数是f(n) = n * 1f(n) = m * 1。最后根据规则三,得出code-4的时间复杂度是
f(n) = O(n)

对数阶举例运用

code-5

int count = 1;
while(count < n){
    count = count * 2;
    //其他时间复杂度为O(1)的代码 
}

code-5似乎不能用前面的推导大O阶方法来分析时间复杂度,我从《数据结构与算法分析》P21找到了分析
"运行时间中的对数"的一般法则。这个一般法则是:

如果一个算法用常数时间(O(1)将问题的大小削减为其一部分(通常是1/2),那么该算法就是 O(log N)
另一方面,如果使用常数时间只是把问题减少一个常数(如将问题减少1),那么这种算法就是 O(N)

code-5中,假设 n = 8 ,初始化时,while(count < n) 需要运行8次。经过一次循环后,count变为2,
循环需要运行4次,变为原来的一半。根据那条一般法则,判断 code-5 的时间复杂度是 O(log N)

code-5修改为code-6

int count = 1;
while(count < n){
    count = count + 2;
    //其他时间复杂度为O(1)的代码 
}

code-6每次执行循环后,会把问题减少2个常数,时间复杂度应为 O(N)

若将code-6中的count = count + 2改为code = count - 2,时间复杂度仍然是 O(N)。但我有点理解不了。

平方价举例运用

code-7

int i, j;   /*1*/
for(i = 0; i < n; i++){ /*2*/
    for(j = 0; j < n; j++){ /*3*/
        //时间复杂度为O(1)的代码 /*4*/
    }   /*5*/
}   /*6*/

code-7中第二个循环体的时间复杂度是O(N)。第一个循环体将第二个循环体再执行N次,时间复杂度变为O(N2)
如果将第二个循环体中的n改为m,那么code-7的时间复杂度就是O(N*M)。注意,O(N*M)O(N2)都叫做
平方阶,二者实质相同。

多层循环体的时间复杂度就是每层循环体的运行次数相乘。

code-8

int i, j;
for(i = 0; i < n; i++){
    for(j = i; j < n; j++){
        //时间复杂度为O(1)的代码
    }
}

code-8运行次数是(n+1)*n*n/2。只保留最高阶并且去掉它的系数,时间复杂度是O(N2)。有些地方理解不了。

code-9

void function(int count){

    int j;
    
    for(j = count; j < n; j++){
    
        printf("%s", "hello,world");
        
    }
}

n++;        /* num = 1 */

function(n);    /* num = n */

int i,j;    /* num = 1 */

for(i = 0; i < n; i++){     /* num = n*n */
    
    function(i);
    
}

for(i = 0; i < n; i++){         /* num = (n+1)*n/2 */
    
    for(j = i; j < n; j++){
        
        printf("%s", "hi");
        
    }
}

code-9的时间复杂度是多少呢?

首先将每行代码的执行次数标出来。

code-9的执行次数(首先忽略掉常数项)是n + n*n + (n+1)*n/2,计算结果为1.5*n*n + 2*n
只保留最高阶1.5*n*n,最后将系数变为1,执行次数为n*n,时间复杂度为O(N2)

这种方法有不确定性的因素存在,或者说,在计算执行次数的时候,使用了互相矛盾的方法。

独立博客地址:chugang.net

重新思考之后,发现并不存在矛盾,而是《大话数据结构》中推导时间复杂度的方法有小缺陷。这个推导
本身就是一种粗略估计,为何在推导过程中有时又在进行精确计算呢?以code-8为例,该书使用了精确
的计算方法。若全部都坚持使用粗略估计计算,那么计算过程是这样的:code-8中第二个循环体的运行
次数是N,或者抽象为“一个变量”,第一个循环体的运行次数也是N或M,也抽象为“一个变量”,整体的运行
次数为两个变量相乘,即时间复杂度为O(N2)。这种粗略估计计算方法,建立的基础是:影响循环执行次数
的变量只有那个与循环终止条件相关的变量,与起始变量无关。

这种方法,又不能适用于对数阶的时间复杂度推导。或许,对数阶中的循环,本来就是一种特殊情况,不能
采用普通循环的推导方法。此处存疑。*

常见的时间复杂度

直接摘抄《大话数据结构》中的有关部分。

常见的时间复杂度
常见的时间复杂度

理解不了这些时间复杂度所耗时间的顺序,应该如何比较它们所耗时间?

独立博客地址:chugang.net

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,204评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,091评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,548评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,657评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,689评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,554评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,302评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,216评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,661评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,851评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,977评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,697评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,306评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,898评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,019评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,138评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,927评论 2 355

推荐阅读更多精彩内容