国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

排序算法總結

KoreyLee / 3144人閱讀

摘要:如果對空間限制不大,可以使用基數排序等方法降低時間復雜度,這些線性時間排序法是利用了數據的特性達到最佳的效果。

內部排序

以下為基于比較的排序。

一、插入排序 直接插入排序

基本思想:

將元素插入到已經排好序的序列中。第一個元素已經是有序序列,然后比較外圍的元素和序列的最后一個元素,判斷是否需要插入,如果小,則插入。

時間復雜度:最優 O(n) 最差 O(n^2)

是否穩定:是

    public void insertSort(int[] arr) {
        int n = arr.length;
        for (int i = 1; i < n; i++) 
            for (int j = i - 1; j >= 0; j--)
                if (arr[j + 1] < arr[j])
                    swap(arr, j + 1, j);
    }

改進后的插入排序

比如,用二分查找優化插入排序,因為是要插入到已經排好序的序列當中,所以在查找插入位置這個地方可以用二分查找來優化。

    public int binarySearch(int[] arr, int low, int high, int key) {
        while (low <= high) {
            int mid = low + (high - low) / 2;
            if (key < arr[mid])
                high = mid - 1;
            else
                low = mid + 1;
        }
        return low;
    }

    public void insertSort(int[] arr) {
        int n = arr.length;
        for (int i = 1; i < n; i++)
            // determine whether to insert
            if (arr[i] < arr[i - 1]) {
                // record the element to insert
                int key = arr[i];
                // find insert index
                int indexInsert = binarySearch(arr, 0, i - 1, arr[i]);
                // move elements
                for (int j = i - 1; j >= indexInsert; j--)
                    arr[j + 1] = arr[j];
                // insert the key
                arr[indexInsert] = key;
            }
    }
二、選擇排序 1. 簡單選擇排序

基本思想:

選出后面最小的元素和前面的交換

時間復雜度: 最優 O(n^2) 最差 O(n^2)

是否穩定:否

    public void selectSort(int[] arr) {

        int n = arr.length;

        for (int i = 0; i < n; i++) {
            int minIndex = i;
            // find the min index
            for (int j = i + 1; j < n; j++) {
                if (arr[j] < arr[minIndex])
                    minIndex = j;
            }
            if (minIndex != i)
                swap(arr, i, minIndex);
        }
    }

改進后的選擇排序

之前的選擇排序是一趟只找到最小的,如果一趟可以把最大最小都找出來,就可以將循環的次數減半。

不過在交換時需要注意一種情況,就是第一個元素就已經是最大元素的情況,因為前面已經交換過 i 和 min,所以再交換時就是交換的 n - i - 1 和 min,而不是 max。

    public void selectSort(int[] arr) {

        int n = arr.length;

        for (int i = 0; i < n / 2; i++) {
            int min = i;
            int max = i;
            for (int j = i + 1; j < n - i; j++) {
                // find the min element
                if (arr[j] < arr[min]) {
                    min = j;
                    continue;
                }
                // find the max element
                if (arr[j] > arr[max])
                    max = j;
            }
            swap(arr, i, min);

            if (max != i)
                swap(arr, n - i - 1, max);
            else // the first element is the max element
                swap(arr, n - i - 1, min);
        }
    }
2. 堆排序

基本思想:

堆排序也是一種直接選擇排序,因為它也是將排好序的大根堆 or 小根堆的頂部元素逐個和尾部元素交換,也是一種選擇。

時間復雜度: 最優 O(nlgn) 最差 O(nlgn) 是一個很優秀的排序算法

是否穩定:否

    public void adjustHeap(int[] arr, int i, int len) {

        int parent = arr[i];

        // start from left child
        for (int k = 2 * i + 1; k < len; k = 2 * k + 1) {
            // find max child (left or right)
            if (k + 1 < len && arr[k + 1] > arr[k])
                k++;
            // compare the parent and its child, but don"t swap
            if (arr[k] > arr[i]) {
                arr[i] = arr[k];
                i = k;
            } else
                break;
        }

        // insert the original parent on index i
        arr[i] = parent;
    }

    public void heapSort(int[] arr) {

        int len = arr.length;

        // adjust heap from the last none-leaf node
        // from bottom to up; from right to left
        for (int i = len / 2 - 1; i >= 0; i--)
            adjustHeap(arr, i, len);

        // swap the top element and the last element
        for (int i = len - 1; i >= 0; i--) {
            swap(arr, i, 0);
            adjustHeap(arr, 0, i);
        }
    }
三、歸并排序

基本思想:分治。將兩個有序序列合并成一個有序序列,遞歸進行。需要輔助數組。

時間復雜度: 最優 O(nlgn) 最差 O(nlgn)

