快速排序、归并排序、基数排序(桶排序)!

快速排序分析推导图

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

class Untitled {
    public static void main(String[] args) {
        System.out.println("hello https://tool.lu/");
        int[] array = {6,1,2,7,9,3,4,5,10,8};
        quick(array, 0, array.length - 1);
        
        for(int i = 0; i < array.length; i++){
            System.out.println(" " + array[i]);
        }
    }
    
    public static void quick(int[] array, int left, int right) {
        if(left > right){
            return;
        }
        
        // 1、确定基数
        int base = array[left];
        // 2、定义i
        int i = left;
        // 3、定义j
        int j = right;
        
        //如果i和j不相遇,那么就一直检索
        while(i != j){
            
            // 右侧索引检测,如果值大于等于基数 就继续检索, 并且不超过i
            while(array[j] >= base && j > i){
                j--;
            }
            
            // 左侧检索,如果值小于等我基数,就检索,同样不能超过j
            while(array[i] <= base && j > i){
                i++;
            }
            
            // 能走到这 说明找到对应索引了,要把j 和i位置值交换
            int num = array[i];
            array[i] = array[j];
            array[j] = num;
        }
        
        // 走到这里 说明相遇了, 相遇要把基数 和 此时位置交换
        array[left] = array[i]; //array[j]也可以
        array[i] = base;
        
        // 接下来重复排左边的
        quick(array, left, i - 1);
        
        // 重复排右边的
        quick(array, j + 1, right);
        
    }
}

二、归并排序

归并排序基本思想:

在这里插入图片描述

合并相邻有序子序列:

再来看看治阶段,我们需要将两个已经有序的子序列合并成一个有序序列,比如上图中的最后一次合并,要将[4,5,7,8]和[1,2,3,6]两个已经有序的子序列,合并为最终序列[1,2,3,4,5,6,7,8],来看下实现步骤
在这里插入图片描述

代码如下:
public static void main(String[] args) {
        // 冒泡排序
//        BubbleSort();
        // 选择排序
//        selecterSort();
        // 插入排序 8万数据 4s
//        insertSort();
        //希尔交换排序  8万数据 17s  80万1s 800万4s
//        shellSort();
        // 希尔移动排序 8万数据不到1s
        //shellMove();
        // 快排 8万数据 和80 万都不到1s  800万2s
//        int[] arr = {6,1,2,7,9,3,4,5,10,8};
//        quickSort(arr, 0, arr.length - 1);
//        System.out.println(Arrays.toString(arr));
        //归并排序
        int[] arr = {6,1,2,7,9,3,4,5,10,8};
        int[] copy = new int[arr.length];
        mergeSort(arr, 0,  arr.length - 1, copy);
        System.out.println(Arrays.toString(arr));
    }

/**
* 分 + 合方法
*/
private static void mergeSort(int[] arr, int left, int right, int[] temp) {
    if(left < right) {
        System.out.println("left :" + left + "  right:" + right);
        int mid = (left + right) / 2; //中间索引
        //向左递归进行分解
        mergeSort(arr, left, mid, temp);
        //向右递归进行分解
        mergeSort(arr, mid + 1, right, temp);
        //合并
        merge(arr, left, mid, right, temp);
    }
}

/**
* @param arr       排序组
* @param left      左边有序序列左指针
* @param mid       中间索引
* @param right     右边有序序列右指针
* @param temp      中转的数组
*  合并的方法
*/
private static void merge(int[] arr, int left, int mid, int right, int[] temp) {
    // 左指针
    int i = left;
    // 右指针
    int j = mid + 1;
    // 中转数组的下标
    int postison = 0;

    //1、把左右两侧数据添加到临时数组
    //   直到左边或右边,有一边处理完毕
    while (i <= mid && j <= right){  // 没有到边一直循环
        if(arr[i] <= arr[j]) {
            temp[postison] = arr[i];
            i += 1;
            postison += 1;
        }else {
            temp[postison] = arr[j];
            j += 1;
            postison += 1;
        }
    }

    // 2、有一边到头了,把剩余的全部方法临时数组
    while (i <= mid){  //左边没有到头
        temp[postison] = arr[i];
        i += 1;
        postison += 1;
    }
    while (j <= right){  //右边没有到头
        temp[postison] = arr[j];
        j += 1;
        postison += 1;
    }


    // 3 、将temp数组的元素拷贝到arr
    //    注意,并不是每次都拷贝所有
    postison = 0;
    int tempLeft = left;
    while (tempLeft <= right){
        arr[tempLeft] = temp[postison];
        tempLeft += 1;
        postison += 1;
    }
}

