5 排序(重點)


排序的基本概念


插入排序

直接插入排序
  • 從空間分析:空間復雜度 o (1),只要一個元素的輔助空間用于位置的交換,也稱原地排序算法。
  • 從時間分析:時間復雜度 o(n^2),對隨機順序的數據來說,移動和比較的次數接近最壞情況。
  • 由于直接插入算法的元素移動是順序的,該排序算法是穩定
for (int i = 1; i < arr.length; i++) {
    int temp = arr[i];
    for (int j = i - 1; j >= 0; j--) {
        if (arr[j] > temp) {
            arr[j + 1] = arr[j];
            if (j == 0) {
                arr[0] = temp;
            }
        } else {
            arr[j + 1] = temp;
            break;
        }
    }
}
折半插入排序

前提條件:有序

  • 過程:利用二分查找法來確定要插入的位置,將該位置及以后的位置依次向后移動一位,然后將要插入的數插入該位置
public void binaryInsertionSort(int[] arr, int n) {
    for (int i = 1; i < n; i++) {
        int temp = arr[i];
        int left = 0, right = i - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (arr[mid] > temp) {
                right = mid - 1;
            } else if (arr[mid] < temp) {
                left = mid + 1;
            }
        }
        for (int j = i - 1; j >= left; j--) {
            arr[j + 1] = arr[j];
        }
        arr[left] = temp;
    }
}
希爾排序
  • 會跳著排,不穩定、時間復雜度在 nlogn 和 n^2 之間,所以定位很尷尬,算法本身比較復雜,但在 nlogn級別 時間復雜度大行其道的高級排序算法根本沒存在的意義。。。不做過深研究

交換排序

冒泡排序
  • 只進行元素間的順序移動,所以是一個穩定的排序算法
public void bubbleSort(int[] arr) {
    for (int i = 0; i < arr.length - 1; i++) {
        for (int j = 0; j < arr.length - 1 - i; j++) {
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}
快速排序

快速排序是名副其實的,因為在實際應用中,它幾乎是最快的排序算法,被評為20世紀十大算法之一。
快排在實踐中有兩種常用的分割策略:

  • 第一種分割策略
  1. 首先用變量備份軸元素
  2. 取兩個指針 left 和 right,它們的初始值分別指向序列最左邊的下標,序列最右邊的下標。當left 小于 right時
  3. 從right所指的位置向左搜索,找到第一個小于等于軸的元素,把這個元素移動到left的位置,再從left所指的位置開始向右搜索,找到第一個大于軸的元素,把它移動到right所指的位置。
  4. 重復這個過程,直到left等于right,最后把軸元素放在left所指的位置。
public int partition1(int[] arr, int left, int right) {
    int pivot = arr[left];
    while (left < right) {
        while (left < right && arr[right] > pivot) {
            right--;
        }
        arr[left] = arr[right];
        while (left < right && arr[left] <= pivot) {
            left++;
        }
        arr[right] = arr[left];
    }
    arr[left] = pivot;
    return left;
}
  • 第二種分割策略
  1. 首先用變量備份軸元素
  2. 取兩個指針 left 和 right,它們的初始值分別指向序列左邊第二個元素下標,序列最右邊的下標。當left不大于right時
  3. 向右移動left,使其停在第一個大于軸元素的元素位置,同時向左移動right,使其停在第一個不大于軸元素的位置,然后交換left和right位置的元素,然后繼續移動left、right,交換相應的元素
  4. 重復這個過程,直至left大于right。
public int partition2(int[] arr, int start, int end) {
    int pivot = arr[start];
    int left = start, right = end;
    while (left <= right) {
        while (left <= right && arr[left] <= pivot)
            left++;
        while (left <= right && arr[right] > pivot)
            right--;
        if (left < right) {
            swap(arr[left], arr[right]);
            left++;
            right--;
        }
        swap(arr[start], arr[right]);
        return right;
    }
}

快排就是遞歸調用上述分割策略來不斷劃分子序列從而完成排序

public void quickSort(int[] arr, int left, int right) {
    int p = partition1(arr, left, right);
    quickSort(arr, left, p - 1);
    quickSort(arr, p + 1, right);
}

快排空間的開銷主要是遞歸調用時所使用的棧,因此快排空間開銷和遞歸調用的棧的深度成正比,故最好的空間復雜度為 logn,最壞的空間復雜度為 n


選擇排序

簡單選擇排序
for (int i = 0; i < arr.length - 1; i++) {
    for (int j = i + 1; j < arr.length; j++) {
        if (arr[j] < arr[i]) {
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
}
堆排序

歸并排序


比較排序算法的時間復雜度下界


基數排序


各種內部排序算法的比較和選擇


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

推薦閱讀更多精彩內容

  • 總結一下常見的排序算法。 排序分內排序和外排序。內排序:指在排序期間數據對象全部存放在內存的排序。外排序:指在排序...
    jiangliang閱讀 1,375評論 0 1
  • 概述 排序有內部排序和外部排序,內部排序是數據記錄在內存中進行排序,而外部排序是因排序的數據很大,一次不能容納全部...
    蟻前閱讀 5,220評論 0 52
  • 概述:排序有內部排序和外部排序,內部排序是數據記錄在內存中進行排序,而外部排序是因排序的數據很大,一次不能容納全部...
    每天刷兩次牙閱讀 3,743評論 0 15
  • 排序的基本概念 在計算機程序開發過程中,經常需要一組數據元素(或記錄)按某個關鍵字進行排序,排序完成的序列可用于快...
    Jack921閱讀 1,459評論 1 4
  • 2017.08.15
    不系之舟a閱讀 147評論 0 1