Java 基础

Java 常用排序算法

2022-01-11  本文已影响0人  yjtuuige

概述:

经常用到的十大排序,如图所示:

按照比较类,和非比较类,又可以分为:

排序算法还可以分为:内部排序和外部排序。

一、冒泡排序(Bubble Sort)

排序步骤:

  1. 比较相邻的两个元素(从索引 0 开始)。如果第一个 arr[i] 比第二个 arr[i+1] 大,就进行交换;
  2. 对每一对相邻元素,做同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
  3. 针对所有的元素,重复以上的步骤,除了最后一个;
  4. 重复步骤 1~3,直到排序完成。
冒泡排序
package com.xxx.sort;

import java.util.Arrays;

/**
 * Description:冒泡排序
 */
public class BubbleSort {
    public static void main(String[] args) {
        int[] array = {12, 63, 1, 95, 44, 62, 78};
        bubbleSort(array);
        System.out.println(Arrays.toString(array));
    }
    // 冒泡排序
    private static void bubbleSort(int[] array) {
        if (array == null || array.length <= 1) {
            return;
        }

        int length = array.length;
        // 外层循环,判断要走多少次;
        for (int j = 0; j < length - 1; j++) {
            // 通过flag 标识位,减少没有意义的比较
            boolean flag = false;
            // 内层循环:每次比较的次数(每次循环时,去掉未尾最大值,数组长度-j)
            // (array.length - 1) 防止索引越界,(array.length - 1 - i) 减少比较次数
            for (int i = 0; i < length - 1 - j; i++) {
                // 内层循环一次,获取一个最大值
                // 内层循环,升序(如果前一个值比后一个值大,则交换)
                if (array[i] > array[i + 1]) {
                    swap(array, i, i + 1);
                    flag = true;
                }
            }

            // 如果没有交换过元素,则已经有序,不再进行接下来的比较
            if (flag = false) {
                break;
            }
        }
    }

    // 自定义方法:交换元素位置
    private static void swap(int[] array, int a, int b) {
        int temp = array[a];
        array[a] = array[b];
        array[b] = temp;
    }
}

二、选择排序(Selection Sort)

排序步骤:

  1. 首先,在未排序序列中,找到最小(大)元素,存放到排序序列的起始位置。
  2. 再从剩余未排序元素中,继续寻找最小(大)元素,然后放到未排序序列的起始位置。
  3. 重复第二步,直到所有元素均排序完毕。
选择排序
package com.xxx.sort;

import java.util.Arrays;

/**
 * Description: 选择排序
 */
public class SelectionSort {
    public static void main(String[] args) {
        int[] array = {12, 63, 1, 95, 44, 62, 78, 1, 12, 0, -5};
        selectionSort(array);
        System.out.println(Arrays.toString(array));
    }

    private static void selectionSort(int[] array) {
        if (array == null || array.length <= 1) {
            return;
        }

        int length = array.length;
        // 外层循环:从 0 索引开始
        for (int i = 0; i < length - 1; i++) {
            // 保存最小数的索引(从索引 0 开始)
            int minIndex = i;
            // 内层循环:从 0 + 1 索引开始(自身不用比较)
            for (int j = i + 1; j < length; j++) {
                // 查找最小数位置,并标记为最小数的索引
                if (array[minIndex] > array[j]) {
                    minIndex = j;
                }
            }
            // 内循环查找的最小值,与本次循环的开始值 array[i],交换元素位置
            // (如果 minIndex 未改变,说明此数为最小值,不执行交换)
            if (i != minIndex) {
                swap(array, minIndex, i);
            }
            //说明:将i前面的数据看成一个排好的队列,i后面的看成一个无序队列。
            // 每次只需要找无序的最小值,做替换
        }
    }

    private static void swap(int[] array, int a, int b) {
        int temp = array[a];
        array[a] = array[b];
        array[b] = temp;
    }
}

三、插入排序(Insertion Sort)

排序步骤:

插入排序
package com.xxx.sort;

import java.util.Arrays;

/**
 * Description: 插入排序
 */
public class InsertionSort {
    public static void main(String[] args) {
        int[] array = {12, 63, 1, 95, 44, 62, 78, 1, 12, 0, -5};
        insertionSort(array);
        System.out.println(Arrays.toString(array));
    }

    // 插入排序
    private static void insertionSort(int[] array) {
        if (array == null || array.length <= 1) {
            return;
        }
        // 直接插入排序:从 1 索引处开始,将后面的元素,
        // 插入之前的有序列表中,使之保持有序
        // 外层循环:定义轮次(从第二个元素开始)
        for (int i = 1; i < array.length; i++) {
            // 内层循环:进行比较插入
            // j--:将交换后的值,可以与前面的值进行再次比较,直到找到合适位置
            for (int j = i; j > 0; j--) {
                // 如果后边小,前边大,则交换位置
                if (array[j] < array[j - 1]) {
                    swap(array, j, j - 1);
                }
            }
        }
        // 另一种:
        /*for (int i = 1; i < array.length; i++) {
            int j = i;
            while (j > 0 && array[j] < array[j - 1]) {
                swap(array, j, j - 1);
                j--;
            }
        }*/

    }

    private static void swap(int[] array, int a, int b) {
        int temp = array[a];
        array[a] = array[b];
        array[b] = temp;
    }
}

折半插入排序

package com.xxx.sort;

import java.util.Arrays;

/**
 * 折半插入排序
 */
public class BinaryInsertSort {
    public static void main(String[] args) {
        int[] array = {12, 63, 1, 95, 44, 62, 78, 1, 12, 0, -5};
        binaryInsertSort(array);
        System.out.println(Arrays.toString(array));
    }

    public static void binaryInsertSort(int[] array) {
        int len = array.length;
        if (len == 0 || len == 1) return;
        // low high mid用于折半查找
        int low, high, mid;
        for (int i = 1; i < array.length; i++) {
            low = 0;
            high = i - 1;
            while (low <= high) {
                // (high+low)/2 这样的写法可能会超出int的表示范围
                mid = low + ((high - low) >> 1);
                if (array[mid] < array[i])
                    low = mid + 1;
                else
                    high = mid - 1;
            }
            // high + 1就是插入的位置
            int temp = array[i];
            // 找到插入位置后,对元素进行挪动
            for (int j = i - 1; j > high; j--)
                array[j + 1] = array[j];
            // 将待排序的元素插入找到的位置
            array[high + 1] = temp;
        }
    }
}

四、希尔排序(Shell Sort)

实现步骤:

  1. 选 increment(增量),划分逻辑分组,组内进行直接插入排序。
  2. 不断缩小 increment(增量),继续组内进行插入排序。
  3. 直到 increment(增量)=1,在包含所有元素的序列内进行直接插入排序。
希尔排序
package com.xxx.sort;

import java.util.Arrays;

/**
 * Description: 希尔排序
 */
public class ShellSort {
    public static void main(String[] args) {
        int[] array = {12, 63, 1, 95, 44, 62, 78, 1, 12, 0, -5};
        shellSort(array);
        System.out.println(Arrays.toString(array));
    }

    private static void shellSort(int[] array) {
        if (array == null || array.length <= 1) {
            return;
        }
        // 设置增量值
        int increment = 1;
        while (increment <= array.length / 3) {
            // (克努特序列)选取第一次增量:h=h*3+1,设置序列间隔
            increment = increment * 3 + 1;
        }
        // 遍历增量值:按(克努特序列)值递减,直到增量值为1
        for (int h = increment; h > 0; h = (h - 1) / 3) {
            // 插入排序:第一个索引为增量值
            for (int i = h; i < array.length; i++) {
                // 内循环:按增量值,比较插入
                for (int j = i; j > h - 1; j -= h) {
                    if (array[j] < array[j - h]) {
                        swap(array, j, j - h);
                    }
                }
            }
        }
    }

