归并排序是将两个或者两个以上的有序序列进行合并的一种排序算法。采用了分治的思想。
它的主要思路是将序列分为两个子序列,对于两个最终有序的子序列进行合并,得到有序的整体序列。
如何保证子序列有序呢?对子序列采用同样的方式进行划分,当子序列长度为1时,子序列有序,此时合并相邻的子序列。
层层返回,不断地进行合并,最终完整的序列就是一个有序的序列。
归并排序可以很清晰地以递归的方式实现。
先进行划分,分为两个长度差不多的子序列,对每个子序列采用同样的方式进行划分,当划分到序列长度为1时,此时序列便是有序的,我们便对相邻的两个有序序列进行合并,合并的方式很简单,另外分配合适大小的辅助空间,将两个有序序列的数据按照大小填充到辅助空间中,然后再从辅助空间将数据拷回原来的位置,这样就完成了一次归并。从最小的子序列开始,不同地进行归并,最终便可以得到完整的有序序列。
代码的简单实现如下:
/*归并排序左边小左边,左边 ++;右边小取右边,右边 ++*/
template<typename T>
void merge(T array[],int low, int mid, inthigh)
{
int k;
// 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
T*temp= new T[high-low+1];
intlbegin= low;
int lend=mid;
int rbegin=mid + 1;
int rend=high;
//比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
for (k=0; lbegin <=lend && rbegin <= rend; ++k)
{
if(array[lbegin]<=array[rbegin])
{
temp[k] =array[lbegin++];
}
else
{
temp[k] = array[rbegin++];
}
}
if(lbegin<= lend) // 若第一个序列有剩余,直接拷贝出来粘到合并序列尾
{
memcpy(temp+k, array+lbegin, (lend-lbegin+1)*sizeof(T));
}
if(rbegin<= rend) // 若第二个序列有剩余,直接拷贝出来粘到合并序列尾
{
memcpy(temp+k, array+rbegin, (rend-rbegin+1)*sizeof(T));
}
memcpy(array+low, temp, (high-low+1)*sizeof(T));//将排序好的序列拷贝回数组中
delete []temp;
}
template<typename T>
void merge_sort(T array[],unsigned int first, unsignedint last)
{
int mid=0;
if(first<last)
{
//mid = (first+last)/2; /*注意防止溢出 */
mid= first+(last-first) >> 1;
//mid = (first & last) + ((first ^ last) >> 1);
merge_sort(array,first, mid);
merge_sort(array,mid+1,last);
merge(array,first,mid,last);
}
}
给出了代码之后,我们可以分析一下上述merge_sort的调用过程如下:
最后分析一下归并排序的时间复杂度:
求解上述式子有:
即可知归并排序的时间复杂度为O(nlogn),其空间复杂度为O(n)。