Swift實(shí)現(xiàn)七大排序算法

一揖闸、排序概念

  • 排序:對(duì)一序列對(duì)象根據(jù)某個(gè)關(guān)鍵字進(jìn)行排序矿卑。

  • 穩(wěn)定:如果 a 原本在 b 前面,而 a 與 b 的值相等审残,排序之后 a 仍然在 b 的前面;
    不穩(wěn)定:如果 a 原本在 b 的前面斑举,而 a 與 b 的值相等搅轿,排序之后 a 可能會(huì)出現(xiàn)在b的后面;

  • 內(nèi)排序:所有排序操作都在內(nèi)存中完成富玷;
    外排序:由于數(shù)據(jù)太大璧坟,因此把數(shù)據(jù)放在磁盤中既穆,而排序通過磁盤和內(nèi)存的數(shù)據(jù)傳輸才能進(jìn)行;

  • 排序耗時(shí)的操作:比較雀鹃、移動(dòng)幻工;

  • 排序分類:

    • 交換類:冒泡排序快速排序黎茎;此類的特點(diǎn)是通過不斷的比較交換進(jìn)行排序囊颅;
    • 插入類:簡(jiǎn)單插入排序希爾排序傅瞻;此類的特點(diǎn)是通過插入的手段進(jìn)行排序踢代;
    • 選擇類:簡(jiǎn)單選擇排序堆排序俭正;此類的特點(diǎn)是看準(zhǔn)了再移動(dòng)奸鬓;
    • 歸并類:歸并排序;此類的特點(diǎn)是先分割后合并掸读;
  • 歷史進(jìn)程:一開始排序算法的復(fù)雜度都是在O(n^2)串远,希爾排序的出現(xiàn)打破了這個(gè)僵局。

二儿惫、排序算法

最簡(jiǎn)單的排序算法

最簡(jiǎn)單的排序?qū)崿F(xiàn)澡罚,缺點(diǎn)是每次找最小值都是單純的找,而沒有為下一次尋找做出鋪墊肾请;

C 代碼

//最簡(jiǎn)單的排序, arr表示數(shù)組首地址留搔,count表示數(shù)組的元素個(gè)數(shù)
void simpleSort(int *arr, int count)
{
    for (int i = 0; i < count; i++) {
        for (int j = i+1; j < count; j++) {
            if (arr[i] > arr[j]) {
                swap(arr+i, arr+j);
            }
        }
    }
}

Swift 代碼

func simpleSort(_ arr: [Int]) -> [Int] {
    var sortArr = arr;
    
    for i in 0..<sortArr.count {
        for j in (i+1)..<sortArr.count {
            if sortArr[i] > sortArr[j] {
                swap(&sortArr[i], &sortArr[j]);
            }
        }
    }
    return sortArr;
}
1. 冒泡排序
  • 冒泡排序相對(duì)于最簡(jiǎn)單的排序有了改進(jìn),即每次交換都是對(duì)后續(xù)有幫助的铛铁,大數(shù)將會(huì)越來越大隔显,小的數(shù)將會(huì)越來越小饵逐;
  • 思想:兩兩相鄰元素之間的比較括眠,如果前者大于后者,則交換倍权;

C 代碼

//arr表示數(shù)組的首地址掷豺,count表示數(shù)組元素的個(gè)數(shù)
void bubbleSort(int *arr, int count)
{
    for (int i = 0; i < count; i++) {
        for (int j = 0; j < count - i - 1; j++) {
            if (arr[j] > arr[j+1]) {
                swap(arr+j, arr+j+1);
            }
        }
    }
}

Swift 代碼

func bubbleSort(_ arr: [Int]) -> [Int] {
    var sortArray = arr;
    
    //循環(huán)按照從后往前的順序確定位置,依次確定最后一個(gè)位置薄声、倒數(shù)第二個(gè)位置...
    for i in 0..<sortArray.count {
        for j in 0..<(sortArray.count-i-1) {
            if sortArray[j] > sortArray[j+1] {
                swap(&sortArray[j], &sortArray[j+1]);
            }
        }
    }
    return sortArray;
}
改進(jìn)冒泡排序
  • 如果出現(xiàn)一個(gè)序列当船,此序列基本是有序的,如果是標(biāo)準(zhǔn)的冒泡排序默辨,則還是需要進(jìn)行不斷的比較德频;
  • 改進(jìn)方法:通過填加一個(gè)boolean類型的變量,如果一次循環(huán)中沒有交換過元素缩幸,則說明已經(jīng)排好序抱婉。
    C 代碼
