【数据结构】排序算法之计数排序与基数排序

一、计数排序
很好理解,就是对应每个数我们统计每个数字出现的次数,然后用一个直接定址的哈希表来存放数据,在通过遍历这个哈希表,进而就可以排好序了
如下所示:
这里写图片描述
代码实现如下所示:

void CountSort(int *array, int size)
{
    assert(array || size < 0);
    int minData = array[0];
    int maxData = array[0];

    //确定数据元素的范围
    for (int i = 1; i < size; ++i)
    {
        if (array[i] < minData)
            minData = array[i];
        else if (array[i] > maxData)
            maxData = array[i];
    }
    //开辟辅助空间
    int range = maxData - minData + 1;
    int *pCount = new int[range];
    memset(pCount, 0, range*sizeof(int));

    //统计每个字符出现的次数
    for (int i = 0; i < size; ++i)
    {
        pCount[array[i] - minData]++;//在此处开辟的区间,是一段连续的数组,下标从0开始
    }

    //回收已经统计好的字符
    int index = 0;
    for (int i = 0; i < range; ++i)
    {

        while (pCount[i]--)
            array[index++] = i + minData;
    }
    delete[] pCount;
}

二、基数排序
(一)低关键码排序
从个位到最高位(例如:最大的数为12345,那么最高位便为万位),每次由高从低到高进行排序。排完最高为之后,整个序列就变得有序了
如图所示:
这里写图片描述

代码如下所示:

//获取最大数的比特位的位数
int GetBitCount(int *array, int size)
{
    int radix = 10;
    int count = 1;
    for (int i = 0; i < size; ++i)
    {
        if (radix < array[i])
        {
            count++;
            radix *= 10;
        }   
    }
    return count;
}

//基数排序-----非比较排序2----低关键码排序
void RadixSort_LSD(int*array, int size)
{
    assert(array || size < 0);
    //获取最大数的比特位
    int bitCount = GetBitCount(array, size);
    int radix = 1;

    int*bucket = new int[size];//辅助空间,
    for (int idx = 0; idx < bitCount; ++idx)
    {
        int bucketCount[10] = { 0 };//存放计数的数组
        //统计每个桶中元素的个数
        for (int i = 0; i < size; ++i)
        {
            int index = array[i] / radix % 10;
            //如果是负数,将其放在0号桶的位置
            if (index < 0)
            {
                bucketCount[0]++;
            }
            else
            {
                bucketCount[index]++;//以每一位的形式将元素统计
            }

        }
        //计算每个桶的起始地址
        int startAddr[10] = { 0 };
        for (int i = 1; i < 10; ++i)//表示10个桶
        {
            startAddr[i] = startAddr[i - 1] + bucketCount[i - 1];
        }

        //将对应元素放置到对应的桶中
        for (int i = 0; i < size; ++i)
        {
            //计算桶号
            int bucketNo = array[i] / radix % 10;
            if (bucketNo < 0)
            {
                if (array[i] > array[i + 1])
                    swap(array[i],array[i + 1]);
                bucket[startAddr[0]++] = array[i];
            }
            else
            {
                //将对应元素放置到对应的桶中
                bucket[startAddr[bucketNo]++] = array[i];
            }   
        }
        //回收元素
        memcpy(array, bucket, size*sizeof(array[0]));

        //下面再来排百位等....
        radix *= 10;
    }
}

(二)搞关键码排序
这里写图片描述

代码如下所示:

void _RadixSort_MSD(int*array, int left, int right, int bit, int* bucket)
{
    assert(array);
    if (bit <= 0)
        return;

    int radix = (int)pow((double)10, bit - 1);
    // 统计每个桶中元素的个数
    int bucketCount[10] = { 0 };
    for (int i = left; i < right; ++i)
        bucketCount[array[i] / radix % 10]++;

    // 统计每个桶的起始地址
    int startAddr[10] = { left };
    for (int i = 1; i < 10; ++i)
        startAddr[i] = startAddr[i - 1] + bucketCount[i - 1];

    // 将各元素放置到对应的桶中
    for (int i = left; i < right; ++i)
    {
        int bucketNo = array[i] / radix % 10;
        bucket[startAddr[bucketNo]++] = array[i];
    }

    // 回收
    memcpy(array + left, bucket + left, (right - left)*sizeof(array[0]));

    for (int i = 0; i < 10; ++i)
    {
        int begin = startAddr[i] - bucketCount[i];
        int end = startAddr[i];
        if (begin + 1 < end)
            _RadixSort_MSD(array, begin, end, bit - 1, bucket);
    }
}
void RadixSort_MSD(int *array, int size)
{
    int* tmp = new int[size];
    int bit = GetBitCount(array, size);
    _RadixSort_MSD(array, 0, size, bit, tmp);
    delete[] tmp;
}

这里写图片描述

缺点:对负数不能进行排序,需要进行特殊的处理,因此会比较麻烦。
有关非比较排序就这么多内容,希望大家一起进步!!!

只有不停的奔跑,才能不停留在原地!!!

猜你喜欢

转载自blog.csdn.net/aaronlanni/article/details/80101423