算法:计数排序与桶排序(一)
之前,我们讲过几个排序算法——
冒泡排序、快速排序
我们用了两篇文章来分别阐述冒泡排序的机制和代码:
1.
2.
用了一篇文章来讲述快速排序的实现原理:
1.
它们的特点都是:“基于比较的”
而计算机世界中的排序算法,更是多如牛毛,如选择排序、插入排序、基数排序、猴子排序、珠排序等等,这次,我们要分两篇文章来讲述两个不基于比较的排序算法——计数排序和桶排序。他们利用较大的空间复杂度,来进行排序。它们的相同点是,都利用到了“桶”,而区别是,对桶的利用不同:
/1.计数排序/
计数排序的基本规则是:“根据数组下表来排序”,它适用于数据明显在一定范围内的排序,举个例子[5,5,4,2,3,1](数据范围1-5):
这时候,我们开辟一个长度为(最大值-最小值)+1(即5)的数组,初始值全部设为0:
然后遍历原数组,每遍历到一个元素,把新开辟出的数组下标为[遍历到的值-最小值]的元素加一:
依次遍历所有元素:
之后遍历新开辟的数组,数字为几,就输出几遍(该数组下标+最小值),就比如上面这个案例,就该输出1个(0+1),1个(1+1),1个(2+1),1个(3+1),2个(4+1)。
这个新开辟的数组,每个数组里的元素都是一个桶,里面加入的是有几个这样的数字在数组里存在,代码实现如下:
using namespace std;
int max(int a[],int n){
int max = a[0];
for (int i=0;i<n;i++){
if (a[i]>max){
max = a[i];
}
}
return max;
}
int min(int a[],int n){
int min = a[0];
for (int i=0;i<n;i++){
if (a[i]<min){
min = a[i];
}
}
return min;
}
int main(){
int a[6]={5,5,4,2,3,1};
int max_n=max(a,6),min_n=min(a,6);
int * b = new int[max_n-min_n+1];
for (int i=0;i<6;i++){
b[i]=0;
}
for (int i:a){
cout << i << endl;
b[i-min_n]++;
}
for (int i=0;i<6;i++){
while (b[i]){
cout << i+min_n << " ";
b[i]--;
}
}
delete[] b;
return 0;
}
其中我们用到了一个新用法:
for (变量:数组){
...
}
这其实就相当于python里的遍历,它可以遍历整个数组,而这个变量就会依次是数组里的每个元素。其中,变量也可以用这种写法:
int& i;
这就代表着“定义一个引用变量”,还记得里面讲的引用传递么,这样可以使函数可以修改全局参数的值,这个引用变量也是一样的,代表改变i的值就是改变了数组元素的值。
注意,这种for是c++11新增的特性,而dev-c++默认为c++98,需要在编译设置里调整参数才行:
从上面的文章看来,计数排序似乎没有什么缺点,但请看看下面这道题:
有一些范围为0-1000的double数据,求如何快速排序。
有明显的范围,这是肯定的,但double数据该如何使用计数排序呢?这就需要我们讲到的“桶排序”了,相比于计数排序的一个个桶像一个个变量,桶排序中的桶更像是一个个列表,关于如何进行桶排序的细节,且听下回分解。
今天你学废了吗