//最好:n-1次比較档叔,不移動(dòng)桌粉。因此時(shí)間復(fù)雜度為O(n)蒸绩,不占用輔助空間。
//最壞:n(n-1)/2次比較和移動(dòng)铃肯,因此為O(n^2)患亿,占用交換的臨時(shí)空間,大小為1押逼;
void bubbleSort1(int *arr, int count)
{
    bool isChanged = true;
    for (int i = 0; i < count && isChanged; i++) {
        
        isChanged = false;
        for (int j = 0; j < count - i - 1; j++) {
            if (arr[j] > arr[j+1]) {
                swap(arr+j, arr+j+1);
                isChanged = true;
            }
        }
    }
}

Swift 代碼

//改進(jìn)冒泡排序
//最好:n-1次比較步藕,不移動(dòng)位置。時(shí)間復(fù)雜度為O(n)挑格,不占用輔助空間咙冗。
//最壞:n(n-1)/2次比較和移動(dòng),因此O(n^2)漂彤,占用交換的臨時(shí)空間雾消,大小為1。
func bubbleSort2(_ arr: [Int]) -> [Int] {
    var sortArray = arr;
    
    var isChanged = true;
    for i in 0..<sortArray.count {
        if !isChanged {
            break;
        }
        
        isChanged = false;
        for j in (i..<sortArray.count-1).reversed() {
            if sortArray[j] > sortArray[j+1] {
                swap(&sortArray[j], &sortArray[j+1]);
                isChanged = true;
            }
        }
    }
    return sortArray;
}
2. 簡(jiǎn)單選擇排序
  • 特點(diǎn):每次循環(huán)找到最小值挫望,并交換立润。因此交換次數(shù)始終為n-1次。
  • 相對(duì)于最簡(jiǎn)單的排序媳板,對(duì)不必要的交換做了改進(jìn)桑腮,每個(gè)循環(huán)不斷比較后記錄最小值,只做了一次交換蛉幸。(也可能不交換破讨,當(dāng)最小值已經(jīng)在正確的位置)

C 代碼

void selectSort(int *arr, int count)
{
    for (int i = 0; i < count; i++) {
        int min = i;
        for (int j = i+1; j < count; j++) {
            if (arr[min] > arr[j]) {
                min = j;
            }
        }
        
        if (min != i) {
            swap(arr+i, arr+min);
        }
    }
}

Swift 代碼

//最差:n(n-1)/2次比較,n-1次交換奕纫,因此時(shí)間復(fù)雜度為O(n^2)
//最好:n(n-1)/2次比較提陶,不交換,因此時(shí)間復(fù)雜度為O(n^2)
//好于冒泡排序

func selectSort(_ arr: [Int]) -> [Int] {
    var sortArray = arr;
    
    for i in 0..<sortArray.count {
        var min = i;
        for j in i+1..<sortArray.count {
            if sortArray[min] > sortArray[j] {
                min = j;
            }
        }
        
        if min != i {
            swap(&sortArray[min], &sortArray[i]);
        }
    }
    return sortArray;
}
3. 簡(jiǎn)單插入排序
  • 思想:給定序列若锁,存在一個(gè)分界線搁骑,分界線的左邊被認(rèn)為是有序的,分界線的右邊還沒被排序又固。每次取沒被排序的最左邊一個(gè)和已排序的做比較仲器,并插入到正確位置;我們默認(rèn)索引 0 的子數(shù)組有序仰冠;每次循環(huán)將分界線右邊的一個(gè)元素插入到有序數(shù)組中乏冀,并將分界線向右移一位;

C 代碼

void insertSort(int *arr, int count)
{
    int j;
    for (int i = 1; i < count; i++) {
        int temp = arr[i];
        
        for (j = i; j > 0 && temp < arr[j-1]; j--) {
            arr[j] = arr[j-1];
        }
        
        //注意要插入的位置
        arr[j] = temp;
    }
}

