歸併排序的實現

歸併排序的時間複雜度和快排還有堆排序是一樣的,歸併排序利用了分治的思想,它的核心就是將兩個有序的數組合並,那麼我們怎麼得到這兩個有序的數組呢,就是將這兩個數組再分爲小的數組,由小的數組合並而成,是不是有種遞歸的趕腳?對了,歸併就是,遞歸+合併

算法的框架像這樣的:

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\n");
    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\n", 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)

發佈了39 篇原創文章 · 獲贊 7 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章