zoukankan      html  css  js  c++  java
  • 归并排序--较快的算法之一

    归并排序是分治法的一种体现,建立在归并操作上。归并排序的思想是将一个数组分成两部分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;
    }

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

  • 相关阅读:
    坑爹啊 StringDictionary 居然是不区分大小写的
    .NET平台OLEDB类型映射到Access数据类型 (转)
    国内省选乱做
    计算几何做题记录
    P6634 [ZJOI2020] 密码 解题报告
    AT2704 [AGC019E] Shuffle and Swap 解题报告
    ARC110F Esoswap 解题报告
    P6631 [ZJOI2020] 序列 解题报告
    P6633 [ZJOI2020] 抽卡 解题报告
    CF1605F PalindORme 解题报告
  • 原文地址:https://www.cnblogs.com/xiezhw3/p/3439343.html
Copyright © 2011-2022 走看看