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),归并排序是稳定的排序。

      

  • 相关阅读:
    小强的HTML5移动开发之路(1)——HTML介绍
    HTML移动开发参考
    EBS R12 LOG files 位置
    ORACLE收集统计信息
    ORACLE sid,pid,spid总结
    How To Get Log, Trace Files In OA Framework Pages And Concurrent Request Programs
    XMPP系列(五)---文件传输
    XMPP系列(四)---发送和接收文字消息,获取历史消息功能
    iOS下如何获取一个类的所有子类
    是时候抛弃Postman了,试试 VS Code 自带神器插件
  • 原文地址:https://www.cnblogs.com/greedyco/p/7160869.html
Copyright © 2011-2022 走看看