36

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

 5 years ago
source link: http://www.cocoachina.com/ios/20190213/26320.html?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

前言

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

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.jianshu.com/p/ceed2daebc47


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK