zoukankan      html  css  js  c++  java
  • 排序算法——归并排序

      如果觉得前面的几种排序很简单的话,那么对于归并排序算法的实现就稍微难一点点了,我相信很多同学学完数据结构后,并不能很熟练的写出归并算法,

    然而,归并排序以及归并排序的变体在互联网在线笔试题是很常见的。接下来就来学习数组的归并排序,为何要强调是数组的归并排序,因为,今天在OJ上刷题

    的时候,遇到了单链表的归并排序,因此,有必要将其区分开来,后面会写一篇单链表归并排序算法。

      这里所说的归并指的是二路归并,即将两个有序的子表,归并为一个表,使这个表中的元素仍然有序。假设有两个子表存放在同一个数组相邻的位置上:

    A[s, mid]表示第一个子表,A[mid+1, t]表示第二个子表,现在如果把这两个子表合并成,并且使的数组A[s, t]有序?可以借助额外的内存空间R,同时从子表

    A[s, mid]和A[mid+1, t]中取元素进行比较,将较小的存在辅助空间R中,最后将辅助空间R中的元素全部复制回数组A中,排序完成

      两个子表的合并算法,代码如下:

    #include <stdlib.h>
    #include <stdio.h>
    
    void Merge(int A[], int s, int mid, int t)          // 给定数组的区间以及中间元素的位置索引
    {  
        int i = s, j = mid + 1, k = 0;
        int *R;
        R = (int *)malloc(sizeof(int)*(t-s+1))          // 动态分配内存
        while(i<=mid && j<=t)
        {
            if(A[i] < A[j])                             // 将第一个子表中的元素存放在R中
            {
                R[k] = A[i];
                k++;
                i++;
            }
            else
            {
                R[k] = A[j];                            // 将第二个子表中的元素存放在R中
                k++;
                j++;
            }
        }
        while(i<=mid)                                   // 将剩余的部分存入R
        {
            A[k] = A[i];
            k++;
            i++
        }
        while(j<=t)                                     // 将剩余的部分存入R
        {
            A[k] = A[j];
            k++;
            j++;
        }
        for(k = 0, i = s; i <= t; i++, k++)             // 将R中的元素拷贝到A中
            A[i] = R[k];
    }

      Merge()函数只是实现了一次归并,如果一个序列,被划分为多个长度为length的子序列(最后一个子序列长度可以小于length),那么就需要多次两两合并,

    也就需要多次调用Merge()函数,让相邻的两个子序列合并。这里需要注意的是:如果一个序列被分为偶数个子序列,那么相邻两个子序列恰好可以两两合并,

    如果一个序列被分为奇数个子序列,则最后一个子序列不参与合并

      多个子序列两两合并的代码如下:

    void MultiMerge(int A[], int length, int n)
    {
        int i;
        for(i = 0; i+2*length-1 < n; i = i+2*length)    // 将相邻的子表两两合并
            Merge(A, i, i+length-1, i+2*length-1);
        if(i+length-1 < n)                              // 如果i+2*length-1>=n 且 i+length-1<n
            Merge(A, i, i+length-1; n-1);               // 说明序列被分为偶数个子序列,且最后一个子序列长度小于length
    }

      现在完成了将多个子序列两两合并,但是这只实现了归并排序的一趟排序。因此,我们可以将数组A看做是n个长度为1的子序列,然后将其子序列两两合并,然后,

    再将其看做n/2个长度为2的子序列,然后两两合并,以此类推;最后整个序列A都是有序的。

      二路归并算法实现如下:

    void MergeSort(int A[], int n)
    {
        int length;
        for(length = 1; length < n; length = 2*length)
            MultiMerge(A, length, n);
    }

      归并排序的时间复杂度为O(nlog2n),时间复杂度为0(n),归并排序是稳定的排序。

      

  • 相关阅读:
    【学习总结】iOS 的机制
    【刷题】面筋-游戏测试-对二次元游戏的认识
    【JAVA】Mac下查看已安装的jdk版本及其安装目录
    【JAVA】MacBook安装Java环境及eclipse
    【学习总结】哈希表:哈希函数构造;哈希表解决地址冲突的方法
    【刷题】面筋-JAVA-hashmap和hashtable
    【刷题】面筋-测开-软件测试的生命周期
    【学习总结】jupyter notebook中以Markdown格式显示文字信息
    【学习总结】n & (n-1)
    【学习总结】IOS系统和Android系统的区别
  • 原文地址:https://www.cnblogs.com/greedyco/p/7160869.html
Copyright © 2011-2022 走看看