Swift 代碼

//最好:n-1次比較洋只,0次移動(dòng)辆沦,時(shí)間復(fù)雜度為O(n)
//最差:n(n-1)/2次比較昼捍,n(n-1)/2次移動(dòng),時(shí)間復(fù)雜度為O(n^2)
func insertSort(_ arr: [Int]) -> [Int] {
    var sortArray = arr;
    
    for i in 1..<sortArray.count {
        
        if sortArray[i] < sortArray[i-1] {
            let temp = sortArray[i];
            
            var index = i;
            for j in (0..<i).reversed() {
                
                if sortArray[j] > temp {
                    //如果沒找到位置肢扯,繼續(xù)尋找
                    sortArray[j+1] = sortArray[j];
                    
                    //記錄位置
                    index = j;
                    continue;
                }
            }
            
            //找到位置, 插入數(shù)值
            sortArray[index] = temp;
        }
    }
    
    return sortArray;
}
4. 希爾排序
  • 希爾排序是第一個(gè)突破O(n^2)的排序算法妒茬,是簡(jiǎn)單插入排序的改進(jìn)版;
  • 思想:由于簡(jiǎn)單插入排序?qū)τ谟涗涊^少或基本有序時(shí)很有效蔚晨,因此我們可以通過將序列進(jìn)行分組排序乍钻,使得每組容量變小,再進(jìn)行分組排序铭腕,然后進(jìn)行一次簡(jiǎn)單插入排序即可银择;
  • 增量的選擇十分重要,可以選擇length/2這樣的方式累舷,也是希爾建議的增量浩考,稱為希爾增量。另外被盈,增量最小為1析孽。
    C 代碼
//希爾排序的步長(zhǎng)選擇從length/2開始,每次再減半害捕,直到最后為1绿淋。其實(shí)也可以有另外的更高效的步長(zhǎng)選擇,不過最后需要保證增量為1尝盼。
void shellSort(int *arr, int count)
{
    int increment = count;
    do {
        //設(shè)置希爾初始增量為數(shù)組長(zhǎng)度的一半
        increment = increment / 2;
        if (increment == 0) {
            increment = 1;
        }
        
        int j;
        for (int i = increment; i < count; i++) {
            int temp = arr[i];
            
            //j指向有序區(qū)的最后一個(gè)元素
            for (j = i-increment; j >= 0 && temp < arr[j]; j -= increment) {
                arr[j+increment] = arr[j];
            }
            
            //找到合適的位置吞滞,插入元素
            arr[j+increment] = temp;
        }
    } while (increment > 1);
}

Swift 代碼

//希爾排序的步長(zhǎng)選擇從length/2開始,每次再減半盾沫,直到最后為1裁赠。其實(shí)也可以有另外的更高效的步長(zhǎng)選擇,不過最后需要保證增量為1赴精。
func shellSort(_ arr: [Int]) -> [Int] {
    var sortArray = arr;
    
    var increment = arr.count;
    repeat {
        //設(shè)置希爾初始增量為數(shù)組長(zhǎng)度的一半
        increment = increment / 2;
        if increment == 0 {
            increment = 1;
        }
        
        for i in increment..<sortArray.count {
            let temp = sortArray[i];
            
            //j指向有序區(qū)的最后一個(gè)元素
            var j = i - increment;
            
            //循環(huán)找到合適的位置插入元素
            while j >= 0 && temp < sortArray[j] {
                sortArray[j+increment] = sortArray[j];
                j -= increment;
            }
            
            sortArray[j+increment] = temp;
        }
    } while increment > 1;
    return sortArray;
}
5. 堆排序
  • 大根堆:任意父結(jié)點(diǎn)都比子結(jié)點(diǎn)大佩捞;
    小根堆:任意父結(jié)點(diǎn)都比子結(jié)點(diǎn)小蕾哟;
  • 堆排序是不穩(wěn)定的排序算法箱沦,是簡(jiǎn)單選擇排序的改進(jìn)版峡懈。
  • 堆的存儲(chǔ):一般用數(shù)組來表示堆,若根結(jié)點(diǎn)存在序號(hào) 0 處,i 結(jié)點(diǎn)的父結(jié)點(diǎn)下標(biāo)就為 (i-1)/2米辐。i 結(jié)點(diǎn)的左颂鸿、右子結(jié)點(diǎn)下標(biāo)分別為 2*i+1 和 2*i+2吗冤。如果根節(jié)點(diǎn)是從 1 開始便贵,則左、右子結(jié)點(diǎn)分別是 2i 和 2i+1昂秃。
  • 完全二叉樹有 n 個(gè)結(jié)點(diǎn)禀梳,則擁有 n/2 個(gè)非葉子結(jié)點(diǎn)杜窄。(取整)
  • 思想:構(gòu)建一顆完全二叉樹。首先構(gòu)建大根堆算途,然后每次把根節(jié)點(diǎn)(最大值)和最后的節(jié)點(diǎn)(最小值)互換塞耕,然后將數(shù)組長(zhǎng)度減一。之后重新構(gòu)建大根堆郊艘,以此類推荷科。
  • 注意:此排序方法不適用于個(gè)數(shù)少的序列,因?yàn)槌跏紭?gòu)建需要時(shí)間纱注。
    C 代碼
