你们好,我是Java最全面试题库
的提裤姐,今天这篇是数据结构与算法的第五篇,主要介绍分配排序
;在后续,会沿着第一篇开篇的知识线路一直总结下去,作到日更!若是我能作到百日百更,但愿你也能够跟着百日百刷,一百天养成一个好习惯。java
前面所讨论的排序算法均是基于关键字之间的比较来实现的,而理论上已证实:
对于这样的排序,不管用何方法都至少要进行[lgn]次关键字的比较。由 Stirling公式可知lgn≈nlgn-1.44n+0(lgn),因此基于关键字比较的排序时间下界是O(nlgn)。可是,若不经过比较关键字来排序,则可能突破此下界。分配排序正是如此,排序过程无须比较关键字,而是经过“分配”和“收集”过程来实现排序,它们的时间复杂度可达到线性阶:O(n)
分配排序包括 桶排序
和基数排序
git
桶排序(箱排序 (Bucket sort)),工做的原理是将数组分到有限数量的桶子里。每一个桶子再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序。面试
算法步骤:
假设有一组长度为N的待排关键字序列K[1....n]
。
一、首先将这个序列划分红M个的子区间(桶)。
二、而后基于某种映射函数 ,将待排序列的关键字k映射到第i个桶中(即桶数组B的下标 i) ,那么该关键字k就做为B[i]中的元素(每一个桶B[i]
都是一组大小为N/M
的序列)。
三、对每一个桶B[i]
中的全部元素进行比较排序(可使用快排)。
四、而后依次枚举输出B[0]....B[M]
中的所有内容便是一个有序序列算法
特性:数组
O(n+k)
O(n+k)
稳定
代码实现:数据结构
public class BucketSort { private static final InsertSort insertSort = new InsertSort(); public int[] sort(int[] sourceArray) throws Exception { // 对 arr 进行拷贝,不改变参数内容 int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); return bucketSort(arr, 5); } private int[] bucketSort(int[] arr, int bucketSize) throws Exception { if (arr.length == 0) { return arr; } int minValue = arr[0]; int maxValue = arr[0]; for (int value : arr) { if (value < minValue) { minValue = value; } else if (value > maxValue) { maxValue = value; } } int bucketCount = (int) Math.floor((maxValue - minValue) / bucketSize) + 1; int[][] buckets = new int[bucketCount][0]; // 利用映射函数将数据分配到各个桶中 for (int i = 0; i < arr.length; i++) { int index = (int) Math.floor((arr[i] - minValue) / bucketSize); buckets[index] = arrAppend(buckets[index], arr[i]); } int arrIndex = 0; for (int[] bucket : buckets) { if (bucket.length <= 0) { continue; } // 对每一个桶进行排序,这里使用了插入排序 bucket = insertSort.sort(bucket); for (int value : bucket) { arr[arrIndex++] = value; } } return arr; } /** * 自动扩容,并保存数据 * * @param arr * @param value */ private int[] arrAppend(int[] arr, int value) { arr = Arrays.copyOf(arr, arr.length + 1); arr[arr.length - 1] = value; return arr; } }
基数排序(Radix Sort)是桶排序的扩展,它的基本思想是:
将整数按位数切割成不一样的数字,而后按每一个位数分别比较。 函数
具体作法:将全部待比较数值统一为一样的数位长度,数位较短的数前面补零。而后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成之后, 数列就变成一个有序序列。spa
算法步骤
一、将全部待比较数值(正整数)统一为一样的数位长度,数位较短的数前面补零。
二、从最低位开始,依次进行一次排序。
三、这样从最低位排序一直到最高位排序完成之后, 数列就变成一个有序序列。code
特性:blog
O(n*k)
O(n+k)
稳定
代码实现:
public class RadixSort { public int[] sort(int[] sourceArray) throws Exception { // 对 arr 进行拷贝,不改变参数内容 int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); int maxDigit = getMaxDigit(arr); return radixSort(arr, maxDigit); } /** * 获取最高位数 */ private int getMaxDigit(int[] arr) { int maxValue = getMaxValue(arr); return getNumLenght(maxValue); } private int getMaxValue(int[] arr) { int maxValue = arr[0]; for (int value : arr) { if (maxValue < value) { maxValue = value; } } return maxValue; } protected int getNumLenght(long num) { if (num == 0) { return 1; } int lenght = 0; for (long temp = num; temp != 0; temp /= 10) { lenght++; } return lenght; } private int[] radixSort(int[] arr, 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 < arr.length; j++) { int bucket = ((arr[j] % mod) / dev) + mod; counter[bucket] = arrayAppend(counter[bucket], arr[j]); } int pos = 0; for (int[] bucket : counter) { for (int value : bucket) { arr[pos++] = value; } } } return arr; } /** * 自动扩容,并保存数据 * * @param arr * @param value */ private int[] arrayAppend(int[] arr, int value) { arr = Arrays.copyOf(arr, arr.length + 1); arr[arr.length - 1] = value; return arr; } }