归并排序(Merge Sort)

算法描述:建立在归并操作上的一种有效的排序算法,其是采用分治法(Divide and Conquer)的一个非常典型的应用。归并排序的动态图示如下所示:
  这里写图片描述

复杂度分析:最坏时间复杂度为 O(NlogN) ,平均时间复杂度也为 O(NlogN) ,效率较高。

主要特点:

  • 稳定;
  • 占用额外内存 O(N)
  • 核心在于有序子列的合并;
  • 可以用递归方式实现,也可以用非递归方式实现。

C语言描述(递归算法):

#include<stdio.h>
#include<stdlib.h>
typedef int ElementType;

void Swap(ElementType *A, ElementType *B) {
    ElementType temp = *A;
    *A = *B;
    *B = temp;
}

/* 有序子列的合并:Left、Right和RightEnd分别为左边起始位置、右边起始位置和右边终点位置 */
void Merge(ElementType Data[], ElementType Temp[], int Left, int Right, int RightEnd) {
    int i;
    int LeftEnd = Right - 1; 
    int temp = Left;
    int num = RightEnd - Left + 1;
    while (Left <= LeftEnd && Right <= RightEnd) { /*左右两边均有元素*/
        if (Data[Left] <= Data[Right]) Temp[temp++] = Data[Left++];
        else Temp[temp++] = Data[Right++];
    }
    while (Left <= LeftEnd)     Temp[temp++] = Data[Left++]; /*直接复制左边元素*/
    while (Right <= RightEnd)   Temp[temp++] = Data[Right++]; /*直接复制右边元素*/
    // 将Temp[]中的元素复制到Data[]中
    for (i = 0; i < num; i++)   Data[RightEnd] = Temp[RightEnd--];
}

/* 核心递归排序函数:分而治之 T(N)=O(NlogN) */
void MSort(ElementType Data[], ElementType Temp[], int Left, int RightEnd) {
    int Center;
    if (Left < RightEnd) {
        Center = (Left + RightEnd) / 2; 
        MSort(Data, Temp, Left, Center); /*递归解决左边*/
        MSort(Data, Temp, Center + 1, RightEnd); /*递归解决右边*/
        Merge(Data, Temp, Left, Center + 1, RightEnd); /*合并两段有序序列*/
    }
}

/* 归并排序C语言描述(递归方式) */
void Merge_Sort(ElementType Data[], int N) {
    /* 在此声明额外空间的好处? */
    ElementType *Temp = (ElementType*)malloc(N*sizeof(ElementType));
    if (Temp != NULL) {
        MSort(Data, Temp, 0, N - 1);
        free(Temp);
    }
    else printf("空间不足");
}

int main() {
    ElementType Data[] = {28, 3, 33, 23, 15, 30, 19, 10, 20, 22 };
    Merge_Sort(Data, 10);
    return 0;
}

C语言描述(非递归算法):

#include<stdio.h>
#include<stdlib.h>
typedef int ElementType;

void Swap(ElementType *A, ElementType *B) {
    ElementType temp = *A;
    *A = *B;
    *B = temp;
}

/* 有序子列的合并:Left、Right和RightEnd分别为左边起始位置、右边起始位置和右边终点位置 */
void Merge(ElementType Data[], ElementType Temp[], int Left, int Right, int RightEnd) {
    int i;
    int LeftEnd = Right - 1; 
    int temp = Left;
    int num = RightEnd - Left + 1;
    while (Left <= LeftEnd && Right <= RightEnd) { /*左右两边均有元素*/
        if (Data[Left] <= Data[Right]) Temp[temp++] = Data[Left++];
        else Temp[temp++] = Data[Right++];
    }
    while (Left <= LeftEnd)     Temp[temp++] = Data[Left++]; /*直接复制左边元素*/
    while (Right <= RightEnd)   Temp[temp++] = Data[Right++]; /*直接复制右边元素*/
    // 将Temp[]中的元素复制到Data[]中
    for (i = 0; i < num; i++)   Data[RightEnd] = Temp[RightEnd--];
}

/* 两两归并相邻有序子列:length为当前有序子列的长度 */
void Merge_pass(ElementType Data[], ElementType Temp[], int N, int length) {
    int i, j;
    for (i = 0; i + 2 * length <= N; i += 2 * length)  
        Merge(Data, Temp, i, i + length, i + 2 * length - 1);
    if (i + length < N) /*归并最后2个子列*/
        Merge(Data, Temp, i, i + length, N - 1);
    else /*最后只剩1个子列*/
    for (; i < N; i++) Temp[i] = Data[i];
}

/* 归并排序C语言描述(非递归方式) */
void Merge_Sort(ElementType Data[], int N) {
    int length = 1; /*初始化子序列长度*/
    ElementType *Temp = (ElementType*)malloc(N*sizeof(ElementType));
    if (Temp != NULL) {
        while (length < N) {
            Merge_pass(Data, Temp, N, length);
            length *= 2;
            Merge_pass(Temp, Data, N, length);
            length *= 2;
        }
        free(Temp);
    }
    else printf("空间不足");
}

int main() {
    ElementType Data[] = {28, 3, 33, 23, 15, 30, 19, 10, 20, 22 };
    Merge_Sort(Data, 10);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/bingbeichen/article/details/77278260