归并排序-采用的事分而治之的思想,是一种非常高效-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了
真的是,这种算法,真的是很有“灵性”,还是多做题吧。