iOS備忘:常用排序算法還記得多少...

排序方法 時間復雜度 時間復雜度 時間復雜度 空間復雜度 穩定性
平均情況 最好情況 最壞情況 輔助存儲
冒泡排序 O(n2) O(n) O(n2) O(1) 穩定
選擇排序 O(n2) O(n2) O(n2) O(1) 不穩定
快速排序 O(nlogn) O(nlogn) 有序或逆序 O(n2) O(nlogn) 不穩定
直接插入排序 O(n2) O(n) O(n2) O(1) 穩定
折半插入排序 O(n2) O(nlogn) O(n2) O(1) 不穩定
堆排序 O(nlogn) O(nlogn) O(nlogn) O(1) 不穩定

冒泡排序

算法思想

通過與相鄰元素的比較和交換,把小的數交換到最前面。

- (void)sort:(NSMutableArray *)arr {
    //外層循環控制數組大小
    for (int i = 0; i < arr.count; ++i) {
        //內循環從后往前依次比較將小的數據放到最前面
        for (int j = 0; j < arr.count-1-i; ++j) {
            //大元素后移
            if ([arr[j] integerValue]> [arr[j+1] integerValue]) {
                [arr exchangeObjectAtIndex:j withObjectAtIndex:j+1];
            }
        }
    }
    NSLog(@"冒泡排序結果:%@", arr);
}

選擇排序

算法思想

每一趟從前往后查找出值最小的索引(下標),最后通過比較是否需要交換。每一趟都將最小的元素交換到最前面。

- (void)sort:(NSMutableArray *)arr {    
    for (int i = 0; i < arr.count; i++) {
        for (int j = i+1; j < arr.count; j++) {
            // 每一趟將最小的元素放到最前
            if ([arr[j] integerValue] < [arr[i] integerValue]) {
                [arr exchangeObjectAtIndex:i withObjectAtIndex:j];
            }
        }
    }
    NSLog(@"選擇排序結果:%@", arr);
}

注意:冒泡排序是從后往前掃,使大的往下沉,而小的往上浮;選擇排序是從前往后掃,每趟找出值最小的索引,使每趟最小值都交換到該趟的最前面,從而得到升序序列。

快速排序

算法思想

每一趟都保證左邊比基準小,右邊比基準大,而且遞歸劃分排序。

  1. 設置兩個變量left、right,排序開始的時候:left=0,right=N-1;
  2. 以第一個數組元素作為基準數據,賦值給key,即key=A[0];
  3. 從right開始向前搜索,即由后開始向前搜索(right--),找到第一個小于key的值A[right],將A[right]和A[left]互換;
  4. 從left開始向后搜索,即由前開始向后搜索(left++),找到第一個大于key的A[left],將A[left]和A[right]互換;
  5. 重復第3、4步,直到left=right;
  • 沒找到符合條件的值,即3中A[right]不小于key,4中A[left]不大于key的時候改變right、left的值,使得right=right-1,left=left+1,直至找到為止。
  • 找到符合條件的值,進行交換的時候left、right指針位置不變。
  • 另外,left==right這一過程一定正好是left++或right--完成的時候,此時令循環結束
- (void)quickSort:(NSMutableArray *)arr leftIndex:(int)left rightIndex:(int)right {
    if (left < right) {
        int temp = [self getMiddleIndex:arr leftIndex:left rightIndex:right];
        [self quickSort:arr leftIndex:left rightIndex:temp - 1];
        [self quickSort:arr leftIndex:temp + 1 rightIndex:right];
    }
}
- (int)getMiddleIndex:(NSMutableArray *)arr leftIndex:(int)left rightIndex:(int)right {
    int tempValue = [arr[left] integerValue];
    while (left < right) {
        while (left < right && tempValue <= [arr[right] integerValue]) {
            right --;
        }
        if (left < right) {
            arr[left] = arr[right];
        }
        while (left < right && [arr[left] integerValue] <= tempValue) {
            left ++;
        }
        if (left < right) {
            arr[right] = arr[left];
        }
    }
    arr[left] = [NSNumber numberWithInt:tempValue];
    return left;
}

插入排序

直接插入排序

算法思想

第一次從R[0]R[n-1]中選取最小值,與R[0]交換,第二次從R[1]R[n-1]中選取最小值,與R[1]交換,....,第i次從R[i-1]R[n-1]中選取最小值,與R[i-1]交換,.....,第n-1次從R[n-2]R[n-1]中選取最小值,與R[n-2]交換,總共通過n-1次,得到一個按排序碼從小到大排列的有序序列.

第一個元素就認為是有序的
取第二個元素,判斷是否大于第一個元素。若是大于,表示已經有序,不用移動,否則將已經有序的序列整體向后移動一個位置
依此類推,直到所有元素已經有序。

- (void)sort:(NSMutableArray *)arr {
    // 外層循環用于跑多少趟
    for (int i = 1; i < arr.count; i ++) {
        int temp = [arr[i] integerValue];
        // 內層循環用于移動元素位置
        for (int j = i - 1; j >= 0 && temp < [arr[j] integerValue]; j --) {
            arr[j + 1] = arr[j];
            arr[j] = [NSNumber numberWithInt:temp];
        }
    }
    NSLog(@"插入排序結果:%@",arr);
}

折半插入排序

折半插入排序利用了二分查找的優點:查找到元素的位置速度更快。

算法思想