//堆排序
void heapSort(int *arr, int count)
{
    //1.首先構(gòu)建大根堆
    for (int i = (count-1)/2; i >= 0; i--) {
        heapAdjust(arr, i, count);
    }
    
    //2.將根結(jié)點(diǎn)與尾結(jié)點(diǎn)互換,數(shù)組長(zhǎng)度減去1胆胰,重新構(gòu)建大根堆
    for (int i = 1; i < count; i++) {
        swap(arr, arr+count-i);
        heapAdjust(arr, 0, count-i);
    }
}

//調(diào)整數(shù)組為大根堆狞贱,parent表示根節(jié)點(diǎn)的下標(biāo),count表示要調(diào)整的數(shù)組長(zhǎng)度
void heapAdjust(int *arr, int parent, int count)
{
    //保存根結(jié)點(diǎn)的數(shù)值
    int temp = arr[parent];
    
    //獲取根節(jié)點(diǎn)的左子節(jié)點(diǎn)(下標(biāo)從0開始)
    for (int i = parent * 2 + 1; i < count; i = i * 2 + 1) {
        //找到左蜀涨、右子結(jié)點(diǎn)的較大者
        if (i < count-1 && arr[i] < arr[i+1]) {
            i = i + 1;
        }
        
        //根結(jié)點(diǎn)大于等于左瞎嬉、右子結(jié)點(diǎn)
        if (temp >= arr[i]) {
            break;
        }
        
        //將根結(jié)點(diǎn)與左、右子結(jié)點(diǎn)較大者替換
        arr[parent] = arr[i];
        
        //再次檢查子結(jié)點(diǎn)的子結(jié)點(diǎn)
        parent = i;
    }
    
    arr[parent] = temp;
}

Swift 代碼

func heapSort(_ arr: [Int]) -> [Int] {
    var sortArray = arr;
    let count = sortArray.count;
    
    //首先建立大根堆
    //先找到最后一個(gè)擁有子結(jié)點(diǎn)的根結(jié)點(diǎn)
    var i = count / 2 - 1;
    while i >= 0 {
        heapAdjust(&sortArray, parent: i, count: count);
        i -= 1;
    }
    
    //進(jìn)行排序
    for i in 1..<count {
        //將最后一個(gè)元素和第一個(gè)元素進(jìn)行交換
        swap(&sortArray[0], &sortArray[count-i]);
        
        //數(shù)組的長(zhǎng)度減一厚柳,然后將剩下的無序數(shù)組調(diào)整為大根堆
        //由于只是頭結(jié)點(diǎn)無序氧枣,所以只需要調(diào)整頭結(jié)點(diǎn)即可,其他結(jié)點(diǎn)不需要調(diào)節(jié)
        heapAdjust(&sortArray, parent: 0, count: count-i);
    }
    return sortArray;
}

