java中的8大排序算法

1.背景

排序算法经常在面试中问到.....

2.排序算法

2.1.冒泡排序

复制代码
package com.ldp.structure.demo02;

import org.junit.Test;

import java.util.Arrays;

/**
 * @create 04/15 7:17
 * @description <p>
 * 冒泡排序
 * </p>
 */
public class Test01BubblingSort {
    @Test
    public void test01() {
        //  int[] array = {7, 20, 2, 3, 8, 12, 11};
        int[] array = {8, 2, 1, 3, 7, 10, -1};
        // int[] array = {8, 2, 1, 3, 7};
        bubblingSort(array);
    }

    /**
     * 冒泡排序,相邻之间比较
     *
     * @param array
     */
    public void bubblingSort(int[] array) {
        System.out.printf("\n 第:0 轮,array=%s", Arrays.toString(array));
        int length = array.length;
        int temp;
        boolean flag = false;
        for (int i = 0; i < length - 1; i++) {
            for (int j = 0; j < length - 1 - i; j++) {
                if (array[j] > array[j + 1]) {
                    flag = true;
                    temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                }
            }
            System.out.printf("\n 第:%d 轮,array=%s", (i), Arrays.toString(array));
            // 如果没有发送交换,则说明已经排好了,结束循环
            if (!flag) {
                break;
            } else {
                // 初始化
                flag = false;
            }
        }
    }
}
复制代码

 

2.2.选择排序

复制代码
package com.ldp.structure.demo02;

import org.junit.Test;

import java.util.Arrays;

/**
 * @create 04/15 7:17
 * @description <p>
 * 冒泡排序
 * </p>
 */
public class Test02SelectSort {
    @Test
    public void test01() {
        //  int[] array = {7, 20, 2, 3, 8, 12, 11};
        int[] array = {8, 2, 1, 3, 7, 10, -1};
        selectSort(array);
        // selectSort2(array);
    }

    /**
     * 选择排序
     *
     * @param array
     */
    public void selectSort(int[] array) {
        int length = array.length;
        int temp;
        for (int i = 0; i < length - 1; i++) {
            for (int j = i + 1; j < length; j++) {
                if (array[i] > array[j]) {
                    temp = array[i];
                    array[i] = array[j];
                    array[j] = temp;
                }
            }
            System.out.printf("\n 第:%d 轮,array=%s", (i + 1), Arrays.toString(array));
        }
    }

    /**
     * 选择排序(减少交换次数)
     *
     * @param array
     */
    public void selectSort2(int[] array) {
        int length = array.length;
        int temp;
        for (int i = 0; i < length - 1; i++) {
            int minIndex = i;
            int minNum = array[i];
            for (int j = i + 1; j < length; j++) {
                if (minNum > array[j]) {
                    // 循环找到最小值
                    minNum = array[j];
                    minIndex = j;
                }
            }
            // 检查是否有交换
            if (i != minIndex) {
                array[minIndex] = array[i];
                array[i] = minNum;
            }
            System.out.printf("\n 第:%d 轮,array=%s", (i + 1), Arrays.toString(array));
        }
    }
}
复制代码

 

2.3.插入排序

复制代码
package com.ldp.structure.demo02;

import org.junit.Test;

import java.util.Arrays;

/**
 * @create 04/16 8:30
 * @description <p>
 * 插入排序
 * 思维:与打扑克.摸牌的思维一样
 * </p>
 */
public class Test03InsertSort {
    /**
     * 测试排序入口
     */
    @Test
    public void insertSort() {
        int[] array = {100, 80, 60, 70, -1};
        System.out.printf("\n 第 %d 轮排序:%s ", 0, Arrays.toString(array));
        int length = array.length;
        for (int i = 1; i < length; i++) {
            int insertData = array[i];// insertData 表示待插入的值
            int insertIndex = i - 1;// insertIndex 表示待插入的下标
            // array[insertIndex] : 表示待插入下标的值
            while (insertIndex >= 0 && insertData < array[insertIndex]) {
                // 如果待插入下标的值(array[insertIndex])比待插入的值(insertData)大,这把待插入位置的值往前移动
                array[insertIndex + 1] = array[insertIndex];
                insertIndex--;  // 检查下一个下标值
            }
            if (insertIndex != (i - 1)) {
                array[insertIndex + 1] = insertData; // 为什么要加1,因为while执行完成前-1了
            }
            System.out.printf("\n 第 %d 轮排序:%s ", i, Arrays.toString(array));
        }
    }

    /**
     * 插入排序思路分析
     */
    @Test
    public void insertSortAnalysis() {
        int[] array = {100, 80, 60, 70, -1};
        System.out.printf("\n 第 0 轮排序: " + Arrays.toString(array));
        // 第 1 轮排序: {100}(80, 60, 70, -1) 把80找到一个合适的位置
        int insertData = array[1];// insertData 表示待插入的值
        int insertIndex = 1 - 1;// insertIndex 表示待插入的下标
        // array[insertIndex] : 表示待插入下标的值
        while (insertIndex >= 0 && insertData < array[insertIndex]) {
            // 如果待插入下标的值(array[insertIndex])比待插入的值(insertData)大,这把待插入位置的值往前移动
            array[insertIndex + 1] = array[insertIndex];
            insertIndex--;  // 检查下一个下标值
        }
        if (insertIndex != (1 - 1)) {
            array[insertIndex + 1] = insertData; // 为什么要加1,因为while执行完成前-1了
        }
        System.out.printf("\n 第 1 轮排序: " + Arrays.toString(array));
        // 第 2 轮排序: {80,100}(60, 70, -1) 把60找到一个合适的位置
        insertData = array[2];// insertData 表示待插入的值
        insertIndex = 2 - 1;// insertIndex 表示待插入的下标
        // array[insertIndex] : 表示待插入下标的值
        while (insertIndex >= 0 && insertData < array[insertIndex]) {
            // 如果待插入下标的值(array[insertIndex])比待插入的值(insertData)大,这把待插入位置的值往前移动
            array[insertIndex + 1] = array[insertIndex];
            insertIndex--;  // 检查下一个下标值
        }
        if (insertIndex != (2 - 1)) {
            array[insertIndex + 1] = insertData; // 为什么要加1,因为while执行完成前-1了
        }
        System.out.printf("\n 第 2 轮排序: " + Arrays.toString(array));
        // 第 3 轮排序: {100,80, 60}( 70, -1) 把70找到一个合适的位置
        insertData = array[3];// insertData 表示待插入的值
        insertIndex = 3 - 1;// insertIndex 表示待插入的下标
        // array[insertIndex] : 表示待插入下标的值
        while (insertIndex >= 0 && insertData < array[insertIndex]) {
            // 如果待插入下标的值(array[insertIndex])比待插入的值(insertData)大,这把待插入位置的值往前移动
            array[insertIndex + 1] = array[insertIndex];
            insertIndex--;  // 检查下一个下标值
        }
        if (insertIndex != (3 - 1)) {
            array[insertIndex + 1] = insertData; // 为什么要加1,因为while执行完成前-1了
        }
        System.out.printf("\n 第 3 轮排序: " + Arrays.toString(array));
        // 第 4 轮排序: {100,80, 60, 70}( -1) 把-1找到一个合适的位置
        insertData = array[4];// insertData 表示待插入的值
        insertIndex = 4 - 1;// insertIndex 表示待插入的下标
        // array[insertIndex] : 表示待插入下标的值
        while (insertIndex >= 0 && insertData < array[insertIndex]) {
            // 如果待插入下标的值(array[insertIndex])比待插入的值(insertData)大,这把待插入位置的值往前移动
            array[insertIndex + 1] = array[insertIndex];
            insertIndex--;  // 检查下一个下标值
        }
        if (insertIndex != (4 - 1)) {
            array[insertIndex + 1] = insertData; // 为什么要加1,因为while执行完成前-1了
        }
        System.out.printf("\n 第 4 轮排序: " + Arrays.toString(array));
    }
}
复制代码

 

2.4.希尔排序

复制代码
package com.ldp.structure.demo02;

import org.junit.Test;

import java.util.Arrays;

/**
 * @create 04/16 11:12
 * @description 希尔排序
 */
