【数据结构】非比较排序--计数排序和基数排序

本文介绍了非比较排序的两种主要方法——计数排序和基数排序。计数排序通过统计每个元素出现的次数直接确定位置,适合数据集较集中,但空间需求较高。基数排序则按位进行,从低位到高位或高位到低位,适用于时间、字符串等整体权值未知的数据排序。两种方法均以空间换时间为代价,具体选择需考虑实际场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

非比较排序

  • 1、思想
    不需要进行元素之间的比较,交换,在线性的时间内完成排序。
  • 2、分类
    1)计数排序
    2)基数排序
  • 3、优缺点
    要求的空间比较多,是典型的以空间换时间的一种做法

计数排序

  • 1、原理
    这里写图片描述
  • 2、代码实现
#include<iostream>
using namespace std; 

void CountSort(int* a,int n)
{
    //1、首先确定要开一个多大的用于统计的数组
    int size = 0;
    int min = a[0];
    int max = a[0];
    for(int i = 0; i<n; i++)
    {
        if(a[i] < min)
            min = a[i];

        if(a[i] > max)
            max = a[i];
    }
    size = max-min+1;

    //2、开始进行统计原数组中对应下标出现的数
    int* count = new int[size];
    memset(count,0,sizeof(int)*size);
    for(int i = 0; i<n; i++)
    {
        count[a[i]-min]++;
    }

    //3、遍历哈希表,将count数组中大于0的数对应出原数组的值,
    //写入原数组中
    int j = 0;
    for(int i = 0; i<size; i++)
    {
        while(count[i]--)
        {
            a[j++] = i+min;
        }
    }
    delete[] count;

}

//测试函数
void TestCountSort()
{
    int a[10] = {2,5,3,8,3,7,10,9,4,0};
    int sz = sizeof(a)/sizeof(a[0]);
    CountSort(a,sz);
    for(int i = 0; i<sz; i++)
    {
        cout<<a[i]<<" ";
    }
    cout<<endl;
} 
  • 4、时间复杂度和空间复杂度
    时间复杂度:O(N)
    空间复杂度:O(k)(其中K为要排序的数组的范围)

  • 5、优缺点
    1)缺点:由于计数排序的计数数组的大小是取决于数据的范围,那么当要进行排序的数据范围很大时,就需要大量的时间和内存。
    2)优点:
    A:无需进行比较,所以时间上快于任何的比较排序。
    B:适用于数据比较集中的数据排序


基数排序

  • 1、原理
    这里写图片描述
  • 2、分类:
    LSD–从低位向高位排
    MSD–从高位向低位排
  • 3、代码实现
#include<iostream>
using namespace std; 
//给一个数,求这个数有多少位
int GetDigit(int* a,size_t n)
{
    int base = 10;
    int digit = 1;
    int num = 0;
    for(int i = 0; i<n; i++)
    {
        while(a[i] >= base)
        {
            digit++;
            base *= 10;
        }
    }

    return digit;
}
void LSDdigit(int* a,int n)
{
    int digit = GetDigit(a,n);  //得到位数
    int count[10] = {0};
    int start[10] = {0};
    int base = 1;
     //开辟一个新的数组,用于存放一次排序后的数
    int*temp = new int[n];      
    while(digit--)
    {
        //首先按各位进行统计个位上的数出现的次数
        for(int i = 0; i<n; i++)
        {
            int num = (a[i]/base)%10;
            count[num]++;

        }
        start[0] = 0;
        for(int i = 1; i<10; i++)
        {
            start[i] = start[i-1]+count[i-1];
        }
        for(int i = 0; i<10; i++)
        {
            int num = (a[i]/base)%10;
            temp[start[num]++] = a[i];
            count[num]--;
        }
        for(int i = 0; i<10; i++)
        {
            a[i] = temp[i];
        }
        base *= 10;
    }
    delete[] temp;  

}

//测试函数
void TestLSDdigit()
{
    int a[10] = {73,22,93,43,55,14,28,65,39,81};
    int sz = sizeof(a)/sizeof(a[0]);
    LSDdigit(a,sz);
    for(int i = 0; i<sz; i++)
    {
        cout<<a[i]<<" ";
    }
    cout<<endl;
}
  • 4、时间复杂度和空间复杂度
    时间复杂度:O(N*digit)
    空间复杂度:O(N)
  • 5、适用性

    • 基数排序更适合用于对时间、字符串等这些整体权值未知的数据进行排序。
    • 注意:基数排序如果从高位向低位排的话会很麻烦
  • 6、缺点
    由于是空间换取时间,按位进行排序,那么每一位的数的位置可能会发生巨大的变化,目前硬件的缓存不是很占优势,并且当内存比较宝贵的时候,就不要采取这种方式进行排序了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值