基数排序
- 基数排序核心思想是将一个排序规则划分为多个关键字, 根据关键字依次采用稳定性排序.
- 基数排序不属于"分配类排序"(桶排序是一种"分配类排序"), 只是借用了"分配类排序"这种稳定性排序来实现根据关键字排序, 也可以将基数排序根据关键字的排序算法改成其它稳定性排序
分析
底层思想
- 基数排序是将排序规则划分为多个关键字. 先按照低权重的关键字进行排序,然后在之前排序基础上按照高权重的关键字排序.
- 只要每次排序时采用稳定性排序方式,就可以得到最终结果. 原理是采用稳定性排序后, 对之前低权重的排序结果并不会干扰.
时间复杂度
- 基数排序时间复杂度: 因为k(关键字数量)是常数可以看作是O(n).
- 如果采用链式存储结构的时间/空间复杂度变化和计数排序的链式结构很很像,暂不分析.
空间复杂度
稳定性
- 因为基数排序每一轮是根据关键字进行’分配-收集’排序, 这个’分配-收集’过程并不会对值相同的元素进行任何交换.
- 而之后再根据高权重的关键字进行分配-收集排序时是按照上次排序后的结果顺序遍历进行, 所以和上一次相同不会对值相同的元素进行任何交换. 所以没有打破稳定性的操作可能
代码实现
public class RadixSort extends Sort {
public static void main(String[] args) {
RadixSort radixSort = new RadixSort();
radixSort.correctTest(new int[]{11, 1233, 42, 123, 543, 42, 0, 42, 98, 65, 9, 8, 9});
}
@Override
public void sortNums(int[] nums) {
radixSort(nums);
}
public void radixSort(int[] nums) {
int[][] buckets = new int[10][nums.length];
for (int i = 0; i < lengthOfMaxNum(nums); i++) {
int[] bucketSize = new int[10];
for (int j = 0; j < nums.length; j++) {
int whichBucket = getNumInDecimal(nums[j], i + 1);
int bucketIndex = bucketSize[whichBucket];
buckets[whichBucket][bucketIndex] = nums[j];
bucketSize[whichBucket]++;
}
int numsIndex = 0;
for (int j = 0; j < buckets.length; j++) {
for (int k = 0; k < bucketSize[j]; k++) {
nums[numsIndex++] = buckets[j][k];
}
}
}
}
public int lengthOfMaxNum(int[] nums) {
int maxLen = 0;
for (int i = 0; i < nums.length; i++) {
int len = getLengthOfNum(nums[i]);
maxLen = Math.max(maxLen, len);
}
return maxLen;
}
public int getLengthOfNum(int num) {
int len = 0;
while (num != 0) {
len++;
num /= 10;
}
return len;
}
public int getNumInDecimal(int num, int lastIndex) {
int div = 1;
for (int i = 0; i < lastIndex - 1; i++) {
div *= 10;
}
int res = num / div % 10;
return res;
}
}
补充
- 数据结构与算法 C语言版中提到主要用链表来进行基数排序,用链表确实可以减少额外空间.
桶排序
分析
- 也是非比较(分配收集)排序
- 只要在分配和收集过程保证稳定性, 对每个桶的排序采用稳定性排序就可以保证整个桶排序是稳定的
代码实现
public class BucketSort extends Sort {
public static void main(String[] args) {
BucketSort bucketSort = new BucketSort();
bucketSort.correctTest(new int[]{5,4,3,2,1,0});
}
@Override
public void sortNums(int[] nums) {
bucketSort(nums);
}
public void bucketSort(int[] nums) {
int bucketsSize = 5;
int[][] buckets = new int[bucketsSize][nums.length];
int[] bucketSize = new int[bucketsSize];
int[] minMax = getMinMax(nums);
int min = minMax[0];
int max = minMax[1];
int gap = (int)Math.ceil((max - min + 1.0) / (bucketsSize));
for (int i = 0; i < nums.length; i++) {
int whichBucket = (nums[i] - min) / gap;
int bucketIndex = bucketSize[whichBucket];
buckets[whichBucket][bucketIndex] = nums[i];
bucketSize[whichBucket]++;
}
for (int i = 0; i < bucketsSize; i++) {
MergeSort mergeSort = new MergeSort();
if (bucketSize[i] != 0) {
mergeSort.mergeSort(buckets[i], 0, bucketSize[i] - 1);
}
}
int numsIndex = 0;
for (int i = 0; i < bucketsSize; i++) {
for (int j = 0; j < bucketSize[i]; j++) {
nums[numsIndex++] = buckets[i][j];
}
}
}
public int[] getMinMax(int[] nums) {
int min = nums[0];
int max = nums[0];
for (int i = 0; i < nums.length; i++) {
if (nums[i] < min) {
min = nums[i];
}
if (nums[i] > max) {
max = nums[i];
}
}
return new int[]{min, max};
}
}
计数排序
分析
- 作为分配类(非比较)排序的一种. 适用场景很有限, 几乎只能用在可以转换为"小范围数字模型"的场景中
- 虽然下面对正数进行排序无法体现稳定性, 但是在需要实现稳定排序的场景中, 计数排序可在分配和收集过程中做到稳定性, 所以计数排序是稳定性的
代码实现
public class CountSort extends Sort {
public static void main(String[] args) {
CountSort countSort = new CountSort();
countSort.correctTest(null);
}
@Override
public void sortNums(int[] nums) {
countSort(nums);
}
public void countSort(int[] nums) {
int[] minMax = getMinMax(nums);
int min = minMax[0];
int max = minMax[1];
int[] buckets = new int[max - min + 1];
for (int i = 0; i < nums.length; i++) {
int bucketIndex = nums[i] - min;
buckets[bucketIndex]++;
}
int numsIndex = 0;
for (int i = 0; i < buckets.length; i++) {
int num = i + min;
for (int j = 0; j < buckets[i]; j++) {
nums[numsIndex++] = num;
}
}
}
public int[] getMinMax(int[] nums) {
int min = nums[0];
int max = nums[0];
for (int i = 0; i < nums.length; i++) {
if (nums[i] < min) {
min = nums[i];
}
if (nums[i] > max) {
max = nums[i];
}
}
return new int[]{min, max};
}
}
补充说明
- Sort类在博主排序专栏的文章中