從第二個元素開始逐個置入監視哨,使用low、high標簽進行折半判斷比較大小,并確認插入位置,該位置到最后一個數全部后移一位,然后騰出該位置,把監視哨里面的數置入該位置。依此類推進行排序,直到最后一個數比較完畢。

- (void)binaryInsertSort:(NSMutableArray *)arr{
    //索引從1開始 默認讓出第一元素為默認有序表 從第二個元素開始比較
    for(int i = 1 ; i < [list count] ; i++){
        //binary search start
        NSInteger temp= [arr[i] intValue];
        int left = 0; 
        int right = i - 1;
        while (left <= right) {
            int middle = (left + right)/2;
            if(temp < [arr[middle] intValue]){   
                right = middle - 1;    
            }else{     
                left = middle + 1;
            }  
        }
        //binary search end
        for(int j = i ; j > left; j--){
            [arr replaceObjectAtIndex:j withObject:arr[j-1]]; 
        }
        [arr replaceObjectAtIndex:left withObject:[NSNumber numberWithInt:temp]];
    }  
}

堆排序

堆是指二叉堆,二叉堆又稱完全二叉樹或者叫近似完全二叉樹。二叉堆又分為最大堆和最小堆。

最大堆的特性如下:

父結點的鍵值總是大于或者等于任何一個子節點的鍵值
每個結點的左子樹和右子樹都是一個最大堆

最小堆的特性如下:

父結點的鍵值總是小于或者等于任何一個子節點的鍵值
每個結點的左子樹和右子樹都是一個最小堆

最大堆的算法思想是:

先將初始的R[0…n-1]建立成最大堆,此時是無序堆,而堆頂是最大元素
再將堆頂R[0]和無序區的最后一個記錄R[n-1]交換,由此得到新的無序區R[0…n-2]和有序區R[n-1],且滿足R[0…n-2].keys ≤ R[n-1].key
由于交換后,前R[0…n-2]可能不滿足最大堆的性質,因此再調整前R[0…n-2]為最大堆,直到只有R[0]最后一個元素才調整完成。

最大堆排序完成后,其實是升序序列,每次調整堆都是要得到最大的一個元素,然后與當前堆的最后一個元素交換,因此最后所得到的序列是升序序列。

最小堆的算法思想是:

先將初始的R[0…n-1]建立成最小堆,此時是無序堆,而堆頂元素是最小的元素
再將堆頂R[0]與無序區的最后一個R[n-1]交換,由此得到新的無序堆R[0…n-2]和有序堆R[n-1],且滿足R[0…n-2].keys >= R[n-1].key
由于交換后,前R[0…n-2]可能不滿足最小堆的性質,因此再調整前R[0…n-2]為最小堆,直到只有R[0]最后一個元素才調整完成

最小堆排序完成后,其實是降序序列,每次調整堆都是要得到最小的一個元素,然后與當前無序堆的最后一個元素交換,所以所得到的序列是降序的。

- (void)heapSortwithOrder:(BOOL)isAsc {
    for (NSInteger i = arr.count/2 - 1; i>=0; --i) {
        [self siftWithLow:i high:arr.count asc:isAsc];
    }
    for (NSInteger i = arr.count - 1; i>=1; --i) {
        id temp = arr[0];
        arr[0] = arr[i];
        arr[i] = temp;
        [self siftWithLow:0 high:i asc:isAsc];
     }
 }
- (void)siftWithLow:(NSInteger)low high:(NSInteger)high asc:(BOOL)isAsc {
    NSInteger left = 2 * low + 1;
    NSInteger right = left + 1;
    NSInteger lastIndex = low;
    //左子節點大的情況 
    if (right < high && ((arr[right] > arr[lastIndex] && isAsc) || (arr[right] < arr[lastIndex] && !isAsc))) {
        lastIndex = left;
    }
    //右子節點大的情況
    if (right < high && ((arr[right] > arr[lastIndex] && isAsc) || (arr[right] < arr[lastIndex] && !isAsc))) {
        lastIndex = right;
    }
    //節點改變
    if (lastIndex != low) {
        //較大的節點值將交換到其所在節點的父節點
        id temp = arr[low];
        arr[low] = arr[lastIndex];
        arr[lastIndex] = temp;
        //遞歸遍歷
        [self siftWithLow:lastIndex high:high asc:isAsc];
    }
}

參考

排序算法(OC實現)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 概述 排序有內部排序和外部排序,內部排序是數據記錄在內存中進行排序,而外部排序是因排序的數據很大,一次不能容納全部...
    蟻前閱讀 5,220評論 0 52
  • 概述:排序有內部排序和外部排序,內部排序是數據記錄在內存中進行排序,而外部排序是因排序的數據很大,一次不能容納全部...
    每天刷兩次牙閱讀 3,743評論 0 15
  • 距離第一次讀完小強升職記已經快一個月了,最近帶著“悅讀群”的13個問題,重新閱讀小強升職記,如果說第一遍是檢視閱讀...
    yiling在路上閱讀 348評論 0 3
  • 古代君王,整個天下都歸自己所有,呼風喚雨,無所不能。今兒個看著人不爽,殺嘍,明兒個瞧那人不順,斬啦。雖然這...
    儲能閱讀 331評論 0 3
  • 今日感恩: 1.感恩一早出門剛到車站就有車,我緊走二步上了車,沒等待沒耽擱。感恩轉乘車時同樣的情形再次出現,剛下車...
    露穎_閱讀 101評論 0 1