排序算法知識點

測試算法性能(準備工做)

  • 排序執行前NSDate * startDate = [NSDate date];,排序結束後return [[NSDate date] timeIntervalSinceDate:startDate];//返回排序算法運行時間
  • 判斷某個數組是不是一個有序數組
- (BOOL)testSort:(NSMutableArray* )array length:(NSInteger) len
{
    // 非嚴格升序
    int IsSortAscending = [array[0] integerValue] <= [array[len-1] integerValue] ? 1 : -1;
    int i;
    for (i = 1; i < len - 1; ++i)
    {
        if (IsSortAscending * ([array[i] integerValue] - [array[i+1] integerValue]) > 0)
            return NO;
    }
    
    return YES;
}
複製代碼
  • 生成一個亂序的隨機數據長度的數組
/**
 *
 *  @param startIndex 開始數字
 *  @param length     數字的長度
 *  @return 返回一個隨機的不重複的數組
 */
- (NSMutableArray*) GetRandomWithStartIndex:(NSInteger) startIndex andLength:(NSInteger) length
{
    NSInteger endIndex = startIndex+length;//結束數字
    NSMutableArray *arr = [NSMutableArray arrayWithCapacity:length];//返回的結果(隨機數數組)
    NSMutableArray *arr1 = [NSMutableArray arrayWithCapacity:length];//填充隨機數的數組
    for (NSInteger i = startIndex; i<endIndex; i++) {//填充隨機數的全部可能值
        [arr1 addObject:[NSString stringWithFormat:@"%ld",(long)i]];
    }
    for (NSInteger i=startIndex; i<endIndex; i++) {
        NSInteger index = arc4random()%arr1.count;//這個隨機數在當初初始化隨機數數組中的隨機位置
        NSInteger radom = [arr1[index] intValue];//隨機位置對應的隨機值
        NSNumber *num = [NSNumber numberWithInteger:radom];
        [arr addObject:num];
        [arr1 removeObjectAtIndex:index];//添加以後 就把基本的填充的數組的參數刪除這個
    }
    return arr;
}
複製代碼
  • 最後打印NSLog(@"sortUse = %f s-----------",(float)timeUse);排序時間,NSLog(@"isSort = %d -------------",isSort);是否有序。

選擇排序(O(n*n))

思想:
假設10個元素的數組,從小到大進行排序,首先在整個數組範圍內選擇出最小的數,和首位交換(首位已經排好序);以後再在首位之後剩下的元素中找最小的數,和尚未排序的第一個位置交換位置,以此類推。算法

-(float)selectionSort:(NSMutableArray *)arr andCount:(NSInteger)n{
    NSDate * startDate = [NSDate date];//計算代碼運行時間
    for (int i = 0; i < n; i ++) {
        //尋找 (i,n)裏的最小值
        int minIndex = i;
        for (int j = i+1 ; j < n ; j ++) {//選擇出i~n中最小的值的index
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }
        [arr exchangeObjectAtIndex:i withObjectAtIndex:minIndex];//最小值與i交換,而後繼續比較其餘沒有排序的數
    }
    return [[NSDate date] timeIntervalSinceDate:startDate];//返回排序算法運行時間
}
複製代碼

插入排序(O(n*n))

思想:
假設10個元素數組,第一個元素不動;第二個元素和第一個元素比較,如符合排序條件就插入到第一個元素前面;第三個元素和第二個元素比較,如符合排序條件就插入到第二個元素前面,第三個元素再和第一個元素比較,如符合排序條件就插入到第一個元素前面,不符合終止這次內層循環;以此類推。數組

- (float)insertionSort:(NSMutableArray *)arr andCount:(NSInteger)n{
    NSDate * startDate = [NSDate date];
    
    for (NSInteger i = 1; i < n; i ++ ) {//對於插入排序,第0個元素不用考慮
        //尋找元素arr[i]合適的插入位置
        for (NSInteger j = i; j > 0; j -- ) {//當前位置元素和前面位置元素比較,最多到j = 1;
            if (arr[j] < arr[j-1]) {
                [arr exchangeObjectAtIndex:j withObjectAtIndex:j-1];
            }else
                break;
        }
        
    }
    return [[NSDate date] timeIntervalSinceDate:startDate];
}
複製代碼

插入排序法的改進