public class Test04ShellSort {
    /**
     * 逐步分析
     * 算法推导
     */
    @Test
    public void test01() {
        int[] array = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0};
        System.out.printf("\n 第 %d 轮排序:%s ", 0, Arrays.toString(array));
        int length = array.length;
        for (int i = 5; i < length; i++) {
            for (int j = i - 5; j >= 0; j -= 5) { // 相当于对分组后的每一组排序
                if (array[j] > array[j + 5]) {// 左边的比右边的大,就交换位置
                    int temp = array[j];
                    array[j] = array[j + 5];
                    array[j + 5] = temp;
                }
            }
        }
        System.out.printf("\n 第 %d 轮排序:%s ", 1, Arrays.toString(array));//第 1 轮排序:[3, 5, 1, 6, 0, 8, 9, 4, 7, 2]
        for (int i = 2; i < length; i++) {
            for (int j = i - 2; j >= 0; j -= 2) { // 相当于对分组后的每一组排序
                if (array[j] > array[j + 2]) {// 左边的比右边的大,就交换位置
                    int temp = array[j];
                    array[j] = array[j + 2];
                    array[j + 2] = temp;
                }
            }
        }
        System.out.printf("\n 第 %d 轮排序:%s ", 2, Arrays.toString(array));//第 2 轮排序:[0, 2, 1, 4, 3, 5, 7, 6, 9, 8]
        for (int i = 1; i < length; i++) {
            for (int j = i - 1; j >= 0; j -= 1) { // 相当于对分组后的每一组排序
                if (array[j] > array[j + 1]) {// 左边的比右边的大,就交换位置
                    int temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                }
            }
        }
        System.out.printf("\n 第 %d 轮排序:%s ", 3, Arrays.toString(array));//第 2 轮排序:[0, 2, 1, 4, 3, 5, 7, 6, 9, 8]
    }

    /**
     * 希尔排序
     * 分组+冒泡的方式
     */
    @Test
    public void test02() {
        //int[] array = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0};
        int[] array = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0, -10, 18, 17, 7};
        System.out.printf("\n 第 %d 轮排序:%s ", 0, Arrays.toString(array));
        int length = array.length;
        int count = 0;
        for (int step = length / 2; step > 0; step /= 2) {
            for (int i = step; i < length; i++) {
                for (int j = i - step; j >= 0; j -= step) { // 相当于对分组后的每一组排序
                    if (array[j] > array[j + step]) {// 左边的比右边的大,就交换位置
                        int temp = array[j];
                        array[j] = array[j + step];
                        array[j + step] = temp;
                    }
                }
            }
            System.out.printf("\n 第 %d 轮排序:%s ", (++count), Arrays.toString(array));//第 1 轮排序:[3, 5, 1, 6, 0, 8, 9, 4, 7, 2]
        }
    }

    /**
     * 希尔排序
     * 分组+插入的方式
     */
    @Test
    public void test03() {
        // int[] array = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0};
        int[] array = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0, -10, 18, 17, 7};
        System.out.printf("\n 第 %d 轮排序:%s ", 0, Arrays.toString(array));
        int length = array.length;
        int count = 0;
        for (int step = length / 2; step > 0; step /= 2) {
            for (int i = step; i < length; i++) {
                // 内部是插入排序的思维
                int insertData = array[i];// insertData 表示待插入的值
                int insertIndex = i - step;// insertIndex 表示待插入的下标
                while (insertIndex >= 0 && insertData < array[insertIndex]) {
                    array[insertIndex + step] = array[insertIndex];
                    insertIndex = insertIndex - step;
                }
                array[insertIndex + step] = insertData;
            }
            System.out.printf("\n 第 %d 轮排序:%s ", (++count), Arrays.toString(array));//第 1 轮排序:[3, 5, 1, 6, 0, 8, 9, 4, 7, 2]
        }
    }
}
复制代码

 

2.5.快速排序

复制代码
package com.ldp.structure.demo02;

import org.junit.Test;

import java.util.Arrays;

/**
 * @create 04/16 5:48
 * @description <p>
 * 快速排序
 * </p>
 */
public class Test05FastSort {
    @Test
    public void test01() {
        int[] array = {80, -9, 1, 0, 30, -5, 4};
        fastSort(array, 0, array.length - 1);
    }

