快速简单搞懂归并排序【新手推荐】

归并排序-采用的事分而治之的思想,是一种非常高效-0(n*logn)的排序算法,也是历来面试题目的热门考点!

首先让我们来把归并排序进行拆分处理,归并排序其实采用了(分解->递归+计算->合并)的这一种模式来进行计算,废话不多说,让我们先上代码

1、一个简单的将两个有序数组合并成一个数组(在不污染原有数组的基础上,我们将把合并结果存放在第三个数组中)

//nums_1代表有序数组1,其长度为length1
//nums_2代表有序数组2,其长度为length2
//将这两个数组都放入num这个数组中

void combine(int *nums_1,int length1,int *nums_2,int length2,int *num)
{
    int *start1=nums_1;
    int *start2=nums_2;
    int index=0;
    while(length1!=0&&length2!=0&&start1!=nums_1+length1&&start2!=nums_2+length2
          )
    {
        if(*start1<*start2)
            num[index++]=*(start1++);
        else
            num[index++]=*(start2++);
    }

//当两个有序数组长度不一样时,将会单独将较长的数组存入num数组中

    if(length1<length2)
        while(start2<nums_2+length2)
            num[index++]=*(start2++);
    else
        while(start1<nums_1+length1)
            num[index++]=*(start1++);
}

2、递归思想:

          首先,我们求一个有序数组的条件——从中间分开看,是两个基本有序的数组的一个合并对吧(当然了,我们知道现在start-midd,midd+1-end,这两个数组现在是无序的)

         好了,开始进行递归——那我们要求start-midd这个有序数组的条件——从中间分开看,也是两个基本有序的数组的一个合并对吧!      (同理,我们在midd+1-end中也是如此)

         重复绿色字体步骤,不停的进行中分-递归~~~~

          快了,看到这你肯定已经有点思路了,那递归到什么时候呢?——当然是这个有序数组里仅剩一个元素(值)的时候——这时数组就是有序的(看到这是不是恍然大悟)

          先别着急看代码,我们理清一下思路——刚才说到我们有了两个有序的数组之后我们要做什么?——合并对吧

          想到这你是不是已经迫不及待的利用代码把它给编写出来?

          ——上代码

//nums_1、nums_2是两个我们要合并的数组
//上述两个数组其实在一个大数组中,我们根据分段作为两个数组进行处理
void combine(int *nums_1,int length1,int *nums_2,int length2)
{
    int *start1=nums_1;
    int *start2=nums_2;
    int index=0;
    int num[length1+length2];
    while(start1<nums_1+length1&&start2<nums_2+length2
         )
    {
        if(*start1<*start2)
            {num[index++]=*(start1++);
            }
        else
           {
               num[index++]=*(start2++);
           }
    }

    if(start1==nums_1+length1)
        while(start2<nums_2+length2)
            num[index++]=*(start2++);
    else
        while(start1<nums_1+length1)
            num[index++]=*(start1++);
    for(int i=0;i<length1+length2;i++)
        nums_1[i]=num[i];
    //上边的for循环困扰了我很长时间
    //最后我终于想明白了——不停的纵向(利用sort_GuiBing(int *start,int *ending,int length)递归——直到length长度为1(即数组只含有一个数)
    //然后我们进行合并-思想是对midd左右两部分的数字进行大小比较,然后存储在一个临时数组中
    // 最后,因为这个临时数组中是经过排序以后的
    // 而且原midd的左右两部分数组只是进行了比较,并没有进行排序
    //所以我们用for循环来对原数据进行覆盖,覆盖成最新的数据
    //那可能会有同学问了,为什么不在原先的数组基础上进行交换?
    //那是因为数组进行了无数次交换,会在一定程度上降低性能,并且交换以后不能保证数组仍然有序
    //例如a[]={1,2,4,9}   b[]={3,5,6};
}
void  sort_GuiBing(int *start,int *ending,int length)
{
       if(length==1)
            return ;
       int midd=length/2;
       if(start<ending)
       {sort_GuiBing(start,start+midd-1,midd);   
        sort_GuiBing(start+midd,ending,ending-start-midd+1);
       }
       combine(start,midd,start+midd,ending-start-midd+1);
}

    //上边的for循环困扰了我很长时间
    //最后我终于想明白了——不停的纵向(利用sort_GuiBing(int *start,int *ending,int length)递归——直到length长度为1(即数组只含有一个数)
    //然后我们进行合并-思想是对midd左右两部分的数字进行大小比较,然后存储在一个临时数组中
    // 最后,因为这个临时数组中是经过排序以后的
    // 而且原midd的左右两部分数组只是进行了比较,并没有进行排序
    //所以我们用for循环来对原数据进行覆盖,覆盖成最新的已排序数据
    //那可能会有同学问了,为什么不在原先的数组基础上进行交换?
    //那是因为数组进行了无数次交换,会在一定程度上降低性能,并且交换以后不能保证数组仍然有序
    //例如a[]={1,2,4,9}   b[]={3,5,6};

因为两个数组已经是有序数组了,我们定义两个指针,分别指向两个数组的头部并且利用指针来取出数据并且进行比较,把小的元素进行存储,并且将指向该元素所在组的指针后移,直达一个数组已经完成这是有序数组的合并,所以剩下的有序数组直接插入到后面就ok了

   真的是,这种算法,真的是很有“灵性”,还是多做题吧。

发布了12 篇原创文章 · 获赞 1 · 访问量 1276

猜你喜欢

转载自blog.csdn.net/qq_34250367/article/details/81268634
今日推荐