空間復雜度

O(n)

是否穩定:是

    /* create an array in advance to avoid creating arrays frequently */
    private void sort(int[] arr) {
        int n = arr.length;
        int[] temp_arr = new int[n];
        mergeSort(arr, 0, n - 1, temp_arr);
    }

    public void mergeSort(int[] arr, int left, int right, int[] temp_arr) {
        if (left < right) {
            int mid = left + (right - left) / 2;
            mergeSort(arr, left, mid, temp_arr);
            mergeSort(arr, mid + 1, right, temp_arr);
            merge(arr, left, mid, right, temp_arr);
        }
    }

    public void merge(int[] arr, int left, int mid, int right, int[] temp_arr) {

        int i = left;
        int j = mid + 1;
        int t = 0;

        while (i <= mid && j <= right) {
            if (arr[i] < arr[j]) {
                temp_arr[t++] = arr[i];
                i++;
            } else {
                temp_arr[t++] = arr[j];
                j++;
            }
        }

        // insert the remaining elements
        while (i <= mid)
            temp_arr[t++] = arr[i++];
        while (j <= right)
            temp_arr[t++] = arr[j++];

        t = 0;
        // copy elements into array
        while (left <= right)
            arr[left++] = temp_arr[t++];
    }
四、交換排序 1. 冒泡排序

基本思想:

總共有 n 個元素,就比較 n - 1 趟,每一趟比較都會將相鄰元素進行比較,然后將較大的元素向后放,就像大數沉底,小數像上冒一樣。冒泡排序的交換次數等于原始序列的逆序數。

時間復雜度: 最優 O(n) 最差也是平均 O(n^2)

是否穩定:是

    public void bubbleSort(int[] arr) {
        int n = arr.length;
        for (int i = 0; i < n - 1; i++) {
            for (int j = 0; j < n - i - 1; j++) {
                if (arr[j] > arr[j + 1])
                    swap(arr, j, j + 1);
            }
        }
    }

改進后的冒泡排序一

交換過后,會有部分元素是已經排好序了,這一部分再進行比較是沒有意義的,可以從這個地方入手改進冒泡排序。

用一個標志位記錄最后一次進行交換的位置,這個位置后面的元素是沒有進行交換的,說明是已經排好序的,所以不需要再比較。

    public void bubbleSort(int[] arr) {

        int n = arr.length;
        int i = n - 1;
        int pos = 0;

        while (i > 0) {
            for (int j = 0; j < i; j++) {
                pos = 0;
                if (arr[j] > arr[j + 1]) {
                    swap(arr, j, j + 1);
                    pos = j;
                }
            }
            i = pos;
        }
    }

改進后的冒泡排序二

雙向冒泡(正反兩個方向同時排序),使排序次數幾乎減少一半

    public void bubbleSort(int[] arr) {

        int n = arr.length;
        int left = 0;
        int right = n - 1;

        while (left < right) {
            for (int i = left; i < right; i++) {
                if (arr[i] > arr[i + 1])
                    swap(arr, i, i + 1);
            }
            right--;

            for (int i = right; i > left; i--) {
                if (arr[i] < arr[i - 1])
                    swap(arr, i, i - 1);
            }
            left++;
        }
    }
2. 快速排序

基本思想:

根據選擇的基準元素進行劃分,然后兩邊都進行排序,再遞歸進行。需要注意的是,遍歷需要從選擇的基準元素的反方向開始。

時間復雜度: 最優也是平均 O(nlgn) 最差 O(n^2) 即每次選的基準元素都是最大(小)值

是否穩定:否

    public void quickSort(int[] arr, int low, int high) {
        if (low < high) {
            int pivotLoc = partition(arr, low, high);
            quickSort(arr, low, pivotLoc - 1);
            quickSort(arr, pivotLoc + 1, high);
        }
    }

    public int partition(int[] arr, int low, int high) {
        int pivot = arr[low];

        while (low < high) {
            while (low < high && arr[high] >= pivot)
                high--;
            swap(arr, low, high);

            while (low < high && arr[low] <= pivot)
                low++;
            swap(arr, low, high);
        }

        return low;
    }
外部排序

非基于比較的排序,時間復雜度可以達到 O(n),其實是用空間換時間。

下面列舉的都是線性時間排序法

1. 計數排序(Counting Sort)

基本思想:

利用數組下標來排序。但只適合有限數值的數字,序列的數字最大值 k 如果太大,那么開的輔助數組 C[] 就會很大,占用太多空間。
這種思路經常被用到。

時間復雜度: 最優也是平均 O(n + k) 最差 O(n^2) 即每次選的基準元素都是最大(小)值