插入排序能夠提早終止第二層循環,但有時效率仍是會慢於選擇排序。目前的插入排序的版本在遍歷的同時也在不停的交換,交換是比單純的遍歷仍是耗時的,每一次交換都有賦值和訪問索引時間。改進,讓每一次遍歷只執行一次交換。遍歷比較以後,不馬上進行交換,如知足排序要求,把當前的元素賦值一個副本,直接賦值過去到相應的位置。bash

//改進後的插入排序
- (float)insertionSort2:(NSMutableArray *)arr andCount:(NSInteger)n{
    NSDate * startDate = [NSDate date];

    for (NSInteger i = 1; i < n; i ++ ) {//對於插入排序,第0個元素不用考慮
        //尋找元素arr[i]合適的插入位置
        NSNumber * temp = arr[i];
        NSInteger j;
        for (j = i; j > 0; j -- ) {//當前位置元素和前面位置元素比較,最多到j = 1;
            if (temp < arr[j-1]) {
                arr[j] = arr[j-1];
            }else
                break;
        }
        arr[j] = temp;
    }
    
    return [[NSDate date] timeIntervalSinceDate:startDate];
}
複製代碼

冒泡排序

水中的氣泡越往上冒,氣泡就越大,因此用這個現象來描述冒泡排序。假設數組中有雜亂無序的數字:拿第一個數字和其餘全部數字進行比較,若比它大則交換位置,直到將這些數字中最大的數交換到最上面。針對除以前比較輪已經排好序的其餘全部元素重複以上的步驟。每一輪j都從0開始,當i輪排序,就有最後面的i個數字是排好的,因此後面的每輪都不用理他了,也就是arr.count-1-i。dom

- (float)bubbleSort:(NSMutableArray *)arr{
    NSDate * startDate = [NSDate date];//計算代碼運行時間
    NSInteger i = 0;
    NSInteger j = 0;
    NSNumber * temp;
    
    for (i = 0; i< arr.count-1; i++) {
        for ( j = 0;j<arr.count-1-i ; j++) {
            if (arr[j]<arr[j+1]) {
                temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
    return [[NSDate date] timeIntervalSinceDate:startDate];//返回排序算法運行時間
}
複製代碼

冒泡排序的優化

  • 第一種優化方式:
    設置一個標記位來標記內層循環是否發生了交換,若是沒有發生交換,說明已是有序的了,就提早結束循環。
/*
 * 冒泡排序優化一
 * 設置一個標記來標誌一趟比較是否發生交換
 * 若是沒有發生交換,則數組已經有序
 * */
- (float)bubbleSort2:(NSMutableArray *)arr{
    NSDate * startDate = [NSDate date];//計算代碼運行時間
    NSInteger i = 0;
    NSInteger j = 0;
    NSNumber * temp;
    int flag = 0;
    
    for (i = 0; i< arr.count-1; i++) {
        for ( j = 0;j<arr.count-1-i ; j++) {
            if (arr[j]<arr[j+1]) {
                flag = 1;
                temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
        if (flag == 0) {
            break;
        }
    }
    return [[NSDate date] timeIntervalSinceDate:startDate];//返回排序算法運行時間
}
複製代碼
  • 第二種優化方式:記錄最後發生交換的位置,做爲下一趟比較結束的位置。

快速排序

堆排序

堆排序的改進

奇偶排序

將數組中的元素排列爲奇數在前偶數在後。處理策略是定義front,end。並令其初始指向數組頭節點和尾節點。front從前日後找應該放在尾部的偶數節點,end從後往前找應該放在頭部的奇數節點,若front位於end以前則交換兩者內容,不然結束處理過程。性能

- (void)oddEvenSort:(NSMutableArray *)arr  andCount:(NSInteger)n{
    
    if (n<= 0) {
        return;
    }
    NSInteger front = 0;
    NSInteger end = n-1;
    while (front<end) {
        while (front<n && ([arr[front] integerValue]&1)==1) {// 從前日後找偶數
            front++;
        }
        while (end>0 && ([arr[end] integerValue]&1)==0) {//從後往前找奇數
            end--;
        }
        if (front<end) {
            NSNumber * num = arr[front];
            arr[front] = arr[end];
            arr[end] = num;
        }
    }
}
複製代碼
相關文章
相關標籤/搜索