zoukankan      html  css  js  c++  java
  • 归并排序的实现

    归并排序的时间复杂度和快排还有堆排序是一样的,归并排序利用了分治的思想,它的核心就是将两个有序的数组合并,那么我们怎么得到这两个有序的数组呢,就是将这两个数组再分为小的数组,由小的数组合并而成,是不是有种递归的赶脚?对了,归并就是,递归+合并

    算法的框架像这样的:

    void merge_sort(int a[], int l, int r, int temp[])
    {
        if(l < r)
        {
            int mid = (l + r)/2;
            merge_sort(a, l, mid, temp);//递归
            merge_sort(a, mid+1, r, temp);//递归
            merge_array(a, l, mid, r, temp);//合并
        }
    }
    

    就像这样的一个数组:(图片摘自唐苏: http://hi.baidu.com/tangsu2009/item/b74e66a7b07a19228919d3f6)



    自己实现的代码如下:

    /****************merge_sort.c made by cfmlovers************/
    #include <stdio.h>
    #define ARRAYSIZE 4
    merge_array(int a[], int l, int mid, int r, int temp[])
    {
        int i = l, j = mid+1, k = 0;
        while(i <= mid && j <= r)
        {
            if(a[i] < a[j])
                temp[k++] = a[i++];
            else
                temp[k++] = a[j++];
        }
    
        while(i <= mid)
            temp[k++] = a[i++];
    
        while( j <= r)
            temp[k++] = a[j++];
    
        for(i = 0; i < k; i++)
            a[i+l] = temp[i];
    }
    
    void merge_sort(int a[], int l, int r, int temp[])
    {
        if(l < r)
        {
            int mid = (l + r)/2;
            merge_sort(a, l, mid, temp);
            merge_sort(a, mid+1, r, temp);
            merge_array(a, l, mid, r, temp);
        }
    }
    void main()
    {
        int a[ARRAYSIZE], i;
        printf("please input 4 numbers
    ");
        for(i = 0; i < 4; i++)
            scanf("%d",&a[i]);
    
        int temparray[ARRAYSIZE];
    
        /*merge sort*/
        merge_sort(a, 0, ARRAYSIZE-1, temparray);
    
        for(i = 0; i < 4; i++)
            printf("%d
    ", a[i]);
    }
    
    


    既然说是递归算法,那么我们可不可以用非递归实现呢?答案是肯定的

    刚才说递归利用了分治的思想,我们的递归框架中先把整个数组分为两个部分,然后在各个部分继续分为两个部分,就像上面的那张图片,分到最后只剩一个数的数组的时候就是有序的了,然后向上合并,每一次都是合并有序的数组,这是一个自上而下分治,然后合并的过程

    那么非递归如何实现呢?其实是一个逆过程,我们可以自下而上分治,然后合并
    代码实现如下:

    void merge_sort(int a[], int length, int *temp)
    {
        int i, left_min, left_max, right_min, right_max, next;
    
        for(i = 1; i < length; i*=2)//自下向上分治,步长为1、2、4、8
        {
            for(left_min = 0; left_min < length - i; left_min = right_max)
            {
                right_min = left_max = left_min + i;//需要注意的是left_max = right_min
                right_max = left_max + i;
    
                if(right_max > length)
                    right_max = length;
                next = 0;
                while(left_min < left_max && right_min < right_max)//此处是<,所以上面for里面是left_min = right_max
                    temp[next++] = a[left_min] > a[right_min] ?a[right_min++]:
                        a[left_min++];
    
                while(left_min < left_max)
                    a[--right_min] = a[--left_max];
    
                while(next > 0)
                    a[--right_min] = temp[--next];
            }
        }
    
    }

    贵并排序的时间分为两个部分,分治,类似一个二分法查找,时间复杂度O(logn),合并的时候时间是O(n),总的时间就是O(nlogn),是一个稳定的排序算法,

    最差,平均,最好时间都是O(nlogn)

  • 相关阅读:
    log4cpp
    互斥锁封装
    Educational Codeforces Round 37-F.SUM and REPLACE (线段树,线性筛,收敛函数)
    Codeforces 920E-Connected Components? (set,补图,连通块)
    Persistent Bookcase CodeForces
    P4390 [BOI2007]Mokia 摩基亚 (CDQ解决三维偏序问题)
    P3157 [CQOI2011]动态逆序对 (CDQ解决三维偏序问题)
    CDQ 分治解决和点对有关的问题
    洛谷 P2163 [SHOI2007]园丁的烦恼 (离线sort,树状数组,解决三维偏序问题)
    洛谷 P3469 [POI2008]BLO-Blockade (Tarjan,割点)
  • 原文地址:https://www.cnblogs.com/suncoolcat/p/3306295.html
Copyright © 2011-2022 走看看