//調(diào)整指定結(jié)點(diǎn)以下為大根堆别垮,parent表示父結(jié)點(diǎn)的下標(biāo)便监,count表示要調(diào)整的數(shù)組長(zhǎng)度
func heapAdjust(_ arr: inout [Int], parent: Int, count: Int) {
    //保存根結(jié)點(diǎn)的數(shù)值
    let temp = arr[parent];
    var parent = parent;
    
    //獲取根結(jié)點(diǎn)的左子結(jié)點(diǎn)
    var i = parent * 2 + 1;
    while i < count {
        if i < count-1 && arr[i] < arr[i+1] {
            //記錄左右子結(jié)點(diǎn)的較大者
            i = i + 1;
        }
        
        //如果根節(jié)點(diǎn)數(shù)大于子結(jié)點(diǎn)數(shù),則中止循環(huán)碳想,否則沿著一路循環(huán)下去
        if temp >= arr[i] {
            break;
        }
        
        //將較大值賦值到根結(jié)點(diǎn)
        arr[parent] = arr[i];
        
        //更新當(dāng)前根結(jié)點(diǎn)的位置
        parent = i;
        
        //尋找parent的左子結(jié)點(diǎn)進(jìn)行下一輪循環(huán)
        i = i * 2 + 1;
    }
    arr[parent] = temp;
}
6. 歸并排序
  • 穩(wěn)定的排序算法
  • 思想:利用遞歸進(jìn)行分割和合并烧董,分割直到長(zhǎng)度為1為止,并在合并前保證兩序列原本各自有序胧奔,合并后也有序逊移。
    C 代碼
//歸并排序
void mergeSort(int *arr, int count)
{
    for (int gap = 1; gap < count; gap = 2 * gap) {
        mergePass(arr, gap, count);
    }
}

//gap表示字表的長(zhǎng)度,count表示數(shù)組的個(gè)數(shù)
void mergePass(int *arr, int gap, int count)
{
    
    //需要合并的兩個(gè)序列的計(jì)算:
    //low = 2 * gap * i;
    //mid = low + gap - 1;
    //high = low + 2 * gap - 1;
    //這里的i就代表low龙填,要合并的第一個(gè)序列的最小下標(biāo)
    
    int i = 0;
    for (i = 0; i + 2 * gap - 1 < count; i = i + 2 * gap) {
        mergeArray(arr, i, i + gap - 1, i + 2 * gap - 1);
    }
    
    //可能有奇數(shù)個(gè)元素胳泉,有則合并剩下的序列
    if (i + gap - 1 < count) {
        mergeArray(arr, i, i + gap - 1, count - 1);
    }
}

//合并數(shù)組元素,low表示第一段序列的最小下標(biāo)岩遗,mid表示第一段序列的最大下標(biāo)扇商,high表示第二段序列的最高下標(biāo)
void mergeArray(int *arr, int low, int  mid, int high)
{
    int i = low;            //第一段序列的下標(biāo)
    int j = mid + 1;        //第二段序列的下標(biāo)
    int k = 0;              //k是存放合并序列的下標(biāo)
    
    int *array = (int *)malloc((high - low + 1) * sizeof(int));    //申請(qǐng)臨時(shí)空間
    
    //掃描第一段和第二段序列,直到有一個(gè)掃描結(jié)束
    while(i <= mid && j <= high) {
        //判斷第一段和第二段取出的數(shù)哪個(gè)更小喘先,將其加入合并序列钳吟,并繼續(xù)向下掃描
        if (arr[i] < arr[j]) {
            array[k] = arr[i];
            i++;
            k++;
        } else {
            array[k] = arr[j];
            j++;
            k++;
        }
    }
    
    //若第一段序列還沒掃描完,將其全部復(fù)制到合并序列
    while (i <= mid) {
        array[k] = arr[i];
        i++;
        k++;
    }
    
    //若第二段序列還沒掃描完窘拯,將其全部復(fù)制到合并序列
    while (j <= high) {
        array[k] = arr[j];
        j++;
        k++;
    }
    
    //將合并序列復(fù)制到原始序列中
    for (k = 0, i = low; i <= high; i++, k++) {
        arr[i] = array[k];
    }
    
    //釋放空間
    free(array);
}

Swift 代碼

//歸并排序
func mergeSort(_ arr: inout [Int]) {
    var gap = 1;
    while gap < arr.count {
        mergePass(&arr, gap: gap);
        
        gap *= 2;
    }
}

