排序之归并排序的算法思想及实现代码

Posted 薛定谔的猫ovo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序之归并排序的算法思想及实现代码相关的知识,希望对你有一定的参考价值。


归并排序

归并排序的基本思想

归并排序与前面讲到的基于交换、选择等排序的思想不一样,“归并”的含义是将两个或两个以上的有序表组合成一个新的有序表

二路归并的基本思想
假定待排序表含有 n n n 个记录,可将其视为 n n n 个有序的子表,每个子表的长度为1,然后两两归并,得到 ⌈ n / 2 ⌉ \\lceil n/2 \\rceil n/2个长度为2或1的有序表;再两两归并……如此重读,直到合并成一个长度为 n n n 的有序表为止。
这种排序方法称为2路归并排序。

2路归并排序的例子:


归并排序的实现代码

归并排序的实现需要两个算法,一个是按 l e n len len做一趟两两归并,另一个是归并排序。

M e r g e ( ) Merge() Merge()的功能是将前后相邻的两个有序表归并为一个有序表。
设两段有序表 L . d a t a [ l o w . . . m i d ] L.data[low...mid] L.data[low...mid] L . d a t a [ m i d + 1... h i g h ] L.data[mid+1...high] L.data[mid+1...high]存在放同一顺序表中的相邻位置,先将它们复制到辅助数组 B [ ] B[] B[]中。每次从对应B中的两个段取出一个记录进行关键字的比较,较小者放入 L . d a t a [ ] L.data[] L.data[]中,当数组 B [ ] B[] B[]中有一段的下标超出其对应的表长(即该段元素已经完全复制到 L . d a t a [ ] L.data[] L.data[]中)时,将另一端中的剩余部分直接复制到 L . d a t a [ ] L.data[] L.data[]中。

//合并
void Merge(SeqList &L, int low, int mid, int high)
    int B[L.n];  //辅助数组B
    int i,j,k;
    for(k=low; k<=high; k++)
        B[k] = L.data[k];  //将L.data中的所有元素复制到B中
    for(i=low, j=mid+1, k=i; i<=mid&&j<=high; k++)
        if(B[i] <= B[j])  //比较B的左右两段中的元素
            L.data[k] = B[i++];  //较小的值复制到L.data中
        else
            L.data[k] = B[j++];
    
    while(i<=mid) L.data[k++] = B[i++];  //若第一个表未检测完,复制
    while(j<=high) L.data[k++] = B[j++];  //若第二个表未检测完,复制

归并排序(递归):

//归并排序
void MergeSort(SeqList &L, int low, int high)
    if(low<high)
        int mid = (low+high)/2;  //从中间划分两个子序列
        MergeSort(L, low, mid);  //对左侧子序列进行递归排序
        MergeSort(L, mid+1, high);  //对右侧子序列进行递归排序
        Merge(L, low, mid, high); //归并
    


归并排序的性能分析

空间复杂度

由于辅助空间占用 n n n 个单元,故归并排序的空间复杂度为 O ( n ) O(n) O(n)

时间复杂度

每趟归并的时间复杂度为 O ( n ) O(n) O(n),总共需要进行 ⌈ l o g 2 n ⌉ \\lceil log_2n \\rceil log2n趟归并,所以算法的时间复杂度为 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)

稳定性

由于 M e r g e ( ) Merge() Merge()操作不会改变相同关键字记录的相对次序,故二路归并排序算法是一种稳定的排序方法


完整代码

#include<bits/stdc++.h>
using namespace std;

#define maxSize 20
typedef struct
    int data[maxSize];
    int n;
SeqList;

void PrintList(SeqList L)
    for(int i=0; i<L.n; i++)
        cout<<L.data[i]<<" ";
    
    cout<<endl<<endl;


//合并
void Merge(SeqList &L, int low, int mid, int high)
    int B[L.n];  //辅助数组B
    int i,j,k;
    for(k=low; k<=high; k++)
        B[k] = L.data[k];  //将L.data中的所有元素复制到B中
    for(i=low, j=mid+1, k=i; i<=mid&&j<=high; k++)
        if(B[i] <= B[j])  //比较B的左右两段中的元素
            L.data[k] = B[i++];  //较小的值复制到L.data中
        else
            L.data[k] = B[j++];
    
    while(i<=mid) L.data[k++] = B[i++];  //若第一个表未检测完,复制
    while(j<=high) L.data[k++] = B[j++];  //若第二个表未检测完,复制


//归并排序
void MergeSort(SeqList &L, int low, int high)
    if(low<high)
        int mid = (low+high)/2;  //从中间划分两个子序列
        MergeSort(L, low, mid);  //对左侧子序列进行递归排序
        MergeSort(L, mid+1, high);  //对右侧子序列进行递归排序
        Merge(L, low, mid, high); //归并
    


int main()
    SeqList L;
    int n;
    cin>>n;
    for(int i=0; i<n; i++)
        cin>>L.data[i];
    
    L.n = n;
    cout<<endl<<"L:";
    PrintList(L);
    //归并排序
    MergeSort(L, 0, L.n-1);
    PrintList(L);
    return 0;

运行结果:

以上是关于排序之归并排序的算法思想及实现代码的主要内容,如果未能解决你的问题,请参考以下文章

重温基础算法内部排序之归并排序法

[ 数据结构 -- 手撕排序算法第六篇 ] 归并排序(上)--递归方法实现

[ 数据结构 -- 手撕排序算法第六篇 ] 归并排序(下)-- 非递归方法实现

数据结构图解七大排序

python代码实现归并排序(Merge Sort )

排序算法之归并排序(Merge Sort)