vlambda博客
学习文章列表

算法:计数排序与桶排序(一)

    之前,我们讲过几个排序算法——

冒泡排序、快速排序

    我们用了两篇文章来分别阐述冒泡排序的机制和代码:

        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)

    这个新开辟的数组,每个数组里的元素都是一个桶,里面加入的是有几个这样的数字在数组里存在,代码实现如下:

#include <iostream>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-1000double数据,求如何快速排序。

    有明显的范围,这是肯定的,但double数据该如何使用计数排序呢?这就需要我们讲到的“桶排序”了,相比于计数排序的一个个桶像一个个变量,桶排序中的桶更像是一个个列表,关于如何进行桶排序的细节,且听下回分解。

    今天你学废了吗