排序算法-----归并排序、计数排序

1. 归并排序

将待排序序列分成两个长度相同的子序列,对每个子序列进行排序,直至子序列剩余一个数,在将其合并成一个序列

具体步骤:
  1. 分组:将待排序序列一分为2,在将子序列进行划分,直至子序列只有一个元素

    这里写图片描述

  2. 归并:将每个子序列进行排序,将排好序的两个子序列进行合并

这里写图片描述


算法分析
  • 稳定性

    最稳定算法,归并和分组过程中都不会使元素的相对位置发生变化

  • 时间复杂度

    这里采用了二分的思想,使其效率有所提高,时间复杂度为O(nlgn)

  • 空间复杂度

    在归并的过程中需要开辟临时数组,故时间复杂度为O(n)


代码
void Merge(DataType* a, int left, int mid, int right)
{
    DataType* tmp = (DataType*)malloc((right - left + 1)*sizeof(int));
    assert(tmp);
    memset(tmp,0,(right - left + 1)*sizeof(int));
    int index = 0;
    int begin1 = left, end1= mid;//第一个数组的范围
    int begin2 = mid + 1, end2 = right;//第二个数组的范围


    //选两个数组中较小的数据在tmp数组中
    while (begin1 <= end1 && begin2 <= end2)
    {
        if (a[begin1] <= a[begin2])
        {
            tmp[index++] = a[begin1++];
        }
        else
        {
            tmp[index++] = a[begin2++];
        }
    }

    //数组1中还有数据
    if (begin1 <= end1)
    {
        while (begin1 <= end1)
        {
            tmp[index++] = a[begin1++];
        }
    }

    //数组2中还有数据
    if (begin2 <= end2)
    {
        while (begin2 <= end2)
        {
            tmp[index++] = a[begin2++];
        }
    }

    //将临时数组的数据拷回原数组
    index = 0;
    while (index < right - left + 1)
    {
        a[index+left] = tmp[index];
        ++index;
    }

    free(tmp);
}

//归并排序
void MergeSort(DataType* a,  int left, int right)
{

    assert(a);

    if (left >= right)
        return;


    //分组
    if (right - left + 1 > 5)
    {
        int mid = left + ((right - left) >> 1);
        MergeSort(a, left, mid);
        MergeSort(a, mid + 1, right);
        //归并
        Merge(a, left, mid, right);
    }
    else
    {
        InsertSort(a+left, right - left + 1);
    }

}

2.计数排序

计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用

具体步骤:
  1. 遍历数组,统计待排序数组的范围range
  2. 开辟数组,大小为统计的范围,并初始化为0
  3. 遍历数组,统计每个数出现的次数
  4. 将统计好数组元素出现的次数保存在哈希表对应位置上,对应位置即为数组元素大小
    注意:待排序数组中不能有负数

算法分析
  • 稳定性

    不稳定,在将数字重新拷贝至原数组时,元素相对位置会发生改变

  • 时间复杂度

    时间复杂度为O(n)

  • 空间复杂度

    需要开辟空间,因此为O(n)


代码
//计数排序
void CountSort(DataType* a, size_t n)
{
    assert(a);

    //统计待排序数组的范围
    DataType max = a[0], min = a[n - 1];
    for (size_t i = 0; i < n; ++i)
    {
        if (a[i] < min)
        {
            min = a[i];
        }

        if (a[i]>max)
        {
            max = a[i];
        }
    }

    size_t range = max - min + 1;

    //开辟范围大小的数组
    DataType* count = (DataType*)malloc(sizeof(int)*range);
    assert(count);
    memset(count, 0, sizeof(int)*range);

    //统计每个数出现的次数
    for (size_t index = 0; index < n; ++index)
    {
        count[a[index]]++;
    }


    //将数字拷至原数组中
    size_t index = 0;
    for (size_t i = 0; i < range; ++i)
    {
        for (int j = 0; j < count[i]; ++j)
        {
            a[index++] = min + i;
        }

    }
    free(count);
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值