    /**
     * 快速排序
     *
     * @param array      需要排序的数组
     * @param leftIndex  最左边的下标
     * @param rightIndex 最右边的下标
     */
    public void fastSort(int[] array, int leftIndex, int rightIndex) {
        // 临时值
        int leftTempIndex = leftIndex;
        int rightTempIndex = rightIndex;
        // 中心下标的值
        int centerValue = array[(leftIndex + rightIndex) / 2]; // 0
        // 用于交换的临时变量
        int temp;
        // 将比中心值小的放到左边,比中心值大的放到右边
        // 左下标-->>>   中心    <<<---右下标
        while (leftTempIndex < rightTempIndex) {
            // 在中心值左边找,如果比中心值大就退出,说明该值不应在左边 {80, -9, 1, 0, 30, -5, 4} 当leftTempIndex=0时退出循环
            while (array[leftTempIndex] < centerValue) {
                leftTempIndex++;
            }
            //在中心值右边找,如果右边的值小于中心值,说明该值不应在右边 {80, -9, 1, 0, 30, -5, 4} 当rightTempIndex=1时退出循环
            while (array[rightTempIndex] > centerValue) {
                rightTempIndex--;
            }
            // 当leftTempIndex>=rightTempIndex,说明大于中心值的都已经在右边了,小于中心值的都已经在左边了
            if (leftTempIndex >= rightTempIndex) {
                break;
            }
            // 交换
            temp = array[leftTempIndex];
            array[leftTempIndex] = array[rightTempIndex];
            array[rightTempIndex] = temp;
            // 如果交换完成后,array[leftTempIndex]==centerValue,右下标左移动一下
            if (array[leftTempIndex] == centerValue) {
                rightTempIndex--;
            }
            // 如果交换完成后,array[rightTempIndex]==centerValue,左下标右移动一下
            if (array[rightTempIndex] == centerValue) {
                leftTempIndex++;
            }
        }
        // 循环完成后,左边的都是小于中心值的,右边的都是大于中心值的
        System.out.println("左右是否以分开==>" + Arrays.toString(array));
        // 始终保持,左右下标不相等
        if (leftTempIndex == rightTempIndex) {
            leftTempIndex++;
            rightTempIndex--;
        }
        // 递归左侧 ,若leftIndex<leftTempIndex,说明上面的执行中左下标发生了右移动
        if (leftIndex < rightTempIndex) {
            fastSort(array, leftIndex, rightTempIndex);
        }
        // 递归右侧
        if (rightIndex > leftTempIndex) {
            fastSort(array, leftTempIndex, rightIndex);
        }
    }
}
复制代码

 

2.6.归并排序

复制代码
package com.ldp.structure.demo02;

import org.junit.Test;

import java.util.Arrays;

/**
 * @create 04/16 10:06
 * @description <p>
 * 归并排序
 * </p>
 */
public class Test06MergeSort {
    // 统计
    int count = 0;

    @Test
    public void test01() {
        int[] array = {9, 5, 6, 8, 2, 4, 7, 3};
        int[] tempArray = new int[array.length];
        branchToMerge(array, 0, array.length - 1, tempArray);
        System.out.println("==>" + Arrays.toString(array));
    }

    /**
     * 拆分+合并数组
     *
     * @param array
     * @param left
     * @param right
     * @param tempArray
     */
    public void branchToMerge(int[] array, int left, int right, int[] tempArray) {
        if (left < right) {
            int middle = (left + right) / 2;
            // 递归左边
            branchToMerge(array, left, middle, tempArray);
            // 递归右边
            branchToMerge(array, middle + 1, right, tempArray);
            // 合并
            merge(array, left, middle, right, tempArray);
        }
    }

    /**
     * 按顺序合并数组
     *
     * @param array     排序的数组
     * @param left      左边下标
     * @param middle    中间下标
     * @param right     右侧下标
     * @param tempArray 临时中间数组
     */
    public void merge(int[] array, int left, int middle, int right, int[] tempArray) {
        int i = left;// 左侧初始化下标
        int j = middle + 1;// 右侧初始化下标
        int t = 0;// 临时数组下标
        //1. 按顺序把数组中的左右两边数据填充到临时数组中
        while (i <= middle && j <= right) {
            if (array[i] <= array[j]) {
                // 如果左边数小,就把左边的数填充到临时数组
                tempArray[t] = array[i];
                i++;
                t++;
            } else {
                // 否则将右侧数组填充到临时数组
                tempArray[t] = array[j];
                t++;
                j++;
            }
        }
        //2. 把剩下的数组中的数字填充到临时数组中
        while (i <= middle) {// 拷贝左边
            tempArray[t] = array[i];
            t++;
            i++;
        }
        while (j <= right) {
            tempArray[t] = array[j];
            t++;
            j++;
        }
        //3. 把已经排序好的临时数组中数组依次复制到原来的数组中
        t = 0;
        int tempLeftIndex = left;
        while (tempLeftIndex <= right) {
            array[tempLeftIndex] = tempArray[t];
            t++;
            tempLeftIndex++;
        }
    }
}
复制代码

 

2.7.基数排序

复制代码
package com.ldp.structure.demo02;

import org.junit.Test;

import java.util.Arrays;

/**
 * @create 04/17 7:56
 * @description <p>
 * 基数排序
 * </p>
 */
public class Test07BaseSort {
    @Test
    public void test01() {
        int[] array = {80, 2, 108, 20, 148, 10, 527, 7, 45};
        // baseSortAnalysis(array);
        baseSort(array);
    }