    private static void swap(int[] array, int a, int b) {
        int temp = array[a];
        array[a] = array[b];
        array[b] = temp;
    }
}

五、快速排序(Quick Sort)

算法描述:

快速排序

代码描述:

  1. i = L; j = R; 将基准数挖出,形成第一个坑 a[i]
  2. j--,由后向前,找比它小的数,找到后,挖出此数填到前一个坑 a[i] 中。
  3. i++,由前向后,找比它大的数,找到后,也挖出此数填到前一个坑 a[j] 中。
  4. 再重复执行 2,3 二步,直到 i==j,将基准数填入 a[i]中。
package com.xxx.sort;

import java.util.Arrays;

/**
 * Description: 快速排序
 */
public class QuickSort {
    public static void main(String[] args) {
        int[] array = {12, 63, 1, 95, 44, 62, 78, 1, 12, 0, -5};
        quickSort(array, 0, array.length - 1);
        System.out.println(Arrays.toString(array));
    }

    private static void quickSort(int[] array, int low, int high) {
        if (low < high) {
            // 获取基准数据的索引位置
            int index = getIndex(array, low, high);
            // 递归:对基准数左边排序
            quickSort(array, low, index - 1);
            // 递归:对基准数右边排序
            quickSort(array, index + 1, high);
        }
    }

    // 获取基准数据的索引位置,并将大于基准数的值移动到右侧,小于基准值的移动到左侧
    private static int getIndex(int[] array, int low, int high) {
        // 左边索引值
        int i = low;
        // 右边索引值
        int j = high;
        // 1.取第一个元素为基准值(挖坑)
        int temp = array[i];
        while (i < j) {
            // 2.从右向左(后往前)查找比基准值小的数,挖出此数,填到前一个坑中
            while (i < j && array[j] > temp) {
                // 索引向左移(前),直到找到比基准值小的数
                j--;
            }
            if (i < j) {
                // 将找到的比基准值小的数,添加到基准值位置
                array[i] = array[j];
                // 将左索引+1:从左向右查找时的索引
                i++;
            }
            // 3.从左向右(前往后)查找比基准值大的数,挖出此数,填到前一个坑中
            while (i < j && array[i] < temp) {
                // 索引向右移(后),直到找到比基准值大的数
                i++;
            }
            if (i < j) {
                // 将找到的比基准值小的数,添加到基准值位置
                array[j] = array[i];
                // 将右索引-1:从右向左查找时的索引
                j--;
            }
        }
        // 3.跳出循环时 i 和 j 相等,为第一个基准值的位置,将其存入
        array[i] = temp;
        // 4.返回索引值(i,j 都可以)
        return i;
    }

    private static void swap(int[] array, int a, int b) {
        int temp = array[a];
        array[a] = array[b];
        array[b] = temp;
    }
}

六、归并排序(Merge Sort)

基本思路:(递归方式)

归并排序

算法思路

代码实现

package com.xxx.sort;

import java.util.Arrays;

/**
 * Description: 归并排序
 */
public class MergeSort {
    public static void main(String[] args) {
        int[] array = {12, 63, 1, 95, 44, 62, 78, 1, 12, 0, -5};
        mergeSort(array, 0, array.length - 1);
        System.out.println(Arrays.toString(array));
    }

    /**
     * @param array 初始数组
     * @param start 开始分组
     * @param end   结束分组
     * @return
     */
    // 拆分
    private static int[] mergeSort(int[] array, int start, int end) {
        // 当 start==end 时,此时分组里只有一个元素,所以这是临界点
        if (start < end) {
            // 分成左右两个分组,再进行递归
            int mid = (start + end) / 2;
            // 左侧分组
            mergeSort(array, start, mid);
            // 右侧分组
            mergeSort(array, mid + 1, end);
            // 递归之后,再归并一个大组
            merge(array, start, mid, end);
        }
        return array;
    }

