算法基础技巧(二)

1. 希尔排序(对插入排序的一个优化)

在这里插入图片描述
解决方法
先间隔排序,每4个为一个间隔,然后再进行插入排序

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
那么到底隔多少个元素当做一个间隔呢?有一个公式
h = (3 k - 1 ) / 2
并且 h < n / 3 (h小于数组的三分之一)

代码实现

public static void  countShellNum(int n){
        int k = 1;
        int h;
        ArrayList<Integer> arrayList = new ArrayList<Integer>();
        do{
            h = ((int)Math.pow(3,k) - 1) / 2;
            if(h > n /3){
                break;
            }
            arrayList.add(h); // 1,4,13,40
            k++;
        }while(h <= n / 3);

    }

在这里插入图片描述
先对间隔为4的数组进行排序,接着在对1排序,根据arrayList存储的元素倒序排序

排序过程步骤
在这里插入图片描述
在这里插入图片描述
。。。
在这里插入图片描述
希尔排序的代码

public static void  shellSort(int[] arr){
        int length = arr.length;
        int k = 1;
        int h;
        ArrayList<Integer> arrayList = new ArrayList<Integer>();
        do{
            h = ((int)Math.pow(3,k) - 1) / 2;
            if(h > length /3){
                break;
            }
            arrayList.add(h);
            k++;
        }while(h <= length / 3);

        for(int a = arrayList.size() -1 ; a >=0 ;a--){
            h = arrayList.get(a);
            // 先写一个未优化的插入排序
            for(int i = h; i < length ; i++){
                for(int j = i ; j >= h ; j = j-h){
                    if(arr[j] < arr[j-1]){
                        int temp = arr[j];
                        arr[j] = arr[j-1];
                        arr[j-1] = temp;
                    }else{
                        break;
                    }
                }
            }
        }
    }

希尔排序时间复杂度
O(n3/2)
空间复杂度
O(1)

在这里插入图片描述

2. 归并排序

总体思想:
先把大数组拆分成小数组,一直拆到剩一个元素为止,接着在从小数组排序合并成为一个大数组
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码实现
在这里插入图片描述

public class GuiBingSort {

    /**
     * 归并的步骤
     * 1.将大问题拆分为小问题
     * 2.写出终止条件
     */

    public void sort(int[] arr,int left,int right){
        // 2.终止条件
        if(left == right){
            return;
        }
        int mid = (left+right) / 2;
        // 1.拆小问题
        sort(arr,left,mid);
        sort(arr,mid+1,right);
        merge(arr,left,mid,right);
    }

    private void merge(int[] arr, int left, int mid, int right) {
        //1 创建一个新数组
        int num = right-left +1;
        int[] temp = new int[num];

        //2.定义指针
        int tempPos = 0;
        int i = left;
        int j = mid +1;
        while(i <= mid && j <= right){
            if(arr[i] < arr[j]){
                temp[tempPos++] = arr[i++];
            }else{
                temp[tempPos++] = arr[j++];
            }
        }
        while(i <= mid){
            temp[tempPos++] = arr[i++];
        }

        while(j <= right){
            temp[tempPos++] = arr[j++];
        }
        // 3.最后还需要将新数组的值复制到老数组中
        for(int k = 0 ; k < temp.length ; k++){
            arr[left++] = temp[k];
        }
    }


}

在这里插入图片描述
归并排序空间复杂度为O(n)
在这里插入图片描述

另一种实现方式
在这里插入图片描述

3. 快速排序(快排)

在这里插入图片描述

先随机找一个分区点,让后将数组中小于分区点的元素放到分区点左边,大于分区点的元素放到分区点右边
在这里插入图片描述
在这里插入图片描述
快排细节
在这里插入图片描述
在这里插入图片描述

public class QuickSort {
    public void sort(int arr[]){
        if(arr == null || arr.length < 0){
            return ;
        }
        sort(arr,0,arr.length-1);

    }

    private void sort(int[] data,int lo,int hi){
        //递归终止条件
        if(lo >= hi) return;
        int j = partition(data,lo,hi);
        sort(data,lo,j-1);
        sort(data,j+1,hi);

    }

    private int partition(int[] data, int lo, int hi) {
        //定义分区点
        int pivot = data[hi];
        int great = lo;
        int less = lo;

        for(;great <= hi -1; great++){
            if(data[great] < pivot){
                int temp = data[great];
                data[great] = data[less];
                data[less] = temp;
                less++;
            }
        }
        //less和pivot调换位置
        int temp = data[less];
        data[less] = data[hi];
        data[hi] = temp;

        return less;
    }
}

快速排序
在这里插入图片描述

