数据结构(七)排序---归并排序

图解排序算法(四)之归并排序

定义

归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

基本思想

归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。

分而治之

 

实现

可以看到这种结构很像一棵完全二叉树,本文的归并排序我们采用递归去实现(也可采用迭代的方式去实现)。分阶段可以理解为就是递归拆分子序列的过程,递归深度为log2n。

递归实现

1)“分解”——将序列每次折半划分。

(2)“合并”——将划分后的序列段两两合并后排序。
#define MAXSIZE 10

void Merging(int L1[], int L1_size, int L2[], int L2_size)
{
    int temp[MAXSIZE], i, j, k;
    i = j = k = 0;
    //按照大小放入temp数组
    while (i < L1_size && j < L2_size)
    {
        if (L1[i] >= L2[j])
            temp[k++] = L2[j++];
        else
            temp[k++] = L1[i++];
    }
    //对未处理完的数据全部放入temp数组
    for (; i < L1_size; i++)
        temp[k++] = L1[i];
    for (; j < L2_size; j++)
        temp[k++] = L2[j];
    //将局部变量数据存放入L1中
    for (i = 0; i < (L1_size + L2_size); i++)
        L1[i] = temp[i];
}

void MergeSort(int k[], int n)
{
    if (n>1)
    {
        int *list1 = k;
        int list1_size = n / 2;
        int *list2 = k + n / 2;
        int list2_size = n - list1_size;

        MergeSort(list1, list1_size);
        MergeSort(list2, list2_size);
        Merging(list1, list1_size, list2, list2_size);
    }
}

int main()
{
    int i;
    int a[10] = { 5, 2, 6, 0, 3, 9, 1, 7, 4, 8 };
    MergeSort(a, 10);

    for (i = 0; i < 10; i++)
        printf("%d ", a[i]);

    system("pause");
    return 0;
}

非递归实现

void MergeSort2(int k[], int n)
{
    int left_min, left_max, right_min, right_max;
    int *temp = (int*)malloc(sizeof(int)*n);
    int next;
    int step = 1;
    //步长从1到n/2
    for (; step < n;step*=2)
    {
        for (left_min = 0; left_min < n-step;left_min=right_max)
        {
            right_min = left_max = left_min + step;
            right_max = right_min + step;
            if (right_max > n)
                right_max = n;
            next = 0;
            while (left_min<left_max&&right_min<right_max)
            {
                if (k[left_min] < k[right_min])
                    temp[next++] = k[left_min++];
                else
                    temp[next++] = k[right_min++];
            }
            for (; left_min < left_max; )
                k[--right_min] = k[--left_max];
            for (; next > 0;)
                k[--right_min] = temp[--next];
        }
    }
}

性能分析

归并排序是稳定排序,它也是一种十分高效的排序,能利用完全二叉树特性的排序一般性能都不会太差。
从上文的图中可看出,每次合并操作的平均时间复杂度为O(n),而完全二叉树的深度为|log2n|。总的平均时间复杂度为O(nlogn)。
而且,归并排序的最好,最坏,平均时间复杂度均为O(nlogn)。

 

posted @ 2018-08-21 20:38  山上有风景  阅读(585)  评论(0编辑  收藏  举报