    // 归并方法
    private static void merge(int[] array, int start, int mid, int end) {
        // 定义临时数组,长度为(end-start+1)
        int[] temp = new int[end - start + 1];
        // 左边起始数组索引
        int i = start;
        // 右边起始数组索引
        int j = mid + 1;
        // 临时数组索引
        int index = 0;
        // 合并序列:比较两个数组元素的大小,存入临时数组
        // 每次存入后,对应的索引值 +1
        while (i <= mid && j <= end) {
            // 将较小元素放入临时数组
            if (array[i] <= array[j]) {
                temp[index] = array[i];
                i++;
            } else {
                temp[index] = array[j];
                j++;
            }
            index++;
        }
        // 处理剩余元素
        // 左边剩余元素
        while (i <= mid) {
            temp[index] = array[i];
            i++;
            index++;
        }
        // 右边剩余元素
        while (j <= end) {
            temp[index] = array[j];
            j++;
            index++;
        }
        // 将临时数组中的元素,覆盖到原数组中
        for (int k = 0; k < temp.length; k++) {
            array[start + k] = temp[k];
        }
    }
}

迭代法

package com.xxx.sort;

import java.util.Arrays;

/**
 * Description: 归并排序(非递归方式)
 */
public class MergeSort02 {
    public static void main(String[] args) {
        int[] array = {12, 63, 1, 95, 44, 62, 78, 1, 12, 0, -5};
        mergeSort(array);
        System.out.println(Arrays.toString(array));
    }

    public static void mergeSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        int N = arr.length;
        // mergeSize代表每次合并时,一半(可以理解为左侧)数据量的大小
        int mergeSize = 1;
        while (mergeSize < N) {
            int L = 0;
            while (L < N) {
                // 从L到M位置的数据就是当前合并部分的左侧数据大小,数据量为mergeSize
                int M = L + mergeSize - 1;
                // 表示当前要合并的数据量凑不够本次合并的左侧部分,比如本次要合并的数据量
                // 为8,则左侧数据量为4,但剩余未合并的数只有3个了,则这三个本次不用再
                // 合并,因为这三个数肯定在上次合并时已经有序了
                if (M >= N) {
                    break;
                }
                // 上面的过程是寻找左侧数据的过程,即:L...M,接下来要找右侧数据。此时
                // 就要分情况了。为什么呢?正常情况下右侧数据的边界是从M+1到M + mergeSize,
                // 但有可能右侧没这么多数据了,右边界实际是N-1,所以右边界应该取这两个
                // 数的最小值(其实就代表实际值)
                int R = Math.min(M + mergeSize, N - 1);
                // 分出了左右边界,接下来就是进行合并了
                merge(arr, L, M, R);
                L = R + 1;
            }
            // 此处的if语句算一个优化语句,不影响功能,防止的是:mergeSize在*2的过程
            // 中超过Integer.MAX_VALUE,出现错误
            if (mergeSize > N / 2) {
                break;
            }
            // 每次合并扩大一倍
            mergeSize = mergeSize * 2;
        }
    }

    public static void merge(int[] arr, int L, int M, int R) {
        // 准备辅助数组,存放排序后的数据
        int[] help = new int[R - L + 1];
        int i = 0;
        // 左侧数据起始位置
        int p1 = L;
        // 右侧数据起始位置
        int p2 = M + 1;
        // 左右两侧都没遍历完,即p1、p2都没越界
        while (p1 <= M && p2 <= R) {
            // 将左右部分的数据进行比较,小的数据存放到辅助数组,
            // 然后help和添加到辅助数组的部分指针(p1或p2)进行右移
            help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
        }
        // 当跳出wile循环,代表左或右某个部分已经遍历完了,然后将未
        // 遍历完的追加到辅助数组尾部,下面的两个while循环只能有一个执行
        while (p1 <= M) {
            help[i++] = arr[p1++];
        }
        while (p2 <= R) {
            help[i++] = arr[p2++];
        }
        // 将辅助数组中的数据追加到原arr数组中
        for (i = 0; i < help.length; i++) {
            arr[L + i] = help[i];
        }
    }
}

