用if else,switch,while,for顛覆你的編程認知

前言

該篇文章主要會涉及如下幾個問題:
1、if elseswitch case 在日常開發(fā)中該如何抉擇?兩者相比誰的效率會高些?
2、如何基于赫夫曼樹結(jié)構(gòu)減少 if else 分支判斷次數(shù)?
3、如何巧妙的應(yīng)用 do...while(0) 改善代碼結(jié)構(gòu)?
4、哨兵是什么東西?如何利用哨兵提高有序數(shù)組查找效率?
5、如何降低 for 循環(huán)嵌套的時間復(fù)雜度?
6、如何利用策略模式替換繁瑣的 if else 分支?

雖然該篇文章說來說去都是 if else、switch case、for、while幾個很簡單的關(guān)鍵字,但是確實都是一些比較實用的小技巧,希望對你實際工作有所幫助。

PS: 做了回標題黨,見諒????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????

一、if else 和 switch case 效率問題

switch caseif else 的根本區(qū)別在于: switch case 會生成一個跳轉(zhuǎn)表來指示實際的 case 分支的地址,而這個跳轉(zhuǎn)表的索引號與switch變量的值是相等的。從而,switch case 不用像 if else 那樣遍歷條件分支直到命中條件,而只需訪問對應(yīng)索引號的表項從而到達定位分支的目的。switch case 會生成一份大?。ū眄棓?shù))為最大 case 常量 +1 的跳表,程序首先判斷 switch 變量是否大于最大 case 常量,若大于,則跳到 default 分支處理;否則取得索引號為switch變量大小的跳表項的地址(即跳表的起始地址+表項大?。饕枺?,程序接著跳到此地址執(zhí)行,到此完成了分支的跳轉(zhuǎn)。

switch 的缺點主要有兩點: 1、 switch 有點以空間換時間的意思,因為它要生成跳表,特別是當case常量分布范圍很大但實際有效值又比較少的情況,switch case 的空間利用率將變得很低。2、if else 能應(yīng)用于更多的場合,switch case可能就做不來,如:if (a > 1) 。

除此, if else 的效率問題同簡單文件壓縮原理還有一定的關(guān)聯(lián),主要是涉及赫夫曼樹結(jié)構(gòu)知識,具體可以參照筆者之前寫的這篇文章。

二、用do while(0) 改善代碼結(jié)構(gòu)

先看一段代碼,要重點注意代碼中的注釋。

- (NSString *)handleString:(NSString *)str {
    if (![str isKindOfClass:[NSString class]]) {
        return nil;
    }
    if(str.length <= 0) {
        return nil;
    }
    // 第一部分邏輯依賴于前面的判斷,只有判斷通過的時候才執(zhí)行
    我是第一部分邏輯偽代碼
    // 第二部分邏輯不依賴于前面的判斷(第二部分中的邏輯可能會依賴第一部分邏輯處理結(jié)果),無論判斷是否通過都要執(zhí)行
    我是第二部分邏輯偽代碼
}

試問,怎樣做才能巧妙的滿足上述注釋代碼的需求,因為上述代碼中存在 return nil; 一旦執(zhí)行到此處,邏輯一和邏輯二處的偽代碼都不會再執(zhí)行。為了滿足上述要求,我們可以巧妙的利用 break 退出臨時構(gòu)造的代碼塊,但不退出整個函數(shù)。

- (NSString *)handleString:(NSString *)str {
    do {
        if (![str isKindOfClass:[NSString class]]) {
            break;
        }
        if(str.length <= 0) {
            break;
        }
        // 第一部分邏輯依賴于前面的判斷,只有判斷通過的時候才執(zhí)行
        我是第一部分邏輯偽代碼
    }while (0);    
    // 第二部分邏輯不依賴于前面的判斷(第二部分中的邏輯可能會依賴第一部分邏輯處理結(jié)果),無論判斷是否通過都要執(zhí)行
    我是第二部分邏輯偽代碼
}

三、有序數(shù)組查找操作中的哨兵

正常的查找處理。

    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循環(huán)相比,i < arr.count的判斷,在處理大批量數(shù)據(jù)時候,對性能提升比較大
    while ([arr[i] integerValue] != [key integerValue]) {//該句代碼和上面for循環(huán)中的if判斷等價======
        i--;//該句代碼和上面的i+等價======
    }
    arr[0] = firstObj;
    [lock unlock];
    if (i == 0) {
        return NO;
    }else{
        return YES;
    }
}

仔細觀察上述兩段代碼,同樣是在有序數(shù)組中查找目標為 2 的元素,第一段代碼是常規(guī)迭代處理,第二段代碼是將要查找的元素設(shè)置為哨兵。同第一段代碼相比第二種方式少了 i < arr.count 的判斷,在小批量有序數(shù)組查詢中對效率的提升并無明顯影響,但是在處理大批量數(shù)據(jù)時候,對性能提升還是比較明顯的。

四、多層 for 嵌套處理

實際開發(fā)中應(yīng)盡量避免使用雙層 for 循環(huán),客戶端數(shù)據(jù)量比較小可能實際開發(fā)中并不是很注意這些。但是后端開發(fā)過程中,數(shù)據(jù)量比較大, 為了提升性能,有些公司后端開發(fā)中可能會直接規(guī)定避免使用多層 for 循環(huán)嵌套的形式。一般第二層或更深層的 for 循環(huán)可以使用字典替換。雙層 for 循環(huán)嵌套的時間復(fù)雜度是 n 的二次方。但如果內(nèi)部 for 循環(huán)用字典代替時間復(fù)雜度為 O(2n)( 實際是 O(n))。如: 兩個數(shù)組中有且只有一個相同元素,尋找該元素。其中一個數(shù)組就可以先用字典做保存,遍歷第一個數(shù)組的時候, 同字典中的數(shù)據(jù)做比較即可。

    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(@"相同的數(shù)據(jù)為:%@",number);
            break;
        }   
    }

五、用策略模式替換 if else

筆者之前這篇文章的第四部分有詳細介紹到,這里不再做過多描述。

小結(jié)

文章很簡短,但是筆者自認為都是一些很實用的技巧??赡芤驗閕f else、switch、while、for 這幾個關(guān)鍵字過于簡單,許多開發(fā)者并不太注意,也不知道這些技巧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 53.計算字符 在字符串中獲取字符值的數(shù)量, 可以使用字符串字符屬性中的計數(shù)屬性: let unusualMena...
    無灃閱讀 1,257評論 0 4
  • 第2章 基本語法 2.1 概述 基本句法和變量 語句 JavaScript程序的執(zhí)行單位為行(line),也就是一...
    悟名先生閱讀 4,504評論 0 13
  • 86.復(fù)合 Cases 共享相同代碼塊的多個switch 分支 分支可以合并, 寫在分支后用逗號分開。如果任何模式...
    無灃閱讀 1,543評論 1 5
  • 只有手握著初生的嬰兒的小手,看見小羊羔柔軟的脊背,才能明白,死是怎么一回事,生又是怎么一回事。 只有看見那些美的,...
    曲彥融閱讀 642評論 5 2
  • 其實,我一直很懷疑《后來的我們》這部電影的意義所在,好像“情懷”售賣光了之后,便也沒有剩下什么了。 我只是覺得蒼白...
    青城而竭閱讀 355評論 0 0

友情鏈接更多精彩內(nèi)容