算法-归并排序-自顶向下

本文详细介绍了自顶向下的归并排序算法,包括算法步骤、C++实现代码及优化策略。通过分治思想,将数据不断二分并合并,达到排序目的。优化1是在数据量小于15时改用插入排序,优化2则是仅在必要时进行合并操作,提高了效率。算法复杂度为O(nlogn),适用于大数据量排序。
摘要由CSDN通过智能技术生成

算法-归并排序-自顶向下

算法步骤:
自顶向下—递归法,函数调用自身一层套一层

1.动画演示

在这里插入图片描述

动画来自

https://www.runoob.com/w3cnote/merge-sort.html

其实我个人认为这个动图做的并不直观,至少缺少了明显的分段过程。归并更像是把一份完整的数据分段,二分分出很多小小段出来,再对小小段进行排序组合成小段,以此类推,小段最终再整合成一份完整的数据。

2.代码

整体使用模板,自适应int float型

gSort.h

#ifndef GSORT_H__
#define GSORT_H__
/**
 * get the size of array
 * arr: array address
 */
#define gSizeof(arr) (sizeof(arr)/sizeof(*arr))

/**
 * 交换两个数的值
 * @tparam T
 * @param a 数1
 * @param b 数2
 */
template<typename T>
void gSwap(T &a,T &b)
{
    T temp=a;
    a=b;
    b=temp;
}

//在本文的优化1被使用到
/**
 *  插入排序优化版-只排序位置在l~r的内容
 * @note  example:
 *          int a[]={0,10,5,4,8,4,5};
 *          gInsertionSortAdvance(a,2,4,1);
 *          a---={0,10,8,5,4,4,5}
 * @param arr arr address
 * @param l left number
 * @param r right number
 * @param order 0: min~max 1: max~min
 */
template<typename T>
void gInsertionSort(T *arr, int l,int r, bool order) {
    for(int i=l+1;i<=r;i++)
    {
        T e=arr[i];//存储当前需要比较的变量
        int j;
        for(j=i;j>l;j--)
        {
            if(order==0) {if(e<arr[j-1]) arr[j]=arr[j-1]; else break;}
            else {if(e>arr[j-1]) arr[j]=arr[j-1];else break;}
        }
        arr[j]=e;
    }
}


/**
 * 归并排序-一分为二后判断大小合并两个数组
 * @tparam T
 * @param l left
 * @param r right
 * @param order 0: min~max 1: max~min
 */
template<typename T>
void __gMerge(T *arr, int l,int mid,int r,bool order) {
    T aux[r-l+1];//开辟一份同样大小的存储空间
    for(int i=l;i<=r;i++)//将上面的空间赋值,实现复制
    {aux[i-l]=arr[i];}
    int i=l;int j=mid+1;//定义两个部分的标记点,初始化为头部位置
    for(int k=l;k<=r;k++)
    {
        if(i>mid){// 如果左半部分元素已经全部处理完毕,防止越界
            arr[k]=aux[j-l];
            j++;
        }else if(j>r){ // 如果右半部分元素已经全部处理完毕,防止越界
            arr[k]=aux[i-l];
            i++;
        }else if(order==0)
        {
            if(aux[i-l]<aux[j-l]) {arr[k] = aux[i - l];i++;}//判断大小赋值
            else {arr[k]=aux[j-l];j++;}
        }else //order==1
        {
            if(aux[i-l]>aux[j-l]) {arr[k] = aux[i - l];i++;}//判断大小赋值
            else {arr[k]=aux[j-l];j++;}
        }
    }
}

/**
 * 归并排序-使用的一分为二函数,递归使用
 * @tparam T
 * @param l left
 * @param r right
 * @param order 0: min~max 1: max~min
 */
template<typename T>
void __gMergeSort(T *arr, int l,int r,bool order) {
#if 1 //是否使用优化1
    if( r - l <= 15){
        gInsertionSort(arr,l,r,order);
        return;
    }
#else
    if(l>=r) return;
#endif

    int mid=(l+r)/2;//计算中间值
    __gMergeSort(arr,l,mid,order);//二分左半部分
    __gMergeSort(arr,mid+1,r,order);//二分右半部分

#if 1 //是否使用优化2
    if(order==0) {
        if(arr[mid] > arr[mid+1])//优化,只有不满足顺序才继续
        __gMerge(arr,l,mid,r,order);//将排好序的两部分合并起来
    }
    else {
        if(arr[mid] < arr[mid+1])//优化,只有不满足顺序才继续
        __gMerge(arr,l,mid,r,order);//将排好序的两部分合并起来
    }
#else
    __gMerge(arr,l,mid,r,order);//将排好序的两部分合并起来
#endif

}

/**
 * 归并排序
 * @tparam T
 * @param arr arr address
 * @param n number
 * @param order 0: min~max 1: max~min
 */
template<typename T>
void gMergeSort(T *arr, int n, bool order) {
    __gMergeSort(arr,0,n-1,order);//注意是0~n-1
}

#endif

main.cpp

#include <iostream>
#include "gSort.h"
using namespace std;
int main() {
    int a[]={1,3,2,4,10};
    gMergeSort(a, gSizeof(a),0);//从小到大
    for(int i=0;i< gSizeof(a);i++)
    {
        cout << a[i]<<" ";
    }
    cout << endl;
    gMergeSort(a, gSizeof(a),1);//从大到小
    for(int i=0;i< gSizeof(a);i++)
    {
        cout << a[i]<<" ";
    }
}

3.分析

  • 算法复杂度O(nlogn),数据量大时运算时间相较于O(n2)的算法有了显著提升
  • 但由于算法复杂度本身前面是有系数的,数据量越小,系数值影响越大,这也会导致O(nlogn)的算法在某些情况可能还比不过O(n2)的

这里用条件编译使用了两处优化

1.优化1

由于数据量小时存在O(n2)算法更好的情况,所以在分段数据量小于15时采用插入排序法
插入排序法代码可以看算法-插入排序

2.优化2

默认是不管数据怎样都会进行排序合并,但是有时数据已经正常,不需要再排了,就可以直接跳过
实现效果类似于插入排序的优化
推荐优化2使用开启

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值