排序

163 阅读1分钟

冒泡排序

for(int i = 0; i < nums.length - 1; i++){  // n个数,只需进行n-1轮循环比较
    for(int j = 1; j < nums.length - i; j++){
        if(nums[j] < nums[j - 1]){ // 如果前面的数>后面的数,交换两个数
            swap(nums, j, j - 1);
        }
    }
}

选择排序

for(int i = 0; i < nums.length - 1; i++){ // n个数,只需进行n-1轮循环比较
    int maxIndex = 0;                    // 找出从0~n-1-i之间最大的数的下标
    for(int j = 0; j < nums.length - i; j++){
        if(nums[maxIndex] < nums[j]){
            maxIndex = j;
        }
    }
    swap(nums, maxIndex, nums.length - 1 - i); // 交换
}

插入排序

for(int i = 1; i < nums.length; i++){  // 从 1开始,第i位之前是排好序的。
    int tem = nums[i];
    int j = i - 1;
    while(j >= 0 && nums[j] > tem){    // 如果第i位小于前面的,找到临界位置,插入进去
        nums[j + 1] = nums[j];
        j--;
    }
    nums[j + 1] = tem;
}

快速排序

class Solution {
    public int[] sortArray(int[] nums) {
        sort(nums, 0, nums.length - 1);
        return nums;
    }
    public void sort(int[] nums, int left, int right){
        if(left >= right){
            return;
        }
        int l = left;
        int r = right;
        int indexNum = nums[left];
        while(l < r){
            while(r > l && nums[r] >= indexNum){
                r--;
            }
            nums[l] = nums[r];
            while(r > l && nums[l] < indexNum){
                l++;
            }
            nums[r] = nums[l];
        }
        nums[l] = indexNum;
        sort(nums, left, l - 1);
        sort(nums, l + 1, right);
    }
}

堆排序

数组存储大根堆/小根堆;

升序使用大顶堆,降序采用小顶堆

下标为i的父节点,其子节点分别为【2 * i + 1】,【2 * i + 2】;

维护堆 以大根堆为例子,对于一个节点i,找出左右节点中最大的子节点,交换父节点与子节点,并递归判断子节点是否满足堆的性质。

void heapify(int nums[], int len, int index){
    int largeIndex = index;
    int leftIndex = index * 2 + 1;
    int rightIndex = index * 2 + 2;
    
    if(leftIndex < len && nums[largeIndex] < nums[leftIndex]){
        largeIndex = leftIndex;
    }
    if(rightIndex < len && nums[largeIndex] < nums[rightIndex]){
        largeIndex = rightIndex;
    }
    if(largeIndex != index){
        swap(nums, largeIndex, index);
        heapify(nums, len, largeIndex);
    }
}

建堆 从最后一个有孩子的节点开始,调整堆。

最后一个有孩子的节点—{下标为i的父节点,其子节点分别为【2 * i + 1】,【2 * i + 2】;},那么对于第i个节点,其父节点的下标为【(i - 1) / 2】

void heapBuild(int[] nums, int len){
    for(int i = (n - 2) / 2; i >= 0; i--){
        heapify(nums, len, i);
    }
}

堆排序

void sort(int[] nums){
    heapBuild(nums, nums.length);
    
    for(int i = n - 1; i > 0; i--){
        swap(nums, i, 0);
        heapify(nums, i, 0);
    }
}

复杂度

排序法平均时间最差情形稳定度额外空间备注
冒泡O((n^2)    O(n^2)稳定O(1)n小时较好
选择O((n^2)O((n^2)不稳定O(1)n小时较好
插入O((n^2)O((n^2)稳定O(1)大部分已排序时较好
快速O(nlogn)O((n^2)不稳定O(nlogn)n大时较好
归并O(nlogn)O(nlogn)稳定O(1)n大时较好
O(nlogn)O(nlogn)不稳定O(1)n大时较好