    /**
     * 基数排序 推导
     *
     * @param array
     */
    public void baseSortAnalysis(int[] array) {
        System.out.println("第 0 轮:" + Arrays.toString(array));
        int length = array.length;
        // 循环将数据放入桶中
        // 定义10个桶
        int[][] bucketArray = new int[10][length];
        // 定义一个记录桶中放入了多少个数的数组
        // bucketCountArray[0]=X,表示第一个桶放入了X个数据,bucketCountArray[1]=Y,表示第二个桶放入了Y个数据
        int[] bucketCountArray = new int[10];
        // 第一轮存放
        for (int i = 0; i < length; i++) {
            // 取个位数
            int n = array[i] % 10;
            bucketArray[n][bucketCountArray[n]] = array[i];
            // 统计数据量加一
            bucketCountArray[n]++;
        }
        int t = 0;
        // 第一轮取
        for (int i = 0; i < 10; i++) {
            // 判断桶中是否有数据
            for (int j = 0; j < bucketCountArray[i]; j++) {
                array[t] = bucketArray[i][j];
                t++;
            }
            // 将统计数量的桶中计算置为0
            bucketCountArray[i] = 0;
        }
        System.out.println("第 1 轮:" + Arrays.toString(array));

        // 第二轮存放
        for (int i = 0; i < length; i++) {
            // 取个位数
            int n = array[i] / 10 % 10;
            bucketArray[n][bucketCountArray[n]] = array[i];
            // 统计数据量加一
            bucketCountArray[n]++;
        }
        t = 0;
        //
        for (int i = 0; i < 10; i++) {
            // 判断桶中是否有数据
            for (int j = 0; j < bucketCountArray[i]; j++) {
                array[t] = bucketArray[i][j];
                t++;
            }
            // 将统计数量的桶中计算置为0
            bucketCountArray[i] = 0;
        }
        System.out.println("第 2 轮:" + Arrays.toString(array));

        // 第三轮存放
        for (int i = 0; i < length; i++) {
            // 取个位数
            int n = array[i] / 100 % 10;
            bucketArray[n][bucketCountArray[n]] = array[i];
            // 统计数据量加一
            bucketCountArray[n]++;
        }
        t = 0;
        //
        for (int i = 0; i < 10; i++) {
            // 判断桶中是否有数据
            for (int j = 0; j < bucketCountArray[i]; j++) {
                array[t] = bucketArray[i][j];
                t++;
            }
            // 将统计数量的桶中计算置为0
            bucketCountArray[i] = 0;
        }
        System.out.println("第 3 轮:" + Arrays.toString(array));
    }

    /**
     * 基数排序
     *
     * @param array
     */
    public void baseSort(int[] array) {
        System.out.println("第 0 轮:" + Arrays.toString(array));
        // 1.寻找最大值
        int length = array.length;
        int max = array[0];
        for (int i = 1; i < length; i++) {
            if (array[i] > max) {
                max = array[i];
            }
        }
        // 2.求最大值的长度
        int maxLength = (max + "").length();
        // 3.循环将数据放入桶中
        // 定义10个桶
        int[][] bucketArray = new int[10][length];
        // 定义一个记录桶中放入了多少个数的数组
        // bucketCountArray[0]=X,表示第一个桶放入了X个数据,bucketCountArray[1]=Y,表示第二个桶放入了Y个数据
        int[] bucketCountArray = new int[10];
        // m表示个,十,百每一轮的循环
        // s是一个辅助取个,十,百数字的值, int n = array[i] / s % 10;
        for (int m = 0, s = 1; m < maxLength; m++, s *= 10) {
            for (int i = 0; i < length; i++) {
                // 取个,十,百位数
                int n = array[i] / s % 10;
                bucketArray[n][bucketCountArray[n]] = array[i];
                // 统计数据量加一
                bucketCountArray[n]++;
            }
            int t = 0;
            // 第一轮取
            for (int i = 0; i < 10; i++) {
                // 判断桶中是否有数据
                for (int j = 0; j < bucketCountArray[i]; j++) {
                    array[t] = bucketArray[i][j];
                    t++;
                }
                // 将统计数量的桶中计算置为0
                bucketCountArray[i] = 0;
            }
            System.out.println("第 " + (m + 1) + " 轮:" + Arrays.toString(array));
        }
    }
}
复制代码

 

2.8.堆排序

完美

posted @   不停学  阅读(150)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
点击右上角即可分享
微信分享提示