归并排序与计数排序

1. 归并排序

空间复杂度O(N)
思路为:不使用key,先划分再归并,直接将数组一分为二,当递归二分至只剩一个或两个元素时,比较大小排序(升序)
然后进行依次合并保证有序。注意是对数组进行操作,故需额外创建一个数组保存数据
这里写图片描述

这里写图片描述
这里写图片描述

代码实现为:

void _MerageSort(DataType* a,size_t left,size_t mid,size_t right)
{
    assert(a);
    DataType* tmp = (DataType*)malloc((sizeof(DataType)*(right - left + 1)));
    memset(tmp, 0, sizeof(DataType)*(right - left + 1));
    assert(tmp);
    //[left,mid],[mid+1,right]

    int begin1 = left;
    int end1 = mid;
    int begin2 = mid + 1;

    int end2 = right;
    int index = 0;
    while (begin1 <= end1&&begin2 <= end2)//选出较小的
    {
        if (a[begin1] < a[begin2])
        {
            tmp[index++] = a[begin1++];
        }
        else
        {
            tmp[index++] = a[begin2++];

        }

    }
    while (begin1 <= end1)
    {
        tmp[index++] = a[begin1++];

    }
    while (begin2 <= end2)
    {
        tmp[index++] = a[begin2++];
    }
    for (int i = 0; i < index;++i)
    {
        a[left+i] = tmp[i];

    }
    free(tmp);
}
void MerageSort(DataType* a,size_t left,size_t right)
{
    assert(a);
    if (left >= right)//只有一个数
    {
        return;
    }
    int mid = left + ((right - left) >> 1);
    MerageSort(a, left ,mid);
    MerageSort(a, mid + 1, right);
    _MerageSort(a, left, mid, right);

}
void TestMerageSort()
{
    //int a[] = { 0, 2, 3, 1, 6, 4, 8, 7, 9, 5 };
    int a[] = { 2, 5, 4, 9, 8, 7, 6, 3, 1, 0 };
    MerageSort(a, 0, sizeof(a) / sizeof(a[0])-1);
    PrintSort(a, sizeof(a) / sizeof(a[0]));
}

2. 计数排序

思路:
  - 遍历一次数组,得出数组范围range,创建一个大小为range的数组,即哈希表,初始化0
  - 再次重头遍历一次,若重复出现,在相应位置数值加一
  - 从左至右依次遍历哈希表,将数值不为0的位置的下标存到数组中,有几个存几个。

注:
计数排序只适用于对数据范围比较集中的数据集合进行排序。范围分散情况太浪费空间。如有100个数,其中前99个都小于100,最后一个数位是10000,我们总不能开辟10000个数据大小的哈希表来进行排序吧!这样空间就太浪费了。 此时,就得考虑其他的算法了。
②还有一个问题,例如我有一千个数,1001~2000,此时我的哈希表该怎么开辟呢? 开0~2000个?那前面1000个空间就浪费了!直接从1001开始开辟?你想多了!所以这种情况我们就需要遍历一遍数据,找出最大值与最小值,求出数据范围。范围 = 最大值 - 最小值+1。 例如,2000-1001+1 = 1000,这样我们就开辟0~1000个空间,用1代表1001,1000代表2000。节省了大量的空间。
③肯定有同学想到用位图(BitMap)来做,但是位图(BitMap)有局限性,它要求每个数据只能出现一次。算法有些复杂,但是可以尝试。

时间复杂度分析:第一遍统计字数据出现次数,遍历原数据,复杂度为O(N),第二遍遍历哈希表,向原空间写数据,遍历了范围次(range),时间复杂度为O(range),所以总的时间复杂度为O(N+range)。
空间复杂度分析:开辟了范围(range)大小的辅助哈希表,所以空间复杂度为O(range)。

void CountSort(DataType* a, size_t n)
{
    assert(a);
    int min = a[0];
    int max = a[0];
    //确定哈希表大小
    for (size_t i = 0; i < n; i++)
    {
        if (a[i]>max)
        {
            max = a[i];

        }
        if (a[i] < min)
        {
            min = a[i];
        }
    }
    size_t range = max - min + 1;//确定范围
    //统计个数
    int* count = (int*)malloc(sizeof(int)*range);
    assert(count);
    memset(count, 0, sizeof(int)*range);//初始化
    for (size_t i = 0; i < n; ++i)
    {
        //count[a[i] - min]++;
        count[a[i]-min]++;
    }
    //将数重写回数组
    int j = 0;
    for (size_t i = 0; i < range; ++i)
    {
        while (count[i]--)
        {
            a[j++] = i + min;
        }
    }
}
void TestCountSort()
{
    //int a[] = { 0, 2, 3, 1, 6, 4, 8, 7, 9, 5 };
    int a[] = {1,2,1,3,4,2,1,9};
    CountSort(a, sizeof(a) / sizeof(a[0]));
    PrintSort(a, sizeof(a) / sizeof(a[0]));
}

这里写图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值