时间复杂度:O(nlogn)
空间复杂度:O(logn)
在代码中没有新建数组呀,为什么不是O(1)。是因为我们用的是递归的写法,递归每调用一次都会占用一次栈的内存。

在这里插入图片描述
快速排序不是稳定的排序算法
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

三路快排代码实现

public class ThreeWayQuickSorter extends Sorter {
    public void sort(int[] data) {
        if (data == null || data.length <= 1) return;
        sort(data, 0, data.length - 1);
    }

    private void sort(int[] data, int lo, int hi) {
        if (lo >= hi) return;
        // 分区
        int pivot = data[hi];

        int less = lo;
        int great = hi;

        int i = lo;
        while (i <= great) {
            if (data[i] < pivot) {
                swap(data, i, less);
                less++;
                i++;
            } else if (data[i] > pivot) {
                swap(data, i, great);
                great--;
            } else {
                i++;
            }
        }

        sort(data, lo, less - 1);
        sort(data, great +1, hi);
    }

    public static void main(String[] args) {
        int[] data = new int[]{34, 33, 12, 78, 21, 1, 98, 100};
        new ThreeWayQuickSorter().sort(data);
        System.out.println(Arrays.toString(data));
    }
}

4. 桶排序

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5. 计数排序

在这里插入图片描述
在这里插入图片描述

public class CountingSorter {
    public void sort(int[] data) {
        if (data == null || data.length <= 1) return;

        // 1. 找到数组中的最大值,初始化计数器
        int max = data[0];
        int min = data[0];
        for (int i = 1; i < data.length; i++) { // O(n)
            max = Math.max(max, data[i]);
            min = Math.min(min, data[i]);
        }
        int[] count = new int[max - min + 1];

        // 2. 计数
        for (int i = 0; i < data.length; i++) { // O(n)
            count[data[i] - min]++;
        }

        // 3. 计数累加
        for (int i = 1; i < count.length; i++) { // O(k)
            count[i] += count[i - 1];
        }

        // 4. 计算每个元素在排序数组中的位置
        int[] output = new int[data.length];
        for (int i = data.length - 1; i >= 0; i--) { // O(n)
            int j = data[i];
            int k = count[j - min] - 1;
            output[k] = data[i];

            count[j - min]--;
        }

        // 5. 拷贝数组
        for (int i = 0; i < data.length; i++) { // O(n)
            data[i] = output[i];
        }
    }

    public static void main(String[] args) {
        CountingSorter sorter = new CountingSorter();

        int[] data = { 4, 2, -2, 8, 3, 3, 1 };
        sorter.sort(data);
        System.out.println(Arrays.toString(data));
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6. 基数排序

基数排序,其实本质上是计数排序
在这里插入图片描述
在这里插入图片描述

public class RadixSorter {
    public void sort(int[] data) {
        if (data == null || data.length <= 1) return;

        // 1. 找到最大值  4006869915
        int max = data[0];
        for (int i = 1; i < data.length; i++) {
            max = Math.max(max, data[i]);
        }

        // 2. 对数组按照每个元素的每位进行计数排序
        for (int exp = 1; max / exp > 0; exp *= 10) { // O(n)
            countSort(data, exp); // 时间复杂度:O(n)
        }
    }

    private void countSort(int[] data, int exp) { // 时间复杂度:O(n)
        // 之所以是 10,是因为数字只有 0...9 十个数字
        int[] count = new int[10];

        for (int i = 0; i < data.length; i++) {
            // 个位数: (234 / 1) % 10 = 4
            // 十位数: (234 / 10) % 10 = 3
            // 百位数: (234 / 100) % 10 = 2
            int digit = (data[i] / exp) % 10;
            count[digit]++;
        }

        for (int i = 1; i < 10; i++) {
            count[i] += count[i - 1];
        }

        int[] output = new int[data.length];
        for (int i = data.length - 1; i >= 0; i--) {
            int digit = (data[i] / exp) % 10;
            int k = count[digit] - 1;
            output[k] = data[i];
            count[digit]--;
        }

        for (int i = 0; i < data.length; i++)
            data[i] = output[i];
    }

    public static void main(String[] args) {
        int[] data = new int[]{4512, 4231, 31923, 2165, 1141};
        new RadixSorter().sort(data);
        System.out.println(Arrays.toString(data));
    }
}

在这里插入图片描述

7. java内置排序算法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
引用型数据类型怎么比较
实现comparable类,重写方法
在这里插入图片描述

如果想比较的对象没有实现comparable 就用第二种方式:
在这里插入图片描述
第二种写法
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
动态数组的排序
在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值