//分解合并序列
func mergePass(_ arr: inout [Int], gap: Int) {
    var i = 0;
    let count = arr.count;
    
    while i + 2 * gap - 1 < count {
        mergeArray(&arr, low: i, mid: i + gap - 1, high: i + 2 * gap - 1);
        
        i += 2 * gap;
    }
    
    //合并剩余的序列
    if i + gap - 1 < count {
        mergeArray(&arr, low: i, mid: i + gap - 1, high: count - 1);
    }
}

//合并兩個(gè)序列
func mergeArray(_ arr: inout [Int], low: Int, mid: Int, high: Int) {
    
    var i = low;
    var j = mid + 1;
    var k = 0;
    
    var array = Array<Int>(repeating: 0, count: high - low + 1);
    
    while i <= mid && j <= high {
        if arr[i] < arr[j] {
            array[k] = arr[i];
            i += 1;
            k += 1;
        } else {
            array[k] = arr[j];
            j += 1;
            k += 1;
        }
    }
    
    while i <= mid {
        array[k] = arr[i];
        i += 1;
        k += 1;
    }
    
    while j <= high {
        array[k] = arr[j];
        j += 1;
        k += 1;
    }
    
    //將排序好的序列復(fù)制回原數(shù)組
    k = 0;
    for i in low...high {
        arr[i] = array[k];
        
        k += 1;
    }
}
7. 快速排序
  • 冒泡排序的升級(jí)版红且,現(xiàn)在用的最多的排序方法坝茎;
  • 思想:選取pivot,將pivot調(diào)整到一個(gè)合理的位置暇番,使左邊的值都小于它嗤放,右邊的值都大于它;
  • 注意壁酬,如果序列基本有序或者序列個(gè)數(shù)較少次酌,則可以采用簡(jiǎn)單插入排序。因?yàn)榭焖倥判驅(qū)@些情況效率不高舆乔。
    C 代碼
//快速排序
void quickSort(int *arr, int low, int high)
{
    if (low < high) {
        int key = partition(arr, low, high);
        
        //對(duì)數(shù)組左邊進(jìn)行排序
        quickSort(arr, 0, key-1);
        
        //對(duì)數(shù)組右邊 進(jìn)行排序
        quickSort(arr, key+1, high);
    }
}

//劃分?jǐn)?shù)組岳服,左邊的數(shù)據(jù)都小于piovt,右邊的數(shù)據(jù)都大于piovt
int partition(int *arr, int low, int high)
{
    int piovtKey = arr[low];            //這個(gè)地方可以優(yōu)化
    
    while (low < high) {
        //遍歷右邊希俩,直到小于piovtKey
        while (low < high && arr[high] >= piovtKey) {
            high--;
        }
        arr[low] = arr[high];
        
        //遍歷左邊吊宋,直到大于piovtKey
        while (low < high && arr[low] <= piovtKey) {
            low++;
        }
        arr[high] = arr[low];
    }
    //將piovtKey賦值到中間位置
    arr[low] = piovtKey;
    
    //返回中間位置,low和high都可以颜武,此時(shí)low與high相等
    return low;
}

Swift 代碼

//快速排序
func quickSort(_ arr: inout [Int], low: Int, high: Int) {
    if low < high {
        let p = partition(&arr, low: low, high: high);
        //左邊遞歸排序
        quickSort(&arr, low: 0, high: p-1);
        
        //右邊遞歸排序
        quickSort(&arr, low: p+1, high: high);
    }
}

