欢迎关注
最酷最in的云资讯

用if else,switch,while,for颠覆你的编程认知

前言

该篇文章主要会涉及如下几个问题:

1、if elseswitch case 在日常开发中该如何抉择?两者相比谁的效率会高些?

2、如何基于赫夫曼树结构减少 if else 分支判断次数?

3、如何巧妙的应用 do…while(0) 改善代码结构?

4、哨兵是什么东西?如何利用哨兵提高有序数组查找效率?

5、如何降低 for 循环嵌套的时间复杂度?

6、如何利用策略模式替换繁琐的 if else 分支?

虽然该篇文章说来说去都是 if else、switch case、for、while几个很简单的关键字,但是确实都是一些比较实用的小技巧,希望对你实际工作有所帮助。

PS: 做了回标题党,见谅

一、if else 和 switch case 效率问题

switch case 与 if else 的根本区别在于: switch case 会生成一个跳转表来指示实际的 case 分支的地址,而这个跳转表的索引号与switch变量的值是相等的。从而,switch case 不用像 if else 那样遍历条件分支直到命中条件,而只需访问对应索引号的表项从而到达定位分支的目的。switch case 会生成一份大小(表项数)为最大 case 常量 +1 的跳表,程序首先判断 switch 变量是否大于最大 case 常量,若大于,则跳到 default 分支处理;否则取得索引号为switch变量大小的跳表项的地址(即跳表的起始地址+表项大小*索引号),程序接着跳到此地址执行,到此完成了分支的跳转。

switch 的缺点主要有两点: 1、 switch 有点以空间换时间的意思,因为它要生成跳表,特别是当case常量分布范围很大但实际有效值又比较少的情况,switch case 的空间利用率将变得很低。2、if else 能应用于更多的场合,switch case可能就做不来,如:if (a > 1) 。

除此, if else 的效率问题同简单文件压缩原理还有一定的关联,主要是涉及赫夫曼树结构知识,具体可以参照笔者之前写的这篇文章。

二、用do while(0) 改善代码结构

先看一段代码,要重点注意代码中的注释。

- (NSString *)handleString:(NSString *)str {    if (![str isKindOfClass:[NSString class]]) {        return nil;    }    if(str.length <= 0) {        return nil;    }    // 第一部分逻辑依赖于前面的判断,只有判断通过的时候才执行    我是第一部分逻辑伪代码    // 第二部分逻辑不依赖于前面的判断(第二部分中的逻辑可能会依赖第一部分逻辑处理结果),无论判断是否通过都要执行    我是第二部分逻辑伪代码}

试问,怎样做才能巧妙的满足上述注释代码的需求,因为上述代码中存在 return nil; 一旦执行到此处,逻辑一和逻辑二处的伪代码都不会再执行。为了满足上述要求,我们可以巧妙的利用 break 退出临时构造的代码块,但不退出整个函数。

- (NSString *)handleString:(NSString *)str {    do {        if (![str isKindOfClass:[NSString class]]) {            break;        }        if(str.length <= 0) {            break;        }        // 第一部分逻辑依赖于前面的判断,只有判断通过的时候才执行        我是第一部分逻辑伪代码    }while (0);        // 第二部分逻辑不依赖于前面的判断(第二部分中的逻辑可能会依赖第一部分逻辑处理结果),无论判断是否通过都要执行    我是第二部分逻辑伪代码}

三、有序数组查找操作中的哨兵

正常的查找处理。

    NSArray *arr = @[@1,@2,@3,@4,@5];    for (NSInteger i = 0; i < arr.count; i++) {        if ([arr[i] integerValue] == 2) {            NSLog(@"for 找到了");        }    }

利用哨兵进行查找处理。

- (BOOL)search:(NSNumber *)key array:(NSMutableArray *)arr{    if (arr.count <= 0) {        return NO;    }    NSInteger i = arr.count - 1;    NSNumber *firstObj = (NSNumber *)arr[0];    if ([firstObj integerValue] == [key integerValue]) {        return 0;    }    NSLock * lock = [[NSLock alloc]init];    [lock lock];    arr[0] = key;    //同上面for循环相比,i < arr.count的判断,在处理大批量数据时候,对性能提升比较大    while ([arr[i] integerValue] != [key integerValue]) {//该句代码和上面for循环中的if判断等价======        i--;//该句代码和上面的i+等价======    }    arr[0] = firstObj;    [lock unlock];    if (i == 0) {        return NO;    }else{        return YES;    }}

仔细观察上述两段代码,同样是在有序数组中查找目标为 2 的元素,第一段代码是常规迭代处理,第二段代码是将要查找的元素设置为哨兵。同第一段代码相比第二种方式少了 i < arr.count 的判断,在小批量有序数组查询中对效率的提升并无明显影响,但是在处理大批量数据时候,对性能提升还是比较明显的。

四、多层 for 嵌套处理

实际开发中应尽量避免使用双层 for 循环,客户端数据量比较小可能实际开发中并不是很注意这些。但是后端开发过程中,数据量比较大, 为了提升性能,有些公司后端开发中可能会直接规定避免使用多层 for 循环嵌套的形式。一般第二层或更深层的 for 循环可以使用字典替换。双层 for 循环嵌套的时间复杂度是 n 的二次方。但如果内部 for 循环用字典代替时间复杂度为 O(2n)( 实际是 O(n))。如: 两个数组中有且只有一个相同元素,寻找该元素。其中一个数组就可以先用字典做保存,遍历第一个数组的时候, 同字典中的数据做比较即可。

    NSArray *arr1 = @[@1,@2,@3,@4,@5];    NSArray *arr2 =@[@5,@6,@7,@8];    NSMutableDictionary *dict = [NSMutableDictionary dictionary];    for (NSInteger i = 0; i < arr2.count; i++) {        [dict setObject:arr2[i] forKey:[NSString stringWithFormat:@"%ld",i]];    }        for (NSInteger i= 0 ; i < arr1.count; i++) {        NSNumber *number = [dict objectForKey:[NSString stringWithFormat:@"%ld",i]];        if ([arr1[i] integerValue] == [number integerValue]) {            NSLog(@"相同的数据为:%@",number);            break;        }       }

五、用策略模式替换 if else

笔者之前这篇文章的第四部分有详细介绍到,这里不再做过多描述。

小结

文章很简短,但是笔者自认为都是一些很实用的技巧。可能因为if else、switch、while、for 这几个关键字过于简单,许多开发者并不太注意,也不知道这些技巧。

作者:ZhengYaWei

链接:https://www.swifty.cc/p/ceed2daebc47

赞(0) 打赏
未经允许不得转载:云微资讯 » 用if else,switch,while,for颠覆你的编程认知
分享到: 更多 (0)

云微资讯 科技新媒体资讯平台

关于我们联系我们

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