C模板:归并排序的C代码魔改适配总结

C模板:归并排序的C代码魔改适配总结

背景


归并排序,时间复杂度O(NlogN),具有方便、易懂的特点,且属于稳定排序,使用场景颇多。

下面总结介绍一些魔改用法,比如升序、降序和参数压缩等。

代码与思路


升序降序的Merge排序实现:

下面代码中,a为实际参与排序比较的,b为跟随变化的关系,是a的关联值。temp1, temp2为与a, b等效长度的中转数组。

// 合并 :将两个序列a[first-middle], a[middle+1-end]合并
static void MergeArray(int16_t a[], uint16_t b[], int first, int middle, int end, int16_t temp1[], uint16_t temp2[])
{
    int i = first;
    int m = middle;
    int j = middle + 1;
    int n = end;
    int k = 0;
    while (i <= m && j <= n) {
        // if (a[i] <= a[j]) { // 升序 orig
        if (a[i] < a[j]) { // 升序 为求稳定,相等时不交换
        // if (a[i] > a[j]) { // 降序
            temp1[k] = a[i];
            temp2[k] = b[i];
            k++;
            i++;
        } else {
            temp1[k] = a[j];
            temp2[k] = b[j];
            k++;
            j++;
        }
    }
    while (i <= m) {
        temp1[k] = a[i];
        temp2[k] = b[i];
        k++;
        i++;
    }
    while (j <= n) {
        temp1[k] = a[j];
        temp2[k] = b[j];
        k++;
        j++;
    }

    int ii;
    for (ii = 0; ii < k; ii++) {
        a[first + ii] = temp1[ii];
        b[first + ii] = temp2[ii];
    }
}

// 闭区间 [first, last]
static void MergeSortAlg(int16_t a[], uint16_t b[], int first, int last, int16_t temp1[], uint16_t temp2[])
{
    if (first < last) {
        int middle = (first + last) / 2;
        MergeSortAlg(a, b, first, middle, temp1, temp2);        //左半部分排好序
        MergeSortAlg(a, b, middle + 1, last, temp1, temp2);     //右半部分排好序
        MergeArray(a, b, first, middle, last, temp1, temp2);  //合并左右部分
    }
}

以上版本未做参数打包压缩。

// 合并 :将两个序列a[first-middle],a[middle+1-end]合并
typedef struct MergeSort {
    int16_t *a;
    uint16_t *b;
    int16_t *temp1;
    uint16_t *temp2;
} AgsMergeSortStru;

static void MergeArray(AgsMergeSortStru *mergSortParam, int first, int middle, int end)
{
    int16_t *a = mergSortParam->a;
    uint16_t *b = mergSortParam->b;
    int16_t *temp1 = mergSortParam->temp1;
    uint16_t *temp2 = mergSortParam->temp2;
    int i = first;
    int m = middle;
    int j = middle + 1;
    int n = end;
    int k = 0;
    while (i <= m && j <= n) {
        if (a[i] < a[j]) { // 升序 为求稳定,相等时不交换
        // if (a[i] >= a[j]) { // 降序,等于时取前面a[i]
            temp1[k] = a[i];
            temp2[k] = b[i];
            k++;
            i++;
        } else {
            temp1[k] = a[j];
            temp2[k] = b[j];
            k++;
            j++;
        }
    }
    while (i <= m) {
        temp1[k] = a[i];
        temp2[k] = b[i];
        k++;
        i++;
    }
    while (j <= n) {
        temp1[k] = a[j];
        temp2[k] = b[j];
        k++;
        j++;
    }

    int ii;
    for (ii = 0; ii < k; ii++) {
        a[first + ii] = temp1[ii];
        b[first + ii] = temp2[ii];
    }
}

// 闭区间 [first, last]
static void MergeSortAlg(AgsMergeSortStru *mergSortParam, int first, int last)
{

    if (first < last) {
        int middle = (first + last) / 2;
        MergeSortAlg(mergSortParam, first, middle);        //左半部分排好序
        MergeSortAlg(mergSortParam, middle + 1, last);     //右半部分排好序
        MergeArray(mergSortParam, first, middle, last);    //合并左右部分
    }
}

以上版本已做参数打包压缩。

细节


注意升降序的调节

保证稳定性的关键在于,if (a[i] >= a[j]) {语句。

  • 升序时,用 <
  • 降序时,用 >=

举例:

  • arr a, i: 3, 2 (左侧)
  • arr b, j: 2(s), 1 (右侧)
  • merge: 3, 2, 2(s), 1
  • 保证数值相同时,先放左侧子数组元素
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值