详解七大排序算法

#常用算法学习# #java运行#

快速排序法

快速排序是一种比较快速的排序算法,它的平均运行时间是 O(nlogn),之所以特别快是由于非常精练和高度优化的内部循环,最坏的情形性能为 O(n^2)。像归并一样,快速排序也是一种分治的递归算法。从空间性能上看,快速排序只需要一个元素的辅助空间,但快速排序需要一个栈空间来实现递归,空间复杂度也为O(logn)。

每趟排序过后,基于选定的基准值,小于基准值的放左边,大于基准值的放右边。

快速排序法可以有挖坑和左右指针法两种实现方法

挖坑法

 /**
     * 挖坑法
     * @param arrays
     * @param low
     * @param high
     */
    public static void pothlingSort(int[] arrays , int low , int high){


        if(low < high){

            //求每次分治的分割线
            int divideIndex = getDivideIndex(arrays,low,high);
            //再递归分别对分割的俩个子数组进行递归排序
            pothlingSort(arrays,low,divideIndex -1);
            pothlingSort(arrays,divideIndex + 1, high);
        }

    }

    private static int getDivideIndex(int[] arrays, int low, int high) {
        // 将数组最左端arrays[0]作为默认的基准值,将最左端的值放至基准值的坑内。
        // 此时arrays[0]没有值了,需要从最右端找到一个比基准值小的数填至[0]这个坑。
        // 再从左到右找到一个比基准值大的数填到刚才的坑。循环进行直到low=high
        // 将基准值填至刚才的low位置。再进行分治

        int baseValue = arrays[low];
        arrays[low] = 0 ;

        while (low < high){
            while(low < high && arrays[high] >= baseValue){
                high--;
            }
            arrays[low] = arrays[high] ;
            arrays[high] = 0 ;

            while(low < high && arrays[low] <= baseValue){
                low++;
            }
            arrays[high] = arrays[low] ;
            arrays[low] = 0 ;

        }

        if(low == high){
            arrays[low] = baseValue;
        }

        return low;
    }

左右指针法

/**
     * 快速排序
     * 选择一个基准值,所有小于基准值的放左边,大于基准值的放右边
     * 1、挖坑法 2、左右指针法
     * @param arr
     */
    public  void quickSortPoint(int[] arr, int low, int high) {
        if (low < high) {
            // 获取分区后的枢纽位置
            int pivotIndex = partitionPoint(arr, low, high);

            // 分别对枢纽左右两边的子数组进行递归排序
            quickSortPoint(arr, low, pivotIndex - 1);
            quickSortPoint(arr, pivotIndex + 1, high);
        }
    }

    private  int partitionPoint(int[] arr, int low, int high) {
        // 选择数组的最后一个元素作为枢纽值
        int pivot = arr[high];
        int i = (low - 1);
        //所有的小于i+1的都小于pivot
        // 遍历数组,将小于枢纽值的元素放到左边,大于枢纽值的元素放到右边
        for (int j = low; j < high; j++) {
            if (arr[j] < pivot) {
                i++;

                // 交换 arr[i] 和 arr[j]
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }

        // 将枢纽元素放到正确的位置
        int temp = arr[i + 1];
        arr[i + 1] = arr[high];
        arr[high] = temp;

        // 返回枢纽位置
        return i + 1;
    }

直接插入排序

插入排序的平均时间复杂度也是 O(n^2),空间复杂度为常数阶 O(1),具体时间复杂度和数组的有序性也是有关联的。

插入排序中,当待排序数组是有序时,是最优的情况,只需当前数跟前一个数比较一下就可以了,这时一共需要比较 N-1 次,时间复杂度为 O(N)。最坏的情况是待排序数组是逆序的,此时需要比较次数最多,最坏的情况是 O(n^2)

/**
 * 直接插入排序
 * 将一个记录插入到已经排好序的有序表中,从而一个新的、记录数增 1 的有序表
 * @param arr
 */
private void insertSort(int [] arr){
    //从第二个元素开始,都是排序过的列表
    for(int i = 1; i < arr.length  ;i++){

        for(int j = i ; j > 0 ; j --){
            if(arr[j] < arr[ j - 1]){
                int tem = arr[j];
                arr[j] = arr[j-1];
                arr[j-1] = tem;
            }else{
                break;
            }

        }
    }

}

冒泡排序

从数据的第一个元素开始,比较相邻的两个元素,前一个大于后一个的交换为只,一轮排序下来,最大的元素排在最后。

在最坏的情况下,即序列本来就是逆序的情况下,需要进行n-1次遍历,每次遍历需要比较和交换n-i次,因此总的比较和交换次数是n(n-1)/2,故冒泡排序的时间复杂度是O(n^2)

 /**
     * 冒泡排序
     * @param arr
     */
    private void sort(int [] arr){

        for(int i = 0 ; i < arr.length - 1 ; i++){
            boolean change = false;
            for(int j = 0 ; j < arr.length - 1 - i ; j++){
                if(arr[j] > arr [ j + 1]){
                    int temp = arr[j+1];
                    arr[j+1] = arr[j];
                    arr[j]=temp;
                    change = true;
                }
            }
            if(!change)
                return;
        }
    }

    /**
     * 双冒泡排序
     * @param arr
     */
    private void sortT(int[] arr){

        int left = 0;
        int right = arr.length  - 1;

        while (left < right){

            for(int i = 0 ;i < right ;i++){
                if(arr[i] > arr [ i + 1]){
                    int temp = arr[i+1];
                    arr[i+1] = arr[i];
                    arr[i]=temp;
                }
            }
            left ++;

            for(int j = right - left ; j > 0  ; j--){
                if(arr[j-1] > arr [ j]){
                    int temp = arr[j-1];
                    arr[j-1] = arr[j];
                    arr[j]=temp;
                }
            }
            right --;

        }

    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值