三、基数排序

基数排序图文说明:

1、将数组 {53, 3, 542, 748, 14, 214} 使用基数排序, 进行升序排序
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码实现:

public static void radixSort(){
    int[] arr = {53, 3, 542, 748, 14, 214};
    // 1、首先找到在最大数,然后计算出最大的长度
    int max = 0;
    for(int i = 0; i < arr.length; i++) {
        if(arr[i] > max) {
            max = arr[i];
        }
    }
    
    int length = (max + "").length();
    // 2、创建2维数组,10个桶, 0 - 9, 然后大小为了防止长度不够,大小都统一成arr.length
    int[][] bucket = new int[10][arr.length];
    // 3、创建保存每个桶存放的数量 坐标
    int[] bucketElementCounts = new int[10];
    
    /**
     * 推导每一次过程
     */
    // 4.1、比较个位数放入桶中。
    for(int i = 0; i < arr.length; i++) {
        // 找到个位数字
        int digitOfElement = arr[i] % 10;
        // 放入对应位置桶中, 第二个参数:每个桶对用的位置,  加进去之后 还要在++
        bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[i];
        bucketElementCounts[digitOfElement]++;
    }
    
    // 4.2 按照这个顺序取出来,在放入原数组中去
    int index = 0;
    for(int i = 0; i < bucketElementCounts.length; i++) {
        // !=0  说明在对应的同放入数据了
        if(bucketElementCounts[i] != 0) {
            // 遍历每个桶的存入的数量
            for(int l = 0; l < bucketElementCounts[i]; l++) {
                arr[index] = bucket[i][l];
                index++;
            }
        }
        // 每次处理完毕之后,都把存的位置 变成0
        bucketElementCounts[i] = 0;
    }
    
    System.out.println("第 1 轮,对个位的排序处理 arr =" + Arrays.toString(arr));
    
    // 第二轮
    for(int i = 0; i < arr.length; i++) {
        // 把十位数字放入对应的桶中
        int digitOfElement = arr[i] / 10 % 10;
        bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[i];
        bucketElementCounts[digitOfElement]++;
    }
    
    // 取出来放入原数组
    index = 0;
    for(int i = 0; i < bucketElementCounts.length; i++) {
        if(bucketElementCounts[i] != 0) {
            for(int l = 0; l < bucketElementCounts[i]; l++) {
                arr[index] = bucket[i][l];
                index++;
            }
        }
        bucketElementCounts[i] = 0;
    }
    
    System.out.println("第 2轮,对个位的排序处理 arr =" + Arrays.toString(arr));

    // 第二轮
    for(int i = 0; i < arr.length; i++) {
        // 把十位数字放入对应的桶中
        int digitOfElement = arr[i] / 100 % 10;
        bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[i];
        bucketElementCounts[digitOfElement]++;
    }
    
    // 取出来放入原数组
    index = 0;
    for(int i = 0; i < bucketElementCounts.length; i++) {
        if(bucketElementCounts[i] != 0) {
            for(int l = 0; l < bucketElementCounts[i]; l++) {
                arr[index] = bucket[i][l];
                index++;
            }
        }
        bucketElementCounts[i] = 0;
    }
    
    System.out.println("第 3轮,对个位的排序处理 arr =" + Arrays.toString(arr));

    /** ====================华丽的分割线=====================*/
    // n 代表每次是找的位数上的值
    for(int i = 0, n = 1; i < length; i++, n *= 10) {
        //(针对每个元素的对应位进行排序处理), 第一次是个位,第二次是十位,第三次是百位..
        // 找到个位数字, 放入对应桶中
        for(int j = 0; j < arr.length; j++) {
            int digitOfElement = arr[j] / n % 10;
            bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
            bucketElementCounts[digitOfElement]++;
        }
        // 遍历每一个桶取出桶中数据,放入原数组
        int index = 0;
        for(int k = 0; k < bucketElementCounts.length; k++) {
            // 取出对应桶存放的位置
            if(bucketElementCounts[k] != 0) {
                // 遍历每个位置,根据位置取出桶中数据,放入原数组
                for(int l = 0; l < bucketElementCounts[k]; l++) {
                    arr[index] = bucket[k][l];
                    index++;
                }
            }
            bucketElementCounts[k] = 0;
        }
        System.out.println("第 " + (i+1)  +"轮,对个位的排序处理 arr =" + Arrays.toString(arr));
    }
    System.out.println("结果,对个位的排序处理 arr =" + Arrays.toString(arr));
}
发布了51 篇原创文章 · 获赞 78 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_39079048/article/details/103376482