自然合并排序

自然合并排序是合并排序算法的一种改进, 对于初始给定的数组, 通常存在多个长度大于1的已自然排好序的子数组段.

例如, 若数组a中元素为{1, 5, 2, 3, 6, 0, 7, 4, 8}, 则自然排好序的子数组段有{1, 5}, {2, 3, 6}, {0, 7}, {4, 8}. 用一次对数组a的线性扫描就足以找出所有这些排好序的子数组段. 然后将相邻的排好序的子数组段两两合并,构成更大的排好序的子数组段({1, 2, 3, 5, 6}, {0, 4, 7, 8}).继续合并相邻排好序的子数组段,直至整个数组已排好序.

通常情况下, 按此方式进行合并排序所需的合并次数较少. 例如, 对于所给的n元素数组已排好序的极端情况, 自然合并排序算法不需要执行合并.

#include <iostream>

using namespace std;

typedef int Type;

void print(Type a[], int n)
{
    for (int i=0; i<n; ++i) {
        cout << a[i] << " ";
    }
    cout << endl;
}

void GetIndex(int a[], int t[], int n, int &m)
{
    // 记录自然分组后每个子串的起始坐标
    int j = 0;
    t[j++] = 0;
    for(int i = 0; i < n-1; i++) {
        if(a[i+1] < a[i]) {
            t[j++] = i+1;
        }
    }
    m = j;      // m为自然分组的个数
}

void Merge(Type c[], Type d[], int l, int m, int r)
{
    // 合并c[l:m]和c[m+1:r]到d[1:r]
    int i = l, j = m + 1, k = l;
    while (i <= m && j <= r) {
        if (c[i] <= c[j]) {
            d[k++] = c[i++];
        } else {
            d[k++] = c[j++];
        }
    }
    if (i > m) {
        for (int q = j; q <= r; q++) {
            d[k++] = c[q];
        }
    } else {
        for (int q = i; q <= m; q++) {
            d[k++] = c[q];
        }
    }
}

void MergePass(Type x[], Type y[], Type t[], int s, int n, int cnt)
{
    // 合并自然分组后相邻的子数组
    int i = 0;

    while(i <= cnt - 2 * s) {
        // 当自然分组后的子数组个数为偶数时, r = n, 表示恰好两两合并
        int r = ((i + 2 * s) < cnt) ? t[i+2*s] : n;
        Merge(x, y, t[i], t[i+s]-1, r-1);
        i = i + 2 * s;
    }

    if(i + s < cnt) {
        Merge(x, y, t[i], t[i+s]-1, n-1);
    } else if (i < cnt) {
        // 剩余元素直接复制
        for(int j = t[i]; j <= n - 1; j++) {
            y[j] = x[j];
        }
    }
}

void MergeSort(Type a[], Type t[], int n, int cnt)
{
    Type *b = new Type[n];
    int s = 1;

    while (s < cnt) {
        MergePass(a, b, t, s, n, cnt);      // 合并到数组b
        s += s;
        MergePass(b, a, t, s, n, cnt);      // 合并到数组a
        s += s;
    }

    delete[] b;
}

int main(int argc, char *argv[])
{
    Type a[] = {1, 5, 2, 3, 6, 0, 7, 4, 8};
    int len = sizeof(a) / sizeof(int);
    Type *t = new Type[len];
    int cnt;        // 记录自然分组个数

    GetIndex(a, t, len, cnt);
    MergeSort(a, t, len, cnt);
    print(a, len);

    delete[] t;

    return 0;
}

这里写图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值