1.计数排序
1. 简介
计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。其时间复杂度为 O(n + k),需要注意的是,该排序算法并不是一种比较排序算法,其主要步骤如下:
- 找出待排序数组中的最大值
- 统计数组中每个值为v元素出现的次数,存入数组Coun的第v项
- 反向填充目标数组,将每个元素v放在新数组result的第Coun(v)项,每放一个元素就将Coun(v)减去1
从上面步骤可以看出,如果待排序数组中数据的范围非常大,那么用该排序算法就会需要大量的内存空间,但是该排序算法又可以用在基数排序中来处理数据范围很大的数组,由于技术排序是稳定的排序算法,所以最后需要反向填充目标数组,并将Coun(v)减去1。
2. python实现
def countingSort(arr):
# 找出原数组中的最大值
max_val = max(arr)
# 创建一个计数数组
counting = [0]*(max_val+1)
# 计算每个元素出现的次数,并将次数存入计数数组,
for e in arr:
counting[e]+=1
# 然后反向填充目标数组
index = len(arr)-1
for t in range(len(counting)-1,-1,-1):
while counting[t]!=0:
arr[index]=t
counting[t]-=1
index-=1
return arr
3. java实现
public int[] countingSort(int[] arr){
//寻找最大值
int max = arr[0];
for(int i=0;i<arr.length;i++){
if(arr[i]>max)max=arr[i];
}
//新建计数数组
int[] counting = new int[max+1];
//统计每个元素出现的次数
for(int j=0;j<arr.length;j++)counting[arr[j]]++;
//反向填充原数组
int start = arr.length-1;
for(int t=counting.length-1;t>=0;t--){
while(counting[t]>0){
arr[start--]=t;
counting[t]--;
}
}
}
2. 桶排序
1. 简介
桶排序是基数排序的升级版,其利用了函数的映射关系,桶排序的快慢与否就取决于所确定的映射函数,一般来讲,为了使排序的速度的更快,确定映射函数需要满足以下两点:
- 在额外空间充足的情况下,尽量增大桶的数量
- 使用的映射函数能够将输入的 N 个数据均匀的分配到 K 个桶中
一般来讲,当输入的数据都被分到一个桶中时,排序的速度最慢,当输入的数据被均匀的放到所有桶中时,速度最快。
下面的示例中,选取了y=i-min的映射函数,其中y表示计数数组的下标,min表示原数组的最小值,i表示在采用计数排序时的下标,即原数组中的真正的值。
2. python实现
def bucketSort(arr):
# 找出原数组中的最大值
max_val = max(arr)
min_val = min(arr)
# 创建存储映射结果的数组
y_list = [0]*(max_val-min_val+1)
# 计数
for e in arr:
y_list[e-min_val]+=1
# 反向填充数组
t = len(arr)-1
for i in range(len(y_list)-1,-1,-1):
while y_list[t]>0:
arr[t]=i+min_val
t-=1
y_list[t]-=1
3. java实现
public void bucketSort(int[] arr){
if(arr.length>0){
int min_val = arr[0];
int max_val = arr[0];
//找出最大最小值
for(int e:arr){
if(e>max_val)max_val=e;
if(e<min_val)min_val=e;
}
//创建存储映射的数组,并统计每个元素的次数
int[] y_list = new int[max_val-min_val+1];
for(int e:arr)y_list[e-min_val]++;
//反向填充原数组
int start = arr.length-1;
for(int j=y_list.length-1;j>=0;j--){
while(y_list[j]>0){
arr[start--]=j+min_val;
y_list[j]--;
}
}
}
}