• 归并排序


    //归并排序  复杂度O(n*logn)
    int MergeSort(int a[], int n)
    {
       int *tmp = malloc(sizeof(int)*n);
       if(tmp == NULL)
             return 0;
       mergesort(a,0,n-1,tmp);
       free(tmp);
       return 1;
    }
    //所谓的“归”  采用递归思想
    void mergesort(int a[],int first, int last, int tmp[])
    {
        int mid = (first + last)/2;
        if(first < last)
        {
            mergesort(a,first,mid,tmp);          //排序左边
            mergesort(a,mid+1,last,tmp);         //排序右边
            MergeTwoArray(a,first,mid,last,tmp); //将已经排序好的左右两边“并”起来
        }
    }
    //所谓的“并”
    void MergeTwoArray(int a[],int first, int mid, int last, int tmp[])
    {
        int i = first, j = mid + 1;
        int k = 0;
        while(i <= mid && j <= last)     
        {
           if(a[i] <= a[j]) 
                {
                 tmp[k++] = a[i++];
                }
           else 
             {
                 tmp[k++] = a[j++];
             }
        }
    
        if(i<=mid) 
        {
            while(i<=mid)
            {
                tmp[k++] = a[i++];
            }
        }
    
        if(j<=last) 
        {
            while(j<=last)
            {
                tmp[k++] = a[j++];
            }
        }
    
        for(i=0;i<k;i++)
        {
            a[first+i]=tmp[i];
        }
    }

     

    --------------------------------------------------------------- 8月28日看了MIT算法的归并排序 对“并”进行代码优化-------------------------------------------------------------

    void MergeTwoArray(int a[],int first, int mid, int last, int tmp[])
    {
      for(int k=first;k<=last;k++)
      {
         tmp[k] = a[k];                //copy
      }
    
      int i=first.j=mid+1;
    
      for(k=first;k<=last;k++)        //merge
      {
         if(i>mid)                a[k]=tmp[j++];
         else if(j>last)          a[k]=tmp[i++];
         else if(tmp[i] < tmp[j]) a[k] = tmp[i++];
         else                     a[k] = tmp[j++];
      }
    }

     

     优化归并排序:

    一、考虑为何归并排序不适合特别小的数组?

          因为申请额外空间,还会增加调用函数开销。而和插入排序比较而言,由于数组规模特别小,时间上并无太大差别。

          因此改进方法就是进行切分。对于小于某个数组规模的数组进行插入排序。见代码

    二、假设左右两边数组排序后已经是有序了,那就可以跳过合并的步骤,见代码

    三、对于tmp辅助数组,可以不用来回拷贝,而是在这两个数组之间交替进行,只要保证最后拷贝回原来的数组即可。

    void MergeTwoArray(int a[],int first, int mid, int last, int tmp[])
    {
      for(int k=first;k<=last;k++)
      {
         tmp[k] = a[k];                //copy
      }
    
      int i=first.j=mid+1;
    
      for(k=first;k<=last;k++)
      {
         if(i>mid)                a[k]=tmp[j++];
         else if(j>last)          a[k]=tmp[i++];
         else if(tmp[i] < tmp[j]) a[k] = tmp[i++];
         else                     a[k] = tmp[j++];
      }
    }
    

    #define CUTOFF 3 void merge_sort(int a[], int tmp[], int first, int last) { if(last <= first + CUTOFF - 1) { insert_sort(a,first,last); return; } int mid=first + (last-first)/2; merge_sort(a,tmp,first,mid); merge_sort(a,tmp,mid+1,last); if(a[mid] <= a[mid+1]) return; MergeTwoArray(a,tmp,first,mid,last); }

    时间复杂度证明:

    1.树状图法:

    2.数学证明法:

    3.归纳法

    非递归的归并排序:

    //非递归的归并排序
    void MergeSort(int a[], int n)
    {
        int length = 1;
        int *tmp = malloc(sizeof(int)*n);
        if(tmp == NULL)
        {
          return 0;
        }
    
        while(length < N)
        {
            mergesort(A,tmp,N,length);
            length *= 2;
            mergesort(tmp,A,N,length);
            length *= 2;
        }
        free(tmp);
        return 1;
    }
    
    
    //所谓的并
    void MergeTwoArray(int a[],int first, int mid, int last, int tmp[])
    {
        int i = first, j = mid + 1;
        int k = 0;
        while(i <= mid && j <= last)     
        {
           if(a[i] <= a[j]) 
                {
                 tmp[k++] = a[i++];
                }
           else 
             {
                 tmp[k++] = a[j++];
             }
        }
    
        if(i<=mid) 
        {
            while(i<=mid)
            {
                tmp[k++] = a[i++];
            }
        }
    
        if(j<=last) 
        {
            while(j<=last)
            {
                tmp[k++] = a[j++];
            }
        }
    
        for(i=0;i<k;i++)
        {
            a[first+i]=tmp[i++];
        }
    }
    
    
    //非递归的“归”
    void mergesort(int a[],int tmp[],int N, int length)
    {
        
        for(int i=0;i <= N-2*length;i += 2*length)
        {
          MergeTwoArray(a,i,i+length,i+2*length-1,tmp);
        }
    
        if(i+length >= N)
        {
         for(int j=i;j<N;j++)
             tmp[j] = a[j];
        }
        else
        {
          MergeTwoArray(a,i,i+length,i+2*length-1,tmp);
        }
    }

    非递归精简版:

    void merge_sort2(int a[], int N)
    {
        tmp = malloc(sizeof(int)*N);
        for(int sz=1;sz<N;sz*=2)
        {
           for(int lo=0;lo<N-sz;lo+=sz+sz)
           {
              MergeTwoArray(a,lo,lo+sz-1,min(lo+sz+sz-1,N-1),tmp);
           }
        }
    }
  • 相关阅读:
    LeetCode-Letter Combinations of a Phone Number
    LeetCode-Sort Colors
    C++Memset误区
    LeetCode-Valid Palindrome
    LeetCode-Longest Consecutive Sequence
    C++豆知识索引
    C++ 哈希表
    LeetCode-Sum Root to Leaf Numbers
    LeetCode-Word LadderII
    LeetCode-Word Ladder
  • 原文地址:https://www.cnblogs.com/dzy521/p/9383136.html
Copyright © 2020-2023  润新知