是否穩定:是

    public int[] countingSort(int[] A, int k) {
        int n = A.length;
        int[] C = new int[k + 1];

        // counting the number of times each element appears in A
        for (int i = 0; i < n; i++) {
            C[A[i]]++;
        }

        // counting elements less than or equal to C[i]
        for (int i = 1; i <= k; i++) {
            C[i] = C[i] + C[i - 1];
        }

        // insert into result array
        int[] B = new int[n];
        for (int i = n - 1; i >= 0; i--) {
            B[C[A[i]] - 1] = A[i];
            C[A[i]]--;
        }

        return B;
    }
2. 桶排序(Bucket Sort)

基本思想:

把數組中數據放到有限個桶中,在每個桶中分別進行排序(可以采用任意排序方法)。

模擬畫圖 ≡ω≡

      input:[12,22,2,13,23,3]

     |     |     |     |     |     |
     | 2,3 |     |12,13|     |22,23|
     |_____|     |_____|     |_____|
     bucket1     bucket2     bucket3
      (1-10)     (11-20)     (21-30)

      output:[2,3,12,13,22,23]   

時間復雜度: 最優近似 O(n) 最差 O(n^2) 即每次選的基準元素都是最大(小)值

是否穩定:是

    public void bucketSort(int[] arr){

        int n = arr.length;

        int max = arr[0];
        int min = arr[0];
        for (int num : arr) {
            if (num < min)
                min = num;
            if (num > max)
                max = num;
        }

        // create bucket
        int bucketNum = max / 10 - min / 10 + 1;
        List bucketList = new ArrayList>();
        for (int i = 1; i <= bucketNum; i++) {
            bucketList.add(new ArrayList());
        }

        // insert into bucket
        for (int i = 0; i < n; i++) {
            int index = (arr[i] - min) / 10;
            ((ArrayList)bucketList.get(index)).add(arr[i]);
        }

        ArrayList bucket = null;
        int index = 0;
        for (int i = 0; i < bucketNum; i++) {
            bucket = (ArrayList)bucketList.get(i);
            bucketInsertSort(bucket);
            for (int num : bucket) {
                arr[index++] = num;
            }
        }
    }

    public void bucketInsertSort(List bucket) {
        for (int i = 0; i < bucket.size(); i++) {
            int temp = bucket.get(i);
            int j = i - 1;
            for (; j >= 0 && bucket.get(j) > temp; j--) {
                bucket.set(j + 1, bucket.get(j));
            }
            bucket.set(j + 1, temp);
        }
    }
3. 基數排序(Radix Sort)

基本思想:

前面的計數和桶排序都是只能排一個關鍵字,而基數排序可以排多個關鍵字。

基數排序分為兩種:假設有二元組 (a, b),以 a 為首要關鍵字,b 為次要關鍵字排序

MSD(Most Siginificant Digit) 先排 a,后排 b

LSD(Least Siginificant Digit) 先排 b,后排 a

基數排序需要使用穩定的排序算法,一般用計數或者桶排序。

e.g. 采用 LSD

input: [170, 45, 75, 90, 802, 24, 2, 66]

1. 從最后一個關鍵字開始排:  
   170, 45, 75, 90, 802, 24, 2, 66
     0   5   5   0    2   4  2   6

   排序后(注意保持原來的相對順序,802 仍然在 2 前面):
   170, 90, 802, 2, 24, 45, 75, 66

2. 從次要關鍵字開始排
   170, 90, 802, 2, 24, 45, 75, 66
    7   9    0      2   4   7   6

   排序后(170 仍然在 75 前面):
   802, 2, 24, 45, 66, 170, 75, 90

3. 從首要關鍵字開始排:
   802, 2, 24, 45, 66, 170, 75, 90
   8                   1

   排序后:
   2, 24, 45, 66, 75, 90, 170, 802

output: [2, 24, 45, 66, 75, 90, 170, 802]

時間復雜度:

平均 O(d * (r + n))

d:digit 數字位數 r:radix 基數 n:number 關鍵字個數

空間復雜度:

O(r + n)

是否穩定:是

    public void radixSort(int[] arr, int n) {

        // find max element
        int max = 0;
        for (int i = 1; i < n; i++) {
            if (arr[i] > max)
                max = arr[i];
        }
        for (int k = 1; max / k > 0; k *= 10) {
            countingSort(arr, n, k);
        }
    }

    public void countingSort(int[] arr, int n, int k) {

        // max number is 9
        int C[] = new int[10];

        // counting occurrences
        for (int i = 0; i < n; i++) {
            C[(arr[i] / k) % 10]++;
        }

        // counting elements less than or equal to C[i]
        for (int i = 1; i < 10; i++) {
            C[i] = C[i] + C[i - 1];
        }

        // insert into result array
        int[] B = new int[n];
        for (int i = n - 1; i >= 0; i--) {
            B[C[(arr[i] / k) % 10] - 1] = arr[i];
            C[(arr[i] / k) % 10]--;
        }

        for (int i = 0; i < n; i++) {
            arr[i] = B[i];
        }

    }