七、基数排序(Radix Sort)

实现步骤:

  1. 将所有待比较数值,统一为同样的数位长度,数位较短的数,前面补零。
  2. 从最低位开始,依次进行一次排序。
  3. 依次从最低位排序,一直到最高位排序完成以后, 数列就变成一个有序序列。
基数排序
package com.xxx.sort;

import java.util.Arrays;

/**
 * Description: 基数排序
 */
public class RadixSort {
    public static void main(String[] args) {
        // 基数排序:通过分配再收集的方式排序(负数暂时有问题)
        int[] array = {18, 381, 983, 5, 147, 5915, 1, 927, 465, 4, 1906, 50, 498};
        radixSort(array);
        System.out.println(Arrays.toString(array));
    }

    private static void radixSort(int[] array) {
        // 定义二维数组,放 10 个桶(0-9),每个桶可能存放元素个数
        // (按最大考虑:数组元素都存在一个桶中 array.length )
        int[][] tempArray = new int[10][array.length];
        // 定义统计数组,索引值与桶索引相同(统计第个桶中存储元素个数,
        // 初始值为 0,每存储一个元素,值做一次自增)
        int[] counts = new int[10];
        // 获取最大值
        int max = getMax(array);
        // max 转成字符串,并获取长度
        int len = String.valueOf(max).length();
        // 确定循环轮次(数组最大值的位数)
        // 变量 n 从 1 开始,每次递增 10 ,取个、十、百....位数字
        for (int i = 0, n = 1; i < len; i++, n *= 10) {
            // 遍历数组中的元素
            for (int j = 0; j < array.length; j++) {
                // 获取每个位上的数字(% 10 取余数)
                int ys = array[j] / n % 10;
                // counts[ys]++:桶内存储元素个数自增
                tempArray[ys][counts[ys]++] = array[j];
            }
            // 取出桶中元素
            int index = 0;
            for (int k = 0; k < counts.length; k++) {
                if (counts[k] != 0) {
                    for (int h = 0; h < counts[k]; h++) {
                        // 从桶中取出元素,放回原数组
                        array[index] = tempArray[k][h];
                        index++;
                    }
                    // 清除上一次统计的个数
                    counts[k] = 0;
                }
            }
        }
    }

    // 获取最大值
    private static int getMax(int[] array) {
        int max = array[0];
        //  用后一个元素和前一个元素比较,查找最大值,保存到 max
        for (int i = 1; i < array.length; i++) {
            if (array[i] > max) {
                max = array[i];
            }
        }
        return max;
    }
}
package com.xxx.sort;

import java.util.Arrays;

/**
 * 基数排序
 */
public class RadixSort02 {
    public static void main(String[] args) {
        int[] array = {18, -147, 5915, 365, 260, 1, 927, 2, 465, 4, -1906, 0, 498};
        // 获取数组最大元素
        int maxDigit = getMaxDigit(array);
        // 基数排序
        radixSort(array, maxDigit);
        System.out.println(Arrays.toString(array));
    }

    // 获取最高位数
    private static int getMaxDigit(int[] array) {
        // 获取最大值
        int maxValue = getMaxValue(array);
        return getNumLength(maxValue);
    }

    // 获取最大值
    private static int getMaxValue(int[] array) {
        int maxValue = array[0];
        for (int value : array) {
            if (maxValue < value) {
                maxValue = value;
            }
        }
        return maxValue;
    }

    // 获取元素位数长度(个位:1位  千位:4位)
    private static int getNumLength(long num) {
        // 0 返回 1位
        if (num == 0) {
            return 1;
        }
        int length = 0;
        // 元素/10 取位数
        for (long temp = num; temp != 0; temp /= 10) {
            length++;
        }
        return length;
    }

