0
点赞
收藏
分享

微信扫一扫

数组的几种排序方法

寒羽鹿 2022-03-12 阅读 98

快速排序

快速排序体现了分治的思想。每次决定一个数的最终位置,将其放置到正确位置后,再通过递归的方式将两头的数组按照同样的方式快速排序。

需要注意的是,使用快速排序时,需要随机取那个决定数,这叫做随机选择比较子。因为当数组时已排好序的时候,指针只会从尾刷到头,快速排序的效率就会非常低,时间复杂度为O(n^2)。所以随机选择比较子后,将比较子和数组最左边的数交换,再做排序。这样的话就算数字已经排好序了,指针也不会从尾刷到头。

  • 快速排序是一种不稳定的算法。算法不稳定是指:在排序之前,有两个数相等,但是在排序结束之后,它们两个有可能改变顺序。
  • 时间复杂度:O(nlogn),这里n是数组的长度;
  • 空间复杂度:O(logn),这里占用的空间主要来自递归函数的栈空间。
class Solution{

    Random random = new Random();
    
    public int[] sortArray(int[] nums) {
        quickSort(nums, 0, nums.length-1);
        return nums;
    }

	//快速排序
    public void quickSort(int[] nums, int start, int last){
        if(start<last){
            int left = start, right = last;
            //随机取数
            int ranIndex = random.nextInt(last-start+1)+start;
            int temp = nums[ranIndex];
            nums[ranIndex] = nums[left];
            nums[left] = temp;
            int aim = nums[left];
            while(left<right){
                while(left<right && aim<=nums[right]) right--;
                if(left<right)  nums[left++] = nums[right];
                
                while(left<right && nums[left]<=aim) left++;
                if(left<right)  nums[right--] = nums[left];
            }
            nums[left] = aim;
            quickSort(nums, start, left-1);
            quickSort(nums, left+1, last);
        }
    }
}

归并排序

归并排序也是体现了分治的思想。将排序任务分给两个子数组,再将两个子数组合并。这里合并的时候需要多申请n的空间资源存放排序后的数组。

  • 时间复杂度:O(nlogn)
  • 空间复杂度:O(n)
class Solution {
    public int[] sortArray(int[] nums) {
        int[] buffer = new int[nums.length];
        mergeSort(nums, 0, nums.length-1, buffer);
        return nums;
    }
    
    public void mergeSort(int[] nums, int start, int last, int[] buffer){
        if(start<last){
            int mid = (start+last)/2;
            mergeSort(nums, start, mid, buffer);
            mergeSort(nums, mid+1, last, buffer);
            mergeTwoArray(nums, start, mid, last, buffer);
        }
    }

    public void mergeTwoArray(int[] nums, int start, int mid, int last, int[] buffer){
        int left = start, right = mid+1;
        int i = left;
        while(left<=mid && right<=last){
            if(nums[left]<=nums[right]){
                buffer[i++] = nums[left++];
            } else{
                buffer[i++] = nums[right++];
            }
        }
        while(left<=mid)    buffer[i++] = nums[left++];
        while(right<=last)    buffer[i++] = nums[right++];

        for(int j = start; j<=last; j++){
            nums[j] = buffer[j];
        }
    }

}

选择排序

选择排序适合于交换数据代价比较大的场合。每轮记住未排序数组中最小的下标,遍历完数组后把最小的下标数和排序后的下一个数(未排序数)交换。

  • 时间复杂度:O(n^2)
  • 空间复杂度:O(1)
public class Solution {

    // 选择排序:每一轮选择最小元素交换到未排定部分的开头

    public int[] sortArray(int[] nums) {
        int len = nums.length;
        // 循环不变量:[0, i) 有序,且该区间里所有元素就是最终排定的样子
        for (int i = 0; i < len - 1; i++) {
            // 选择区间 [i, len - 1] 里最小的元素的索引,交换到下标 i
            int minIndex = i;
            for (int j = i + 1; j < len; j++) {
                if (nums[j] < nums[minIndex]) {
                    minIndex = j;
                }
            }
            swap(nums, i, minIndex);
        }
        return nums;
    }

    private void swap(int[] nums, int index1, int index2) {
        int temp = nums[index1];
        nums[index1] = nums[index2];
        nums[index2] = temp;
    }

插入排序

插入排序在数组越有序的时候效率越高,越有序,需要移动指针的次数越少,最少只需要n次。
插入排序每次从左侧已排序数组的下一个数(未排序数)开始与已排序数组的数逐一比较,若未排序数更小,那就把大的已排序数往后挪一格,直到找到属于自己的位置。

class Solution{
    public void InsertSort(int[] nums){
        for(int i = 0; i<nums.length; i++){
            int temp = nums[i];
            int j = i;
            while(j>0 && nums[j-1]>temp){
                nums[j] = nums[j-1];
                j--;
            }
            nums[j] = temp;
        }
    }
}
举报

相关推荐

0 条评论