總結

關于穩定性:

穩定的排序算法:冒泡、插入、歸并、計數、桶和基數排序

不穩定的排序算法: 選擇、快速、希爾和堆排序

排序算法的選擇:

如果數據有序或基本有序,冒泡和插入的時間復雜度可以降到 O(n),而快排則相反。

如果數據很大,需要考慮使用 O(nlgn) 的排序方法,如快排、歸并排序、堆排。

如果對空間限制不大,可以使用基數排序等方法降低時間復雜度,這些線性時間排序法是利用了數據的特性達到最佳的效果。

參考資料:

https://www.byvoid.com/zhs/bl...

https://zh.wikipedia.org/wiki...

https://blog.csdn.net/hguisu/...

https://www.geeksforgeeks.org...

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/69574.html

相關文章

  • 各種排序算法總結

    摘要:排序算法是最基本最常用的算法,不同的排序算法在不同的場景或應用中會有不同的表現,我們需要對各種排序算法熟練才能將它們應用到實際當中,才能更好地發揮它們的優勢。今天,來總結下各種排序算法。 排序算法是最基本最常用的算法,不同的排序算法在不同的場景或應用中會有不同的表現,我們需要對各種排序算法熟練才能將它們應用到實際當中,才能更好地發揮它們的優勢。今天,來總結下各種排序算法。 下面這個表格...

    null1145 評論0 收藏0
  • 前端 排序算法總結

    摘要:前言排序算法可能是你學編程第一個學習的算法,還記得冒泡嗎當然,排序和查找兩類算法是面試的熱門選項。本篇將會總結一下,在前端的一些排序算法。函數的性能相信對于排序算法性能來說,時間復雜度是至關重要的一個參考因素。 前言 排序算法可能是你學編程第一個學習的算法,還記得冒泡嗎? 當然,排序和查找兩類算法是面試的熱門選項。如果你是一個會寫快排的程序猿,面試官在比較你和一個連快排都不會寫的人的時...

    happen 評論0 收藏0
  • 算法排序算法總結(JavaScript描述)

    摘要:二代碼簡單選擇排序一分析循環次,每一次的當前項與其之后的項作比較,找出其中最小的那個,與當前項交換。二代碼希爾排序是一種改進版的插入排序,縮小增量排序。這樣做的目的是因為,直接插入排序在序列基本有序時效率最高。 排序算法 平均情況 最好情況 最壞情況 輔助空間 穩定性 冒泡排序 O(n^2) O(n) O(n^2) O(1) 穩定 簡單選擇排序 O(n^2) O(n^2)...

    dkzwm 評論0 收藏0
  • 十大經典排序算法總結(Javascript描述)

    摘要:算法描述冒泡排序是一種簡單的排序算法。算法描述和實現一般來說,插入排序都采用在數組上實現。平均情況希爾排序年發明第一個突破的排序算法是簡單插入排序的改進版它與插入排序的不同之處在于,它會優先比較距離較遠的元素。 前言 讀者自行嘗試可以想看源碼戳這,博主在github建了個庫,讀者可以Clone下來本地嘗試。此博文配合源碼體驗更棒哦~~~ 個人博客:Damonare的個人博客 原文地址:...

    Binguner 評論0 收藏0
  • 十大排序算法總結

    摘要:排序算法的穩定性例如排序一個數組,數組中有兩個,排序之后是,如果排序之后的兩個的前后順序沒有發生變化,那么稱這個排序是穩定的,反之則是不穩定的。冒泡排序冒泡排序是很經典的排序算法了,相鄰的兩個數據依次進行比較并交換位置。 0. 前言 排序算法中涉及到了兩個概念: 原地排序:根據算法對內存的消耗情況,可以將算法分為原地排序和非原地排序,原地排序特指空間復雜度為 O(1) 的排序。 排序算...

    王晗 評論0 收藏0
  • 算法-java排序實現總結

    摘要:一常見的排序算法及時間復雜度二各排序算法的理解及實現冒泡排序算法描述比較相鄰元素,如果第一個比第二個大,交換位置,這樣每經過一趟就冒出一個最大的動圖演示代碼實現快速排序算法描述從數列中挑出一個元素,稱為基準從左向右找比這個第一個比這個基 一.常見的排序算法及時間復雜度 showImg(https://segmentfault.com/img/bV8J6j?w=1722&h=1132);...

    explorer_ddf 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<