冒泡排序
选择排序
插入排序
归并排序
快速排序

排序就是将输入的数字按照从小到大的顺序进行排列。

冒泡排序

冒泡排序就是重复从序列右边开始比较相邻两个数字的大小,再根据结果交换两个数字的位置。
在冒泡排序中 第一轮要比较n-1次,第二轮比较n-2次...第n-1轮需要比较1次,所以时间复杂度为O(n^2)
Tips:这里指n的平方

         public int[] sort(int[] nums) {
            for (int i=0; i<nums.length; i++) {
                for (int j=0; j<nums.length-1-i; j++) {
                    int a = nums[j];
                    int b = nums[j+1];
                    if (a > b) {
                        nums[j] = b;
                        nums[j+1] = a;
                    }
                }
            }
            return nums;
        }

如果给定一个有序的数组,那么冒泡也会从头到尾遍历,这样会浪费很多资源,所以可以增加一个判断,看是否已经排序完成。代码如下:

  public int[] sort(int[] nums) {
            for (int i=0; i<nums.length; i++) {
                boolean isSort = true;
                for (int j=0; j<nums.length-i-1; j++) {
                    int a = nums[j];
                    int b = nums[j+1];
                    if (a > b) {
                        nums[j] = b;
                        nums[j+1] = a;
                        isSort = false;
                    }
                }
                if (isSort) {
                    break;
                }
            }
            return nums;
        }

选择排序

选择排序是重复从等待排序的数据中寻找最小值,将其与未排序的序列最左边的数字进行交换。
双层循环,时间复杂度为O(n^2)

        public int[] sort(int[] nums) {
            for (int i=0; i<nums.length; i++) {
                int index = i;
                for (int j=i+1; j<nums.length; j++) {
                    index = nums[index] > nums[j] ? j : index;
                }
                int temp = nums[i];
                nums[i] = nums[index];
                nums[index] = temp;
            }
            return nums;
        }

插入排序

插入排序是一种从序列左端开始依次对数据进行排序的算法。
在排序的过程中,左侧的数据陆续归位,而右侧留下的就是还未排序的数据。
从右边拿到的数字还是要跟已经排序好的数字逐一比较,所以时间复杂度还是O(n^2)

        public int[] sort(int[] nums) {
            for (int i=0; i<nums.length-1; i++) {
                int tempIndex = i + 1;
                while (tempIndex > 0) {
                    if (nums[tempIndex] > nums[tempIndex-1]) {
                        break;
                    }
                    int temp = nums[tempIndex];
                    nums[tempIndex] = nums[tempIndex-1];
                    nums[tempIndex-1] = temp;
                    tempIndex--;			
                }
            }
            return nums;
        }

Tips:当然,中间的while循环也可以使用for循环来代替

归并排序

归并排序会把序列分成长度相同的两个子序列,当无法往下分时候,就对子序列进行归并,也就是把两个排好序的子序列合并成一个有序序列,该操作会一直重复执行,直到所有的子序列都归并成一个整体为止。
合并两个排序好的子序列的时候,只需要维护两个指针从首位开始,逐步向后走就好了。所以归并排序的时间复杂度为O(n log n)。
代码如下:


	public int[] sort(int[] nums) {
	    if (nums.length <= 1) {
	        return nums;
	    }
	    int len = nums.length;
	    int[] leftNums = new int[len / 2];
	    int[] rightNums = new int[len - len / 2];
	    System.arraycopy(nums, 0, leftNums, 0, len / 2);
	    System.arraycopy(nums, len / 2, rightNums, 0, len - len / 2);
	    if (leftNums.length != 1) {
	        leftNums = sort(leftNums);
	    }
	    if (rightNums.length != 1) {
	        rightNums = sort(rightNums);
	    }
	    return merge(leftNums, rightNums);
	}


	private int[] merge(int[] nums1, int[] nums2) {
	    if (nums1 == null || nums1.length == 0) return nums2;
	    if (nums2 == null || nums2.length == 0) return nums1;
	    int a = 0, b = 0;
	    int len1 = nums1.length, len2 = nums2.length;
	    int[] res = new int[len1 + len2];
	    int index = 0;
	    while (a < len1 && b < len2) {
	        int aNum = nums1[a];
	        int bNum = nums2[b];
	        if (aNum < bNum) {
	            res[index] = aNum;
	            a++;
	        } else {
	            res[index] = bNum;
	            b++;
	        }
	        index++;
	    }
	    if (a == len1) {
	        System.arraycopy(nums2, b, res, index, len1+len2-index);
	    } else {
	        System.arraycopy(nums1, a, res, index, len1+len2-index);
	    }
	    return res;
	}

快速排序

快速排序算法首先会在序列中随机选择一个基准值,然后将除了基准值以外的数分为比基准值大的数和比基准值小的数,将小的数放基准值前面,将大的放后边,然后再将里面的数按照同样的方法排序。快速排序也是一种分治法。快速排序的时间复杂度为O(n long n)。
代码如下:

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

        private void sort(int[] nums, int startIndex, int endIndex) {
            if (endIndex <= startIndex) {
                return;
            }
            int partiIndex = partitionV2(nums, startIndex, endIndex);
            sort(nums, startIndex, partiIndex-1);
            sort(nums, partiIndex+1, endIndex);
        }

        // 单边扫描
        private int partition(int[] nums, int startIndex, int endIndex) {
            //  随机取一个为基准值
            Random r = new Random();
            int rand = startIndex + r.nextInt(endIndex-startIndex);
            swap(nums, startIndex, rand);
            int res = startIndex;
            int pivot = nums[startIndex];
            for (int i = startIndex+1; i <= endIndex; i++) {
                if (nums[i] < pivot) {
                    res++;
                    swap(nums, res, i);
                }
            }
            //  在循环过程中,指针一直指向最后一个比基准值小的元素
            //  调换基准和当前指针的数值
            swap(nums, startIndex, res);
            return res;
        }

        //  双边扫描
        private int partitionV2(int[] nums, int startIndex, int endIndex) {
            //  随机取一个为基准值
            Random r = new Random();
            int rand = startIndex + r.nextInt(endIndex-startIndex);
            swap(nums, startIndex, rand);
            int pivot = nums[startIndex];

            int left = startIndex+1,right = endIndex;
            while(left <= right) {
                if (nums[left] > pivot && nums[right] < pivot) {
                    swap(nums, left, right);
                    left++;
                    right--;
                    continue;
                }
                if (nums[left] < pivot) {
                    left++;
                    continue;
                }
                if (nums[right] > pivot) {
                    right--;
                    continue;
                }
                left++;
                right--;
            }
            swap(nums, startIndex, right);
            return right;
        }

        private void swap(int[] nums, int startIndex, int endIndex) {
            int temp = nums[startIndex];
            nums[startIndex] = nums[endIndex];
            nums[endIndex] = temp;
        }

Tips:两种扫描方式均可,随机数作为基准。

当然还有其他一些排序,希尔排序、计数排序、稳定排序、桶排序、基数排序等,他们在某些固定的场合非常有效,我们可以根据使用场景来选择使用效率更高的排序方法。