排序学习笔记

235 阅读2分钟

题目地址

选择排序

运行逻辑

  • 遍历数组0到倒数第二个数字, 遍历到第i个数的时候, 将第i个数 和 i+1个数往后的所有数字作比较, 找到一个最小的数字, 将其值和第i个数交换.
  • 整体思路: 找到第一小和第一个数互换, 第二小和第二个数互换....

代码

注意点

  1. 需要一个局部变量minIndex标识当前最小元素
  2. i 从 0 ~ len-1, 因为倒数第一个数, 没有数字和他比较了, 不需要排了
  3. j从 i+1 ~ len 因为第i个数已经被拿走.
class Solution {
    public int[] sortArray(int[] nums) {
        int len = nums.length;
        // 取出数组所有元素
        for (int i = 0; i < len - 1; i ++) {
            // 局部变量i为起始,  minIndex保存最小元素
            int minIndex = i;
            for (int j = i + 1; j < len; j++) {
                if (nums[j] < nums[minIndex]) {
                    minIndex = j;
                }
            }
            swap(minIndex, i, nums);
        }

        return nums;
    }

    public void swap(int minIndex, int i, int[] nums) {
        int tmp = nums[minIndex];
        nums[minIndex] = nums[i];
        nums[i] = tmp;
    }
}

复杂度

  • 一共n个数字, 第一个数字要和n-1个数字比较, 第二个数字要和n-2个数字比较...
  • 求和 1+2+3+...+n = big O(n^2)

插入排序

运行逻辑

  • 第i个数, 如果前面的3个数比他大, 就先将3个比他大的数后移, 然后将第i个数插入这三个数字的前面

代码

class Solution {
    public int[] sortArray(int[] nums) {
        int len = nums.length;
        // 插入排序 1~len个元素往前插入
        // 1 3 4 2 比如 2 比 3 4 小, 3 4 后移动, 2放在3现在的位置上
        for (int i = 1; i < len; 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;
    }
}

特点

  • 插入排序」可以提前终止内层循环(体现在 nums[j - 1] > temp 不满足时),在数组「几乎有序」的前提下,「插入排序」的时间复杂度可以达到 O(N), 因此插入排序在短数组和几乎有序数组表现良好

复杂度

  • 时间复杂度:O(N^2)

归并排序 MergeSort

运行逻辑

  • 合并两个有序数组, 如{1}, {2} 合并成{1,2}, 又如{1, 2},{3,4} 合并成{1,2,3,4}, 利用递归的思想进行合并

API

  • System.arraycopy
public static void arraycopy(Object src,
                             int srcPos,
                             Object dest,
                             int destPos,
                             int length)

代码

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

    public void mergeSort(int[] nums, int start, int end, int[] temp) {
        if (start >= end) return;
        int mid = start + (end - start) / 2;
        mergeSort(nums, start, mid, temp);
        mergeSort(nums, mid+1, end, temp);

        // 合并两个排序好的数组,
        int i = start;
        int j = mid+1;
        int cur = 0;
        // 合并数组保存到temp中, 此时左边右边都有数
        while (i<=mid&&j<=end) {
            if (nums[i]<=nums[j]) temp[cur] = nums[i++];
            else temp[cur] = nums[j++];
            cur++;
        }
        // 右半部分没有数字了
        while (i<=mid) {
            temp[cur++] = nums[i++];
        }
        // 左半部分没有数字了
        while (j<=end) {
            temp[cur++] = nums[j++];
        }
        // 保存到nums中
        System.arraycopy(temp, 0, nums, start, end - start + 1);
    }
}

要点

  • 新建一个temp数组和nums同样大小, 来保存每次合并好的数组(因为不能在nums上直接改动, 每次需要新建很麻烦)
  • 每次都会将一个数组, 拆封成两部分, 进行排序
  • 将排序的数组合并
  • 分冶法 下面这图很形象

复杂度

  • nlogn

参考链接

www.cnblogs.com/chengxiao/p…