https://leetcode-cn.com/problems/sort-an-array/

选择排序

平均:排序 - 图1
最坏:排序 - 图2
因为要将最小值调换到前面,不稳定

  1. int* sortArray(int* nums, int numsSize, int* returnSize){
  2. *returnSize = numsSize;
  3. for(int i = 0; i < numsSize; i++){
  4. int min = i;
  5. for(int j = i + 1; j < numsSize; j++){
  6. if(nums[j] < nums[min]){
  7. min = j;
  8. }
  9. }
  10. if(min != i){
  11. int temp = nums[min];
  12. nums[min] = nums[i];
  13. nums[i] = temp;
  14. }
  15. }
  16. return nums;
  17. }
  1. public static int[] selectionSort(int[] nums) {
  2. for (int i = 0; i < nums.length; i++) {
  3. int currentMin = i; //当前最小值下标
  4. for (int j = i + 1; j < nums.length; j++) {
  5. if (nums[j] < nums[currentMin])
  6. currentMin = j;
  7. }
  8. if (currentMin != i) {
  9. int temp = nums[i];
  10. nums[i] = nums[currentMin];
  11. nums[currentMin] = temp;
  12. }
  13. }
  14. return nums;
  15. }

冒泡排序

平均:排序 - 图3
最坏:倒序,排序 - 图4
稳定

int* sortArray(int* nums, int numsSize, int* returnSize){
    *returnSize = numsSize;
    for(int i = 1; i < numsSize; i++){
        for(int j = 0; j < numsSize - i; j++){
            if(nums[j] > nums[j + 1]){
                int temp = nums[j];
                nums[j] = nums[j + 1];
                nums[j + 1] = temp;
            }
        }
    }
    return nums;
}
public static int[] bubbleSort(int[] nums) {
    int temp;
    boolean flag;
    for (int p = nums.length - 1; p > 0; p--) {
        flag = false;
        for (int i = 0; i < p; i++) { //一趟冒泡
            if (nums[i] > nums[i + 1]) {
                temp = nums[i];
                nums[i] = nums[i + 1];
                nums[i + 1] = temp;
                flag = true;
            }
        }
        if (!flag) //全程无交换
            break;
    }
    return nums;
}

插入排序

平均:排序 - 图5
最坏:倒序,排序 - 图6
最好:顺序,排序 - 图7
稳定

int* sortArray(int* nums, int numsSize, int* returnSize){
    *returnSize = numsSize;
    for(int i = 1; i < numsSize; i++){
        int temp = nums[i];
        int j = i;
        while(j > 0 && nums[j - 1] > temp){
            nums[j] = nums[j - 1];
            j--;
        }
        nums[j] = temp;
    }
    return nums;
}
public static int[] insertionSort(int[] nums) {
    for (int i = 1; i < nums.length; i++) {
        int temp = nums[i];
        while (i > 0 && temp < nums[i - 1]) {
            nums[i] = nums[i - 1]; //将下标i-1空出来
            i--;
        }
        nums[i] = temp;
    }
    return nums;
}

任意N个不同元素组成的序列平均具有 N(N-1)/4 个逆序对
任何仅以交换相邻两元素来排序的算法,其平均时间复杂度为排序 - 图8

希尔排序

平均:排序 - 图9
最坏:排序 - 图10

public static int[] shellSort(int[] nums) {
    int c = 0;
    int[] Sedgewick = {929, 505, 209, 109, 41, 19, 5, 1, 0};
    //增量不能超过数组长度
    while (Sedgewick[c] >= nums.length)
        c++;
    for (int d = Sedgewick[c]; d > 0; d = Sedgewick[++c]) {
        for (int i = d; i < nums.length; i += d) {
            int temp = nums[i];
            while (i > 0 && temp < nums[i - d]) {
                nums[i] = nums[i - d];
                i = i - d;
            }
            nums[i] = temp;
        }
    }
    return nums;
}

归并排序

无论如何排序 - 图11
额外空间:排序 - 图12
稳定

int* sortArray(int* nums, int numsSize, int* returnSize){
    *returnSize = numsSize;
    int* temp = (int *)malloc(sizeof(int) * numsSize);
    sort(nums, 0, numsSize - 1, temp);
    return nums;
}

void sort(int* nums, int left, int right, int* temp){
    if(left >= right)
        return;
    int middle = (left + right) / 2;
    sort(nums, left, middle, temp);
    sort(nums, middle + 1, right, temp);
    merge(nums, left, middle + 1, right, temp);
}

