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


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

    定义

    归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(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)。
  • 相关阅读:
    Shell重新学习(忘光了)
    vim 设置默认显示行号
    maven学习资料(三)
    maven:新建的maven工程需要添加一下插件
    Spring框架:第五章:Spring EL表达式
    Spring框架:第四章:Spring管理数据库连接池
    Spring框架:第三章:对象的生命周期及单例bean生命周期的11个步骤
    Spring框架:第二章:IOC依赖注入及40个实验
    Spring框架:第一章:介绍和准备工作
    MyBatis框架:第十一章:mybatis 逆向工程
  • 原文地址:https://www.cnblogs.com/ssyfj/p/9513825.html
Copyright © 2020-2023  润新知