自然合并排序算法是对合并排序算法的一种改进。设 a[0:n-1]是无序数组,用一次对数组a的扫描可以找出其中 自然排好序的子数组,然后将相邻的排好序的子数组段两 两合并,继续合并相邻排好序的子数组段,直至将整个数 组排好序。

code:

#include <algorithm>
#include <iostream>

using namespace std;

int getIndex(int *a, int *t, int n)
{
    // 记录初始自然排好序的子数组段的起始下标及个数
    int cnt = 0;
    t[cnt++] = 0;	// 第一个下标为0
    for(int i = 0; i < n-1; i++)
    {
        if(a[i+1] < a[i])
            t[cnt++] = i+1;
    }
    return cnt;
}

// 合并a中有序的两段子数组到b对应的位置
// l是第一个有序子数组段的起始下标
// m是第一个有序子数组段的末尾下标
// r是第二个有序子数组段的末尾下标
void merge(int *a, int *b, int left, int mid, int right)
{
    int i = left;
    int j = mid+1;	// j为第二个的起始下标
    int k = left;
    while(i <= mid && j <= right)	// 合并两段
    {
        if(a[i] <= a[j])	// 每次取两段中较小的一个
            b[k++] = a[i++];
        else
            b[k++] = a[j++];
    }
    // 合并两段中的剩余部分
    while(i <= mid) b[k++] = a[i++];
    while(j <= right)	b[k++] = a[j++];
}

void mergePass(int *a, int *b, int *t, int s, int n, int cnt)
{
    int i = 0;
    while(i <= cnt - 2*s)	// 用子段数组个数控制循环
    {
        if(i + 2*s < cnt)
            merge(a, b, t[i], t[i+s] - 1, t[i + 2*s] -1);
        else
            merge(a, b, t[i], t[i+s] - 1, n -1);
        i = i + 2*s;
    }
    // 剩余未合并的不足s
    if(i + s < cnt)
        merge(a, b, t[i], t[i+s] - 1, n-1);
    else if(i < cnt)
        for(int j = t[i]; j <= n-1; j++)
            b[j] = a[j];
}

void mergeSort(int *a, int *t, int n, int cnt)
{
    // s指的是每次合并的子段数或者说步长
    // s = 1时是是对于初始分段1-1合并
    // s = 2时是相对与初始分段2-2合并,2是之前合并好的1-1
    int b[100];
    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;
    }
}


int main()
{
    int n;
    int a[100], t[100];
    cin >> n;
    for(int i = 0; i < n; i++)
        cin >> a[i];
    int cnt = getIndex(a, t, n);
    mergeSort(a, t, n, cnt);
    for(int i = 0; i < n; i++)
        cout << a[i] << ' ';

    return 0;
}