    // 基数排序
    private static int[] radixSort(int[] array, int maxDigit) {
        int mod = 10;
        int dev = 1;

        for (int i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
            // 考虑负数的情况,这里扩展一倍队列数,其中 [0-9]对应负数,
            // [10-19]对应正数 (bucket + 10)
            int[][] counter = new int[mod * 2][0];

            for (int j = 0; j < array.length; j++) {
                int bucket = ((array[j] % mod) / dev) + mod;
                counter[bucket] = arrayAppend(counter[bucket], array[j]);
            }

            int pos = 0;
            for (int[] bucket : counter) {
                for (int value : bucket) {
                    array[pos++] = value;
                }
            }
        }
        return array;
    }

    /**
     * 自动扩容,并保存数据
     *
     * @param array
     * @param value
     */
    private static int[] arrayAppend(int[] array, int value) {
        array = Arrays.copyOf(array, array.length + 1);
        array[array.length - 1] = value;
        return array;
    }
}

八、堆排序(Heap Sort)

排序步骤:

堆排序
package com.xxx.sort;

import java.util.Arrays;

/**
 * Description:堆排序
 */
public class HeapSort {
    public static void main(String[] args) {
        int[] array = {12, 63, 1, 95, 44, 62, 78, 1, 12, 0, -5};
        // 调整成大顶堆
        // 定义开始调整的位置
        int startIndex = (array.length - 1) / 2;
        // 循环开始调整
        for (int i = startIndex; i >= 0; i--) {
            toMaxHeap(array, array.length, i);
        }
        // 经过上述操作,已经成为大顶堆,把根元素和最后一个元素调换
        for (int i = array.length - 1; i > 0; i--) {
            int temp = array[0];
            array[0] = array[i];
            array[i] = temp;
            // 换完之后,将剩余元素调整成大顶堆
            toMaxHeap(array, i, 0);
        }
        System.out.println(Arrays.toString(array));
    }

    /**
     * Description:调整成大顶堆
     *
     * @param array 要排序的数组
     * @param size  调整的元素个数
     * @param index 开始调整的索引位置
     */
    private static void toMaxHeap(int[] array, int size, int index) {
        // 获取左右子节点的索引
        int leftNodeIndex = index * 2 + 1;
        int rightNodeIndex = index * 2 + 2;
        // 查找最大节点所对应的索引
        int maxIndex = index;
        // leftNodeIndex < size: 防止递归调用后,角标越界
        if (leftNodeIndex < size && array[leftNodeIndex] > array[maxIndex]) {
            maxIndex = leftNodeIndex;
        }
        if (rightNodeIndex < size && array[rightNodeIndex] > array[maxIndex]) {
            maxIndex = rightNodeIndex;
        }
        // 调换位置
        if (maxIndex != index) {
            int temp = array[maxIndex];
            array[maxIndex] = array[index];
            array[index] = temp;
            // 调完之后,可能会影响下面的子树,不再是大顶堆,需要再次调整
            toMaxHeap(array, size, maxIndex);
        }
    }
}

九、计数排序(Counting Sort)

排序步骤

  1. 找出原数组中元素值最大的,记为 max。
  2. 创建一个新数组 count,其长度是 max+1,其元素默认值都为 0。
  3. 遍历原数组中的元素,以原数组中的元素作为 count 数组的索引,以原数组中的元素出现次数,作为 count 数组的元素值。
  4. 创建结果数组 result,起始索引 index。
  5. 遍历 count 数组,找出其中元素值大于 0 的元素,将其对应的索引,作为元素值,填充到 result 数组中去,每处理一次,count 中的该元素值减 1,直到该元素值,不大于 0,依次处理 count 中剩下的元素。
  6. 返回结果数组 result。
计数排序
package com.xxx.sort;

import java.util.Arrays;

/**
 * Description:计数排序
 */
public class CountingSort02 {
    public static void main(String[] args) {
        int[] array = {12, 63, 1, 95, 44, 62, 78, 1, 12, 0, -5};
        int min = getMin(array);
        int max = getMax(array);
        countSort(array, min, max);
        System.out.println(Arrays.toString(array));
    }