void merge(int* nums, int left, int right, int rightEnd, int* temp){
    int leftEnd = right - 1;
    int p = left;
    int count = rightEnd - left + 1;
    while(left <= leftEnd && right <= rightEnd){
        if(nums[left] <= nums[right]){
            temp[p] = nums[left];
            left++; 
        }
        else{
            temp[p] = nums[right];
            right++; 
        }
        p++;
    }
    while(left <= leftEnd){
        temp[p] = nums[left];
        left++;
        p++;
    }
    while(right <= rightEnd){
        temp[p] = nums[right];
        right++;
        p++;
    }
    for(int i = 0; i < count; i++){
        nums[rightEnd] = temp[rightEnd];
        rightEnd--;
    }
}
import java.util.Arrays;

class Solution {

    private static int[] temp;

    public static int[] mergeSort(int[] nums) {
        temp = new int[nums.length]; //在最外层申请额外空间
        sort(nums, 0, nums.length - 1);
        return nums;
    }

    public static void sort(int[] nums, int low, int high) {
        if (high <= low)
            return;
        int mid = (high + low) / 2;
        sort(nums, low, mid); //递归对左半边排序
        sort(nums, mid + 1, high);
        if (nums[mid] >= nums[mid + 1]) //若已为顺序则不必进入排序
            merge(nums, low, mid + 1, high);
    }

    //left左边起始位置,right右边起始位置,rightEnd终点位置
    public static void merge(int[] nums, int left, int right, int rightEnd) {
        int k = left;
        int leftEnd = right - 1;
        int count = rightEnd - left + 1;
        while (left <= leftEnd && right <= rightEnd) {
            //这里的等号使得归并排序是稳定的
            if (nums[left] <= nums[right]) {
                temp[k] = nums[left];
                left++;
            } else {
                temp[k] = nums[right];
                right++;
            }
            k++;
        }
        while (left <= leftEnd) {
            temp[k] = nums[left];
            left++;
            k++;
        }
        while (right <= rightEnd) {
            temp[k] = nums[right];
            right++;
            k++;
        }

        for (int i = 0; i < count; i++, rightEnd--) {
            nums[rightEnd] = temp[rightEnd];
        }

    }

    public static void main(String[] args) {
        int[] test = new int[]{4, 3, 2, 1};
        System.out.println(Arrays.toString(mergeSort(test)));
    }
}

快速排序

平均:排序 - 图13
最坏:排序 - 图14
额外空间:排序 - 图15

class Solution {
    public int[] sortArray(int[] nums) {
        sort(nums, 0, nums.length - 1);
        return nums;
    }

    public int getMedium(int[] nums, int left, int right){
        int center = (left + right) / 2;
        int temp;
        if(nums[left] > nums[right]){
            temp = nums[left];
            nums[left] = nums[right];
            nums[right] = temp;
        }
        if(nums[left] > nums[center]){
            temp = nums[left];
            nums[left] = nums[center];
            nums[center] = temp;
        }
        if(nums[center] > nums[right]){
            temp = nums[center];
            nums[center] = nums[right];
            nums[right] = temp;
        }
        temp = nums[center];
        nums[center] = nums[right - 1];
        nums[right - 1] = temp;

        return nums[right - 1];
    }

    public void sort(int[] nums, int left, int right){
        if(right - left > 0){
            int pivot = getMedium(nums, left, right);
            //如果不设置cutoff使用插入排序一定要判断条件
            if(right - left > 2){
                int temp;
                int i = left + 1;
                int j = right - 2;
                while(true){
                    while(nums[i] < pivot)
                        i++;
                    while(nums[j] > pivot)
                        j--;
                    if(i < j){
                        temp = nums[i];
                        nums[i] = nums[j];
                        nums[j] = temp;
                    }
                    else break;
                }
                temp = nums[i];
                nums[i] = nums[right - 1];
                nums[right - 1] = temp;
                sort(nums, left, i - 1);
                sort(nums, i + 1, right);                
            }
        }
    }
}

堆排序

  • 建堆,删除,导回,时间复杂度为排序 - 图16,需要额外排序 - 图17额外空间
  • 建最小堆,将堆顶与最后一个元素交换,此时最后一个元素已固定,不需要额外空间,时间复杂度较上面小