java排序算法整理(二)

一、交换排序

利用交换数据元素的位置进行排序的方法称为交换排序。常用的交换排序有冒泡排序法和快速排序法。

1. 冒泡排序

基本思想:设数组中a中存放了n个数据元素,循环进行n-1趟排序过程:第一趟时,依次比较相邻的两个数据元素,若为逆序,则交换两个数据元素,这样数值最大的数据将被放置在a[n-1]中,第二趟时,循环次数减1,数据元素个数为n-1,这样整个n个数据元素中次大的数据元素被放置在a[n-1]中。直至所有的元素排列完成。有些待排序的数据元素序列已经基本有序,这样,实际上并不需要全部执行完上述过程。可以在算法中设计一个flag变量,flag变量用于标记本次排序过程中是否有交换动作,若本次排序过程没有交换动作则说明数据元素集合已全部排好。
冒泡算法如下:

public static void bubbleSort(int[] arr){
        int flag = 1;
        for(int i = 0; i < arr.length-1 && flag == 1; i++){
            flag = 0;
            for(int j = i+1; j < arr.length; j++){
                if (arr[j] < arr[i]){
                    flag = 1;
                    int tmp = arr[j];
                    arr[j] = arr[i];
                    arr[i] = tmp;
                }
            }
        }
    }

总结:冒泡算法的最好情况数据元素集合已经全部排好序,这是循环n-1次,每次循环都因没有交换动作而推出,因此冒泡排序算法最好情况的时间复杂度为O(n);冒泡排序算法最坏情况是数据元素集合全部逆序存放,这是时间复杂度为O(n^2)。冒泡排序的空间复杂度为O(1)

冒泡排序在面试中会让你写递归形式:(主要思路就是每次冒泡会将最大的值移动到数组尾端,每次递归的时候传入的长度减1)

public static void bubbleRecursion(int[] arr, int n){
        if (n < 2)
            return;
        for(int i = 0; i < n-1; i++){
            if (arr[i] > arr[i+1]){
                int tmp = arr[i];
                arr[i] = arr[i+1];
                arr[i+1] = tmp;
            }

            bubbleRecursion(arr, n-1);
        }
    }

2. 快速排序

基本思想:设数组a中存放了n个数据元素,low为数组的低端下标,high为数组的高端下标,从数组a中任取一个元素作为标准元素,以该标砖元素为基准来调整数组a中其他各个元素的位置,使排在标准元素前面的元素均小于标准元素,排在标准元素后面的均大于或等于标准元素。对这两个数组中的元素分别再进行方法类同的递归快速排序,算法的递归出口条件是low>=high。

快速排序算法如下:

public static void quickSort(int[] arr, int low, int high){
        if (arr.length == 0 || low > high)
            return ;

        int index = partition(arr, low, high);
        quickSort(arr, low, index-1);
        quickSort(arr, index+1, high);
    }

    public static int partition(int[] arr, int low, int high){
        int key = arr[low];
        while(low < high){
            while(low < high && arr[high] >= key)
                high--;
            arr[low] = arr[high];

            while(low < high && arr[low] <= key)
                low++;
            arr[high] = arr[low];
        }
        arr[high] = key;

        return high;
    }

快速排序算法的时间复杂度和各次标准数据元素的取法关系很大。若每次选取的标准元素都能均分两个子数组的长度,这样的快速排序过程就是一个完全二叉树结果,这时分解次数等于完全二叉树的深度logn,每次快速排序过程中无论把数组怎样划分,全部的比较次数都接近于n-1次,所以最好情况下快速排序算法的时间复杂度为O(nlogn)

快速排序算法的最坏情况是数据元素全部正序或反序有序,此时每次标准元素都把当前数组分成一个大小比当前数组小1的子数组,若把这样的排序过程画成二叉树结果就是一个二叉退化树。一个二叉退化树的深度是n,所以最坏情况下的快速排序算法的时间复杂度为O(n^2)

一般情况下,数据元素的分布式随机的,数组分解构成的二叉树深度接近于logn,所以快速排序的算法的平均时间复杂度为O(nlogn)

快速排序需要堆栈空间临时保存递归调用参数,堆栈空间的使用个数和递归调用的次数有关,因此最好情况下快速排序算法的空间复杂度为O(logn)最坏情况下快速排序算法的空间复杂度为O(n)平均空间复杂度为O(logn)

快速排序算法是一种不稳定的排序算法。

归并排序
归并排序常用的是二路归并排序。基本思想:设数组a中存放了n个数据元素,初始时我们把它看做n个长度为1的有序子数组,然后从第一个子数组开始,把相邻的子数组两两合并,得到n/2个长度为2的新的有序子数组。对于这些新的有序子数组再两两归并,如此重复,直到得到一个长度为n的有序数组为止。
二路归并排序算法如下:

public static void merge(int[] a, int[] swap, int k){
        int n = a.length;
        int m = 0, l1 = 0, u1 = 0, l2 = 0, i = 0, j = 0, u2 = 0;

        while(l1+k <= n-1){
            l2 = l1 + k;
            u1 = l2 - 1;
            u2 = (l2+k-1 <= n-1) ? l2+k-1 : n-1;

            for(i = l1, j = l2; i <= u1 && j <= u2; m++){
                if (a[i] < a[j]){
                    swap[m] = a[i];
                    i++;
                }
                else{
                    swap[m] = a[j];
                    j++;
                }
            }

            while(i <= u1){
                swap[m] = a[i];
                i++;
                m++;
            }

            while(j <= u2){
                swap[m] = a[j];
                m++;
                j++;
            }

            l1 = u2 + 1;
        }

        for(i = l1; i < n; i++, m++){
            swap[m] = a[i];
        }
    }

    public static void mergeSort(int[] a){
        int i = 0;
        int n = a.length;
        int k = 1;
        int[] swap = new int[n];

        while(k < n){
            merge(a, swap, k);

            for(i = 0; i < n; i++)
                a[i] = swap[i];

            k = 2*k;
        }
    }

对n个元素进行一次二路归并排序时,归并的次数约为logN,任何一次的二路归并排序元素的比较次数都约为n-1,二路归并排序算法的时间复杂度为O(NlogN),二路归并排序使用了n个临时临时内存空间存放数据元素,所以二路归并排序的空间复杂度为O(N)

由于二路归并排序算法是相邻有序子表的两两归并,对于相同的两个数据元素,能够保证原来在前边的元素排序后仍在前边。因此,二路归并排序算法是一种稳定的排序算法。二路归并排序是唯一一个不仅时间复杂度为O(NlogN),并且还是一个稳定的排序算法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值