//將數(shù)組分成兩部分璃搜,左邊部分小于pivotKey的值,右邊部分大于pivotKey的值
func partition(_ arr: inout [Int], low: Int, high: Int) -> Int {
    var low = low;
    var high = high;
    let pivotKey = arr[low];
    
    while low < high {
        //循環(huán)右邊鳞上,直到小于pivotKey
        while low < high && arr[high] >= pivotKey {
            high -= 1;
        }
        arr[low] = arr[high];
        
        //循環(huán)左邊这吻,直到大于pivotKey
        while low < high && arr[low] <= pivotKey {
            low += 1;
        }
        arr[high] = arr[low];
    }
    
    //將pivotKey放置到中間的位置,返回劃分的位置
    arr[low] = pivotKey;
    return low;
}
快速排序優(yōu)化方案
  • 選取pivot:選取pivot的值對(duì)于快速排序至關(guān)重要篙议,理想情況唾糯,pivot應(yīng)該是序列的中間數(shù)。前面我們只是簡(jiǎn)單的取第一個(gè)數(shù)作為pivot涡上,這點(diǎn)可以進(jìn)行優(yōu)化趾断。
  • 優(yōu)化方法:抽多個(gè)數(shù)后取中位數(shù)作為pivot。
  • 對(duì)于小數(shù)組使用插入排序:因?yàn)榭焖倥判蜻m合大數(shù)組排序吩愧。如果是小數(shù)組芋酌,則效果沒有簡(jiǎn)單插入排序效果好。

三雁佳、排序總結(jié)

  • 數(shù)組長(zhǎng)度不大的情況下不宜使用歸并排序脐帝,其它排序差別不大。
  • 數(shù)組長(zhǎng)度很大情況下希爾排序最快糖权,快速排序其次堵腹,冒泡排序最慢。

總結(jié):每個(gè)排序都有各自的特點(diǎn)星澳,我們需要在適當(dāng)?shù)臅r(shí)候用適當(dāng)?shù)乃惴ň吻辍1热缭?code>基本有序、數(shù)組規(guī)模小的時(shí)候用直接插入排序;比如在大數(shù)組時(shí)用快速排序腿堤;比如想要穩(wěn)定性阀坏,則使用歸并排序

排序方法 平均情況 最好情況 最壞情況 輔助空間 穩(wěn)定性
冒泡排序 O(n^2) O(n) O(n^2) O(1) 穩(wěn)定
簡(jiǎn)單選擇排序 O(n^2) O(n^2) O(n^2) O(1) 穩(wěn)定
直接插入排序 O(n^2) O(n) O(n^2) O(1) 穩(wěn)定
希爾排序 O(n^1.3) O(n) O(n^2) O(1) 不穩(wěn)定
堆排序 O(nlogn) O(nlogn) O(nlogn) O(1) 不穩(wěn)定
歸并排序 O(nlogn) O(nlogn) O(nlogn) O(n) 穩(wěn)定
快速排序 O(nlogn) O(nlogn) O(n^2) O(logn) ~ O(n) 不穩(wěn)定
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末笆檀,一起剝皮案震驚了整個(gè)濱河市忌堂,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌酗洒,老刑警劉巖士修,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異樱衷,居然都是意外死亡棋嘲,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門箫老,熙熙樓的掌柜王于貴愁眉苦臉地迎上來封字,“玉大人,你說我怎么就攤上這事耍鬓。” “怎么了流妻?”我有些...
    開封第一講書人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵牲蜀,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我绅这,道長(zhǎng)涣达,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任证薇,我火速辦了婚禮度苔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘浑度。我一直安慰自己寇窑,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開白布箩张。 她就那樣靜靜地躺著甩骏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪先慷。 梳的紋絲不亂的頭發(fā)上饮笛,一...
    開封第一講書人閱讀 51,258評(píng)論 1 300
  • 那天,我揣著相機(jī)與錄音论熙,去河邊找鬼福青。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的无午。 我是一名探鬼主播媒役,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼指厌!你這毒婦竟也來了刊愚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤踩验,失蹤者是張志新(化名)和其女友劉穎鸥诽,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體箕憾,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡牡借,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了袭异。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钠龙。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖御铃,靈堂內(nèi)的尸體忽然破棺而出碴里,到底是詐尸還是另有隱情,我是刑警寧澤上真,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布咬腋,位于F島的核電站,受9級(jí)特大地震影響睡互,放射性物質(zhì)發(fā)生泄漏根竿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一就珠、第九天 我趴在偏房一處隱蔽的房頂上張望寇壳。 院中可真熱鬧,春花似錦妻怎、人聲如沸壳炎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽冕广。三九已至,卻和暖如春偿洁,著一層夾襖步出監(jiān)牢的瞬間撒汉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來泰國打工涕滋, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留睬辐,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像溯饵,于是被迫代替她去往敵國和親侵俗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容