排序算法-java实现

一、快速排序

思想:基于分治的思想,是冒泡排序的改进型。首先在数组中选择一个基准点并把基准点放于序列的开头(该基准点的选取可能影响快速排序的效率,关于基准点的选择方法后面再讲解),然后分别从数组的两端扫描数组,设两个指示标志(lo指向起始位置,hi指向末尾),首先从后半部分开始,如果发现有元素比该基准点的值小,就交换lo和hi位置的值,然后从前半部分开始扫秒,发现有元素大于基准点的值,就交换lo和hi位置的值,如此往复循环,直到lo>=hi,然后把基准点的值放到hi这个位置,一次排序就完成了。之后再采用递归的方式分别对前半部分和后半部分排序,当前半部分和后半部分均有序时该数组自然也就有序了。

时间复杂度:平均时间复杂度O(nlogn),最坏时间复杂度O(n*n)(数组全部倒序)。
空间复杂度:平均O(logn) 最坏O(n)。

代码

public static void quickSort(int[] arr,int low,int high){
        if(low>=high){
            return;
        }
        int i=low;
        int j=high;
        int temp=arr[i];
        while (i<j){
            while (i<j&&temp<=arr[j]){
                j--;
            }
            while (i<j&&temp>=arr[i]){
                i++;
            }
            if(i<j){
                int t=arr[i];
                arr[i]=arr[j];
                arr[j]=t;
            }


        }
        arr[low]=arr[i];
        arr[i]=temp;
        quickSort(arr, low, i-1);
        quickSort(arr, j+1, high);
    }

二、归并排序

思想:基于分治的思想,不断细分至两个子元素,排序后向上归并。
时间复杂度:O(nlogn)。
代码:

public static void merge(int[] arr,int low,int mid,int high,int[] tmp){
        int i=0;
        int j=low;
        int k=mid+1;
        //两个数组归并到一个数组
        while (j<=mid&&k<=high){
            if(arr[i]<arr[k]){
                tmp[i++]=arr[j++];
            }else {
                tmp[i++]=arr[k++];
            }
        }
        //哪个剩了直接添加
        while (j<=mid){
            tmp[i++]=arr[j++];
        }
        while (k<=high){
            tmp[i++]=arr[k++];
        }
        for(int t=0;t<i;t++){
            arr[t+low]=tmp[t];
        }
    }
    public static void mergeSort(int[] arr,int low,int high,int[] tmp){
        if(low<high){
            int mid=(low+high)/2;
            mergeSort(arr, low, mid, tmp);
            mergeSort(arr, mid+1, high, tmp);
            merge(arr,low,mid,high,tmp);
        }
    }
    public int[] sortArray(int[] nums) {
        mergeSort(nums,0,nums.length-1, new int[nums.length]);
        return nums;
    }

三、堆排序

思想:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列。
时间复杂度:O(nlogn)
空间复杂度:O(1)

public static int[] sortArray(int[] nums) {
        int len = nums.length;
        // 将数组整理成堆
        heapify(nums);

        // 循环不变量:区间 [0, i] 堆有序
        for (int i = len - 1; i >= 1; ) {
            // 把堆顶元素(当前最大)交换到数组末尾
            swap(nums, 0, i);
            // 逐步减少堆有序的部分
            i--;
            // 下标 0 位置下沉操作,使得区间 [0, i] 堆有序
            siftDown(nums, 0, i);
        }
        return nums;
    }

    /**
     * 将数组整理成堆(堆有序)
     *
     * @param nums
     */
    private static void heapify(int[] nums) {
        int len = nums.length;
        // 只需要从 i = (len - 1) / 2 这个位置开始逐层下移
        for (int i = (len - 1) / 2; i >= 0; i--) {
            siftDown(nums, i, len - 1);
        }
    }

    /**
     * @param nums
     * @param k    当前下沉元素的下标
     * @param end  [0, end] 是 nums 的有效部分
     */
    private static void siftDown(int[] nums, int k, int end) {
        while (2 * k + 1 <= end) {
            int j = 2 * k + 1;
            if (j + 1 <= end && nums[j + 1] > nums[j]) {
                j++;
            }
            if (nums[j] > nums[k]) {
                swap(nums, j, k);
            } else {
                break;
            }
            k = j;
        }
    }

    private static void swap(int[] nums, int index1, int index2) {
        int temp = nums[index1];
        nums[index1] = nums[index2];
        nums[index2] = temp;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值