用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 caseif 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 這幾個關鍵字過于簡單,許多開發者并不太注意,也不知道這些技巧。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,621評論 2 380

推薦閱讀更多精彩內容

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