归并排序(递归、非递归、自然归并排序)

算法思想:
  归并排序是分治法的典型应用,其思想是不断地将两个有序的数组合并为一个有序数组。
递归实现
  

#include <stdio.h>

void Merge(int a[], int left, int m, int right);
void MergeSortAux(int a[], int left, int right);
void MergeSort(int a[], int len);

int main(void) {
    int len = 0;

    printf("请输入待排数的个数: ");
    scanf("%d", &len);

    int a[len];
    printf("请输入待排的数:\n"); 
    for (int i = 0; i < len; ++i) {
        scanf("%d", &a[i]);
    }  

    MergeSort(a, len);
    printf("排序后的结果为:\n");
    for (int i = 0; i < len; ++i) {
        printf("%d ", a[i]);
    }

    printf("\n");

    return 0;
}

void Merge(int a[], int left, int mid, int right) {
    int arrtmp[right - left +1];    //备份数组a
    int i = left, j = mid + 1;   //i,j分别指向两个子数组的开头

    for (int m = left; m <= right; ++m) {   //将数组a中的元素映射到数组arrtmp中,以作备份
        arrtmp[m - left] = a[m];
    }
    for (int m = left; m <= right; ++m) {
        if (i > mid) {
            a[m] = arrtmp[j - left];
            ++j;
        }
        else if (j > right) {
            a[m] = arrtmp[i - left];
            ++i;
        }
        else {
            if (arrtmp[i - left] < arrtmp[j - left]) {
                a[m] = arrtmp[i - left];
                ++i;
            }
            else {
                a[m] = arrtmp[j - left];
                ++j;
            }
        }
    }
}

void MergeSortAux(int a[], int left, int right) {
    if (left < right) {
        int mid = (left + right) /2;
        MergeSortAux(a, left, mid);
        MergeSortAux(a, mid + 1, right);
        Merge(a, left, mid, right);
    }
}

void MergeSort(int a[], int len) {
    MergeSortAux(a, 0, len - 1);
}

非递归实现

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>

void MergeSort(int a[], int len);
void MergePass(int a[], int b[], int s, int n);
void Merge(int c[], int d[], int l, int m, int r);
void PrintArray(int a[], int len);

int main(void) {
    int a[] = {1, 3, 5, 2, 4};
    MergeSort(a, 5);

    PrintArray(a, 5);

    return 0;
}

void MergeSort(int a[], int len) {
    int *b = (int *)malloc(sizeof(int) * len);
    if (NULL == b) {
        printf("malloc\n");
        exit(-1);
    }
    int s = 1;
    while (s < len) {
        MergePass(a, b, s, len);
        s += s;
        MergePass(b, a, s, len);
        s += s;
    }
    free(b);
}
void MergePass(int a[], int b[], int s, int len) {
    int i = 0;
    while (i <= len - 2 * s) {
        Merge(a, b, i, i + s - 1, i + 2 * s - 1);
        i +=  2 * s;
    }
    if (i + s < len) {
        Merge(a, b, i, i + s -1, len - 1);
    }
    else {
        while(i < len) {
            b[i] = a[i];
            ++i;
        }
    }
}

void Merge(int a[], int b[], int l, int m, int r) {
    int k = l;  //标记数组b
    int i = l, j = m + 1;  //标记数组a的两部分
    while (i <= m || j <= r) {
        if (i > m) {
            b[k++] = a[j++];
        }
        else if (j > r) {
            b[k++] = a[i++];
        }
        else if (a[i] < a[j]) {
            b[k++] = a[i++];
        }
        else {
            b[k++] = a[j++];
        }
    }
}

void PrintArray(int a[], int len) {
    for (int i = 0; i < len; ++i) {
        printf("%d ", a[i]);
    }
    printf("\n");
}

  在实际应用中,待排序的数中,里面会存在一些已经有序的数据,在实际应用归并排序中,可以待排序的数中已经有序的数分成一组,这可以提高排序的效率。
自然归并排序

#include<iostream>  
using namespace std;  
#define N 100 

int boundary_size;      
int boundary[N];  

void Merge(int c[], int d[], int l, int m, int r);
void PrintArray(int a[], int n);
void GetBPoint(int a[], int b[], int n);
void MergePass(int x[], int y[], int s, int n);
void MergeSort(int a[], int n);

int main(void) {  
    int n;
    cin >> n;

    int* a = new int [n];    
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
    }

    GetBPoint(a,boundary,n);  
    MergeSort(a,n);  
    PrintArray(a,n);  

    return 0;  
}

void GetBPoint(int a[], int b[], int n) {  
    int j = 0;  
    b[j++] = 0;  
    for(int i = 0;i < n-1;i++) {  
        if(a[i+1] < a[i])  
            b[j++] = i+1;  
    }  
    boundary_size = j;  
}

void MergeSort(int a[], int n) {  
    int *b = new int [n];
    if (NULL == b) {
        cout << "new\n";
    }  
    int s = 1;  
    while(s <  boundary_size) {  
        MergePass(a,b,s,n);   
        s += s;  
        MergePass(b,a,s,n);  
        s += s;  
    }  
    delete[] b;  
}

void MergePass(int x[], int y[], int s, int n) {  
    int i = 0;  
    while(i <= boundary_size - 2 * s) {  
        int r = ((i+2*s) < boundary_size) ? boundary[i+2*s] : n;  

        Merge(x, y, boundary[i], boundary[i+s]-1, r-1);  
        i += 2 * s;  
    }  
    if(i + s < boundary_size)  
        Merge(x, y, boundary[i], boundary[i+s]-1, n-1);  
    else  
        if(i < boundary_size) {  
            for(int j = boundary[i]; j <= n-1; j++)  
                y[j] = x[j];  
        }  
} 

void Merge(int c[], int d[], int l, int m, int r) {   
    int i = l, j = m + 1, k = r;  
    while((i <= m) && (j <= r)) {  
        if(c[i] <= c[j])  
            d[l++] = c[i++];  
        else  
            d[l++] = c[j++];  
    }  
    if(i>m)                        
        for(int q = j; q <= r; q++)       
            d[l++] = c[q];  
    else  
        for(int p = i; p <= m; p++)         
            d[l++] = c[p];  
}  

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

时间复杂度
  归并排序排序是一种稳定的排序,时间复杂度为O(nlogn)

猜你喜欢

转载自blog.csdn.net/qq_38253837/article/details/79763908