首页 > 技术文章 > 归并排序--较快的算法之一

xiezhw3 2013-11-23 19:43 原文

归并排序是分治法的一种体现,建立在归并操作上。归并排序的思想是将一个数组分成两部分A,B,如果A, B是有序的,那只要将A, B合并起来即可,那么如何保证A, B是有序的呢?那就将A, B按一样的方法各自分成两部分...如此到当分出来的A, B都只有一个元素的时候,A, B都是有序的了。

这就是分治法的一种体现。这样因为A, B都是有序的,合并起来后就是一个完整的有序序列了。

那么,改如何进行合并?他的思想是:先新开一个大小为A, B大小之和的数组cSeq,设两个指针a, b分别指向A, B的第一个元素,然后将a, b正想的元素较大的那个赋到cSeq。并将指向较大的那个的指针指向下一个....如此知道某个指针遍历完了其对应的数组,这时停止遍历并将没有遍历完的那个数组剩下的元素直接赋到cSeq的后面。其实现如下:

 1 void merge(int* aSeq, int lenOfA, int* bSeq, int lenOfB, int* cSeq) {
 2     int i = 0, j = 0, k = 0;
 3 
 4     while (i < lenOfA && i < lenOfB) {
 5         if (aSeq[i] < bSeq[j]) 
 6             cSeq[k++] = aSeq[i++];
 7         else
 8             cSeq[k++] = bSeq[j++];
 9     }
10 
11     //将为遍历完的数组接到cSeq的后面
12     while (i < lenOfA)
13         cSeq[k++] = aSeq[i++];
14 
15     while(j < lenOfB)
16         cSeq[k++] = bSeq[j++];
17 }

下面来看看归并排序的效率,设某数列长为N,将数列分开成小数列一共要logN步,每步都是一个合并有序数列的过程,时间复杂度可以记为O(N),故一共为O(N*logN)。因为归并排序每次都是在相邻的数据中进行操作,所以归并排序在O(N*logN)的几种排序方法(快速排序,归并排序,希尔排序,堆排序)也是效率比较高的。

归并排序使用递归来实现,因为归并是分治的,递归是比较常用的方法。递归思想是:先分别sort A, B两部分,然后将A, B合并。最终的程序如下:

#include <iostream>
#include <stdio.h>

using namespace std;

void merge(int* aSeq, int begin, int mid, int end, int *cSeq) {
    int i = begin, j = mid + 1, k = 0;

    while(i <= mid && j <= end) {
        if (aSeq[i] < aSeq[j])
            cSeq[k++] = aSeq[i++];
        else
            cSeq[k++] = aSeq[j++];
    }

    while (i <= mid)
        cSeq[k++] = aSeq[i++];

    while (j <= end)
        cSeq[k++] = aSeq[j++];

    //将合并后的数组赋给原数组,cSeq只是一个临时使用数组
    //但是因为新开数组需要时间消耗,所以直接开好一个以后一直用...
    for (int i = 0; i != k; i++)
        aSeq[begin + i] = cSeq[i];
}

void merge_sort(int *arrayToSort, int left, int right, int* temp) {
    if (left < right) {
        int midOfArray = (left + right) / 2;

        //首先将两部分排序,然后将两部分合并
        merge_sort(arrayToSort, left, midOfArray, temp);
        merge_sort(arrayToSort, midOfArray + 1, right, temp);
        merge(arrayToSort, left, midOfArray, right, temp);
    }
}

void output(int *arrayToPrint, int len) {
    for (int i = 0; i != len; i++)
        printf("%d ", arrayToPrint[i]);
}

int main(int argc, char const *argv[])
{
    cout << "Enter the length of the array: ";
    int lenOfArray;
    scanf("%d", &lenOfArray);

    cout << "Enter the element of the array: ";
    int *arrayL = new int[lenOfArray];
    for (int i = 0; i != lenOfArray; i++)
        scanf("%d", &arrayL[i]);

    int *temp = new int[lenOfArray];
    merge_sort(arrayL, 0, lenOfArray - 1, temp);
    output(arrayL, lenOfArray);

    return 0;
}

其实就算法来说,在一般情况下归并排序和快速排序是比较理想的了。。

 

推荐阅读