    /**
     * @param arr 数组
     * @param min 该数组中的最小值
     * @param max 该数组中的最大值
     * @Title: countSort
     * @Description:计数排序,适用于数字的范围小,排序量大的数组
     * @return: int[]
     */
    public static void countSort(int[] arr, int min, int max) {
        // arr的最小值到最大值之间的数字,即为countArr的下标
        int[] countArr = new int[max - min + 1];
        // 统计arr中每个数字出现的次数
        for (int j = 0; j < arr.length; j++)
            countArr[arr[j] - min]++;
        int[] res = new int[arr.length];
        // 将countArr变为累加数组,这一步主要是实现算法稳定
        for (int m = 1; m < countArr.length; m++)
            countArr[m] += countArr[m - 1];
        // 这一步参见基数排序的过程示意图
        for (int k = arr.length - 1; k >= 0; k--)
            res[--countArr[arr[k] - min]] = arr[k];
        // 将排序好的数组赋值给arr
        for (int i = 0; i < arr.length; i++) {
            arr[i] = res[i];
        }
    }

    // 获取最小值
    private static int getMin(int[] array) {
        int min = array[0];
        for (int i = 0; i < array.length; i++) {
            if (array[i] < min) {
                min = array[i];
            }
        }
        return min;
    }

    // 获取最大值
    private static int getMax(int[] array) {
        int max = array[0];
        for (int i = 0; i < array.length; i++) {
            if (array[i] > max) {
                max = array[i];
            }
        }
        return max;
    }
}

十、桶排序(Bucket Sort)

排序步骤:

  1. 先计算装所有元素,所需要的桶的个数。
  2. 将待排序元素,按大小装到对应的桶中。
  3. 对每个桶内的元素进行排序。
  4. 将所有桶中的元素,按顺序放入到原数组中。
桶排序
package com.xxx.sort;

import java.util.*;

/**
 * Description:桶排序
 */
public class BucketSort {
    public static void main(String[] args) {
        int[] array = {12, 63, 1, 95, 44, 62, 78, 1, 12, 0, -5};
        bucketSort(array);
        System.out.println(Arrays.toString(array));
    }

    /**
     * Description: 桶排序
     *
     * @param array 要排序的数组
     * @return void
     */
    public static void bucketSort(int[] array) {
        if (array == null || array.length <= 1) {
            return;
        }
        // 建立桶,个数和待排序数组长度一样
        int length = array.length;
        LinkedList<Integer>[] bucket = (LinkedList<Integer>[]) new LinkedList[length];
        // 待排序数组中的最大值
        int maxValue = Arrays.stream(array).max().getAsInt();
        // 根据每个元素的值,分配到对应范围的桶中
        for (int i = 0; i < array.length; i++) {
            int index = toBucketIndex(array[i], maxValue, length);
            // 没有桶才建立桶(延时)
            if (bucket[index] == null) {
                bucket[index] = new LinkedList<>();
            }
            // 有桶直接使用
            bucket[index].add(array[i]);
        }
        // 对每个非空的桶排序,排序后顺便存入临时的List,则list中已经有序)
        List<Integer> temp = new ArrayList<>();
        for (int i = 0; i < length; i++) {
            if (bucket[i] != null) {
                Collections.sort(bucket[i]);
                temp.addAll(bucket[i]);
            }
        }

        // 将temp中的数据写入原数组
        for (int i = 0; i < length; i++) {
            array[i] = temp.get(i);
        }
    }

    /**
     * Description: 映射函数,将值转换为应存放到的桶数组的索引
     *
     * @param value
     * @param maxValue
     * @param length
     * @return int
     */
    private static int toBucketIndex(int value, int maxValue, int length) {
        return (value * length) / (maxValue + 1);
    }
}

排序算法比较:

上一篇下一篇

猜你喜欢

热点阅读