做爲一名前線的碼農不時地看一下算法和數據結構仍是頗有必要的,雖然《算法導論》這本書很難啃,但仍是有必要啃一下的。算法這東西和某種編程語言關係不大,在大學的課堂上書上通常是用僞代碼來描述算法的,而用C語言去實現。算法更多的是一種思想,一種解決問題的方法,多看看算法仍是頗有必要的,它能夠開闊的你的思路,讓你在編程時思惟更爲活躍。算法
固然了,本人在算法方面水平有限,這不正在努力的學習不是,接下來就按算法導論上描述的插入排序和歸併排序使用Objective-C語言實現一下,固然用什麼語言是次要的,關鍵是理解算法纔是關鍵。編程
1、建立咱們的測試工程數組
由於咱們只理解相應算法,沒有什麼用戶圖形,也就用不到UI了,在這兒使用Xcode建立一個基於Mac開發的控制檯工程便可,整個工程很簡單,一個main函數一個排序類,以下所示。數據結構
在Sort類中咱們寫了關於排序的一些類方法,而後在main函數中進行調用。app
2、插入排序dom
插入排序顧名思義,就是把無序的元素插入到有序的元素當中。《算法導論》中舉了一個特爲形象的例子,插入排序就如同你在打撲克時摸牌同樣,手裏的牌是有序的,而你剛摸得牌是是隨機的,須要你插入到已經排好序的撲克牌中,這就是插入排序。編程語言
若是用代碼實現的話就是每通過一輪插入排序後,前面有序的元素就會加一,然後面無序的元素就會減一。下面根據Demo的實例來講明一下插入排序的思路和具體實現方式。函數
1.由於在OC中的可變數組是引用類型,因此在函數中改變後不須要返回。學習
2.由於數組中只有一個數據的時候它就是有序的,因此前面有序數列的初始有一個數據,也就是原始數組中的第一個數據。咱們從下標爲1開始遍歷每一個無序的元素,往前面有序的元素中相應的位置插入該元素,但插入後必須保證有序數組依然是有序的。測試
3.咱們須要把即將插入到有序序列的數據進行暫存,由於有序序列中大於當前要插入數據的元素須要後移,爲元素插入作準備。有序元素的移動會覆蓋的要插入的元素,因此必須得暫存。
4.遍歷有序序列,找到合適的插入位置,進行元素的插入。
1 +(void) insertionSortWithArray: (NSMutableArray *) array{ 2 3 //從第二個數開始往前面的數據中進行插入,每通過一輪外面的循環,前面就插入一個從後面取出的值, 4 //所以沒通過一輪外層循環,有序序列的長度就增長一 5 for (int i = 1; i < array.count; i ++) { 6 7 //暫存將要插入到前方的數據 8 NSNumber *key = array[i]; 9 10 //獲取有序序列最後一個元素的下標 11 int j = i - 1; 12 13 //循環遍歷有序序列,尋找合適的數據插入位置,在此過程當中,爲數據的插入騰出位置,也就是把 14 //比將要暫存的數據大的元素向後移動 15 while (j >= 0 && array[j] > key) { 16 17 array[j+1] = array[j]; 18 19 j--; 20 } 21 22 //插入數據 23 array[j+1] = key; 24 25 NSLog(@"第%d輪插入排序結果以下:", i); 26 [self displayArrayWithArray:array]; 27 28 } 29 }
displayArrayWithArray是事先寫好的輸出數組中數據的方法,代碼以下,該方法是把數組元素拼接成字符串,而後進行輸出。
1 +(void) displayArrayWithArray: (NSMutableArray *)array{ 2 3 NSMutableString *strTemp = [NSMutableString string]; 4 for (int i = 0; i < array.count; i++) { 5 [strTemp appendFormat:@"%@, ", array[i]]; 6 } 7 NSLog(@"%@\n\n", strTemp); 8 }
接下來,讓咱們在main函數中使用隨機數產生一個隨機的數組,而後進行測試,以下:
1 //生成測試隨機數組 2 NSMutableArray *array = [[NSMutableArray alloc] init]; 3 UInt count = 10; 4 for (int i = 0; i < count; i ++) { 5 NSNumber *temp = @(arc4random()%100); 6 [array addObject:temp]; 7 }
進入測試階段,調用displayArrayWithArray方法,打印隨機生成的原始數組,而後調用插入排序,以下所示:
1 NSLog(@"原始數組以下:"); 2 [Sort displayArrayWithArray:array]; 3 4 //插入排序 5 [Sort insertionSortWithArray:array];
輸入結果以下,排序方式以下,一目瞭然,第一輪是前面兩個有序,第二輪是前面3個有序,以此類推,該算法的複雜度是O(n2)的
3、歸併算法
歸併算法之因此有歸併是由於把原來的問題分解成更小的子問題,而後子問題解決要比原問題更爲簡單一些,把子問題的解進行有效的合併,而後獲得整個問題的解。這就是分而治之的思想。
接下來將要具體的實現歸併排序算法。
1.首先實現歸併部分的代碼,進行歸併的數組是已經排好序了的,下面是把數組進行合併的代碼,以下:
1 //一次歸併 2 +(void) mergeWithArray: (NSMutableArray *)array 3 WithStarIndex: (NSInteger) starIndex 4 WithMidIndex: (NSInteger) midIndex 5 WithEndIndex: (NSInteger) endIndex 6 { 7 //記錄歸併次數 8 static int sort_count = 0; 9 10 if (endIndex < starIndex) { 11 return; 12 } 13 14 //前半部分元素個數 15 NSInteger frontCount = midIndex - starIndex + 1; 16 17 //後半部分元素的個數 18 NSInteger rearCount = endIndex - midIndex; 19 20 //把數組拆分紅兩部分進行歸併 21 22 //取出前半部分 23 NSMutableArray *frontArray = [[NSMutableArray alloc] initWithCapacity:frontCount]; 24 for (NSInteger i = 0; i < frontCount; i ++) { 25 [frontArray addObject:array[starIndex + i]]; 26 } 27 28 //取出後半部分 29 NSMutableArray *rearArray = [[NSMutableArray alloc] initWithCapacity:rearCount]; 30 for (NSInteger i = 0; i < rearCount; i ++) { 31 [rearArray addObject:array[midIndex + i + 1]]; 32 } 33 34 35 //進行比較歸併 36 37 NSInteger fi = 0; 38 NSInteger ri = 0; 39 NSInteger oi = starIndex; 40 41 //當兩個子數組中都有元素時才進行合併 42 while (fi < frontArray.count && ri < rearArray.count) { 43 44 if(frontArray[fi] <= rearArray[ri]){ 45 46 array[oi++] = frontArray[fi++]; 47 continue; 48 } 49 50 array[oi++] = rearArray[ri++]; 51 } 52 53 //前面元素中通過合併後仍然有元素,把剩餘的元素進行添加 54 while (fi < frontArray.count) { 55 56 array[oi++] = frontArray[fi++]; 57 58 } 59 60 //後邊元素通過合併後仍然有元素,把剩餘元素進行添加 61 while (ri < rearArray.count) { 62 63 array[oi++] = rearArray[ri++]; 64 65 } 66 67 NSLog(@"第%d合併結果以下:", ++ sort_count); 68 [self displayArrayWithArray:array]; 69 }
上面的代碼只是進行問題解的合併,下方是對問題進行拆分,分解成規模比較小的子問題,遞歸分解代碼以下,在這就很少說了,下面代碼中已經給出了註釋。
1 #pragma mark -- 本方法是把問題進行遞歸分割,使其成爲多個類似的子問題,而後在把子問題進行合 2 +(void) mergeSortWithArray: (NSMutableArray *)array 3 WithStarIndex: (NSInteger) starIndex 4 WithEndIndex: (NSInteger) endIndex 5 { 6 //遞歸結束條件 7 if (starIndex >= endIndex) { 8 return; 9 } 10 11 //找出中點進行分解 12 NSInteger midIndex = (starIndex + endIndex)/2; 13 14 //遞歸分解前半部分 15 [self mergeSortWithArray:array WithStarIndex:starIndex WithEndIndex:midIndex]; 16 17 //遞歸分解後半部分 18 [self mergeSortWithArray:array WithStarIndex:midIndex + 1 WithEndIndex:endIndex]; 19 20 //通過上面的遞歸分解後,最小的子數組裏只有一個元素,也就是有序的了,而後從底層進行遞歸合併 21 [self mergeWithArray:array WithStarIndex:starIndex WithMidIndex:midIndex WithEndIndex:endIndex]; 22 23 }
調用歸併排序代碼以下:
1 //歸併排序 2 [Sort mergeSortWithArray:array WithStarIndex:0 WithEndIndex:array.count-1];
運行結果以下,仔細觀察每次歸併後的結果,你會找到規律的哦。
今天的博客就先到這吧,編程是少不了算法的呀,繼續努力學習中。