码迷,mamicode.com
首页 > 编程语言 > 详细

线性排序之基数排序,桶排序,计数排序

时间:2015-07-20 13:01:28      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:排序

基数排序,桶排序,计数排序是三种线性排序方法,突破了比较排序的O(nlogn)的限制。但是只适用于特定的情况。

基数排序

以下为维基百科的描述:

基数排序 :
将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。

基数排序的方式可以采用LSD(Least significant digital)或MSD(Most significant
digital),LSD的排序方式由键值的最右边开始,而MSD则相反,由键值的最左边开始。

基数排序的效率:
基数排序的时间复杂度是O(k·n),其中n是排序元素个数,k是数字位数。注意这不是说这个时间复杂度一定优于O(n·log(n)),k的大小取决于数字位的选择(比如比特位数),和待排序数据所属数据类型的全集的大小;k决定了进行多少轮处理,而n是每轮处理的操作数目。

以排序n个不同整数来举例,假定这些整数以B为底,这样每位数都有B个不同的数字,k =
logB(N),N是待排序数据类型全集的势。虽然有B个不同的数字,需要B个不同的桶,但在每一轮处理中,判断每个待排序数据项只需要一次计算确定对应数位的值,因此在每一轮处理的时候都需要平均n次操作来把整数放到合适的桶中去,所以就有:

k约等于logB(N) 所以,基数排序的平均时间T就是:

T~= logB(N)·n 其中前一项是一个与输入数据无关的常数,当然该项不一定小于logn

如果考虑和比较排序进行对照,基数排序的形式复杂度虽然不一定更小,但由于不进行比较,因此其基本操作的代价较小,而且在适当选择的B之下,k一般不大于logn,所以基数排序一般要快过基于比较的排序,比如快速排序。

简单来说,基数排序就是从最低位排序一直到最高位排序完成。时间复杂度O(kn) 空间复杂度O(n)

#include <iostream>
using namespace std;
int maxbit(int data[], int n)
{
    int d = 1;
    int max = data[0];
    for (int i = 1; i < n; i++) {  // 找出最大值
        if (data[i] > max)
            max = data[i];
    }
    int radix = 10;
    while (max >= radix) {
        d++;
        radix *= 10;
    }
    return d;
}
void radixsort(int data[], int n) {
    int d = maxbit(data, n); // 求data中最大数具有的位数,决定循环几次
    int *count = new int[10]; // 10 个桶
    int *tmp = new int[n];
    int radix = 1;
    for (int i = 0; i < d; i++) {
        // 每次清零桶计数器
        for (int j = 0; j < 10; j++) 
            count[j] = 0;
        // 统计每个桶中的记录数
        for (int j = 0; j < n; j++) {  
            int k = (data[j] / radix) % 10;
            count[k]++;
        }
        // 分配tmp的位置
        for (int j = 1; j < 10; j++) {
            count[j] = count[j - 1] + count[j]; // count[j] 中 是 j 桶 和比 j 小的桶中的记录数的和
        }
        // 倒着来,将所有桶中记录依次收集到tmp中
        for (int j = n - 1; j >= 0; j--) {
            int k = (data[j] / radix) % 10;
            tmp[count[k] - 1] = data[j];
            count[k]--;
        }
        // 将临时数组复制回data
        for (int j = 0; j < n; j++)
            data[j] = tmp[j];
        radix *= 10;
    }
    delete count;
    delete tmp;
    count = NULL;
    tmp = NULL;
}
int main()
{
    int data[] = { 52,353,458,279,129,152 };
    radixsort(data, 6);
    for (int i = 0; i < 6; i++)
        cout << data[i] << " ";
}

计数排序

维基百科-计数排序
计数排序对于数据范围很大的数组,需要大量时间和内存。适合排序小范围内的整数。
算法的步骤如下:

  • 找出待排序的数组中最大和最小的元素
  • 统计数组中每个值为i的元素出现的次数,存入数组C的第i项
  • 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)
  • 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1
void count_sort(int data[], int n) { 
    int *tmp = new int[n];
    int max = data[0]; // max为data中的最大数
    int min = data[0];
    for (int i = 0; i < n; i++) {
        if (data[i] > max)
            max = data[i];
        if (data[i] < min)
            min = data[i];
    }
    int len = max - min + 1;
    int *count = new int[len];
    for (int i = 0; i < len; i++)
        count[i] = 0;
    for (int i = 0; i < n; i++)
        count[data[i]-min]++;
    for (int j = 1; j < len; j++)
        count[j] += count[j - 1];
    for (int i = n - 1; i >= 0; i--) {
        tmp[count[data[i]-min] - 1] = data[i];
        count[data[i]-min]--;
    }
    for (int i = 0; i < n; i++)
        data[i] = tmp[i];
    delete count;
    delete tmp;
}

桶排序

假设排序数的范围是[0,1],在[0,1]内平均划分为k个桶,将待排序数放在这些桶里。对于桶内元素个数大于 1 的进行桶内排序(常用插入排序)。因为平均划分,所以一个桶内的元素不会太多,时间复杂度O(n),点击打开维基百科-桶排序

版权声明:本文为博主原创文章,未经博主允许不得转载。

线性排序之基数排序,桶排序,计数排序

标签:排序

原文地址:http://blog.csdn.net/quzhongxin/article/details/46965651

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!