归并排序 笔试面试手写代码常考
2013-10-07 11:35
323 查看
归并排序是将两个或者两个以上的有序序列进行合并的一种排序算法。采用了分治的思想。
它的主要思路是将序列分为两个子序列,对于两个最终有序的子序列进行合并,得到有序的整体序列。
如何保证子序列有序呢?对子序列采用同样的方式进行划分,当子序列长度为1时,子序列有序,此时合并相邻的子序列。
层层返回,不断地进行合并,最终完整的序列就是一个有序的序列。
归并排序可以很清晰地以递归的方式实现。
![](https://img-blog.csdn.net/20140513143531125?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGluZ2Zlbmd0ZW5nZmVp/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
先进行划分,分为两个长度差不多的子序列,对每个子序列采用同样的方式进行划分,当划分到序列长度为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的调用过程如下:
![](https://img-blog.csdn.net/20140513143552593?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGluZ2Zlbmd0ZW5nZmVp/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
最后分析一下归并排序的时间复杂度:
![](https://img-blog.csdn.net/20140513143615796?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGluZ2Zlbmd0ZW5nZmVp/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
求解上述式子有:
![](https://img-blog.csdn.net/20140513143631109?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGluZ2Zlbmd0ZW5nZmVp/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20140513143653296?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGluZ2Zlbmd0ZW5nZmVp/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
即可知归并排序的时间复杂度为O(nlogn),其空间复杂度为O(n)。
它的主要思路是将序列分为两个子序列,对于两个最终有序的子序列进行合并,得到有序的整体序列。
如何保证子序列有序呢?对子序列采用同样的方式进行划分,当子序列长度为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)。
相关文章推荐
- 归并排序 笔试面试手写代码常考
- 从头说12种排序算法:原理、图解、动画视频演示、代码以及笔试面试题目中的应用
- 九大排序算法的手写实现及时空复杂度分析 笔试面试必备
- C++面试基础之手写代码
- 从头说12种排序算法:原理、图解、动画视频演示、代码以及笔试面试题目中的应用
- 整理一些笔试题(要求手写代码的) 2011年以前的
- 面试手写代码的题目
- 面试常考手写代码之--二叉树非递归遍历
- 记2016腾讯 TST 校招面试经历,电面、笔试写代码、技术面、hr面,共5轮
- 12种排序算法:原理、图解、动画视频演示、代码以及笔试面试题目中的应用
- 面试手写代码题目
- 找工作知识储备(3)---从头说12种排序算法:原理、图解、动画视频演示、代码以及笔试面试题目中的应用
- 面试常考手写代码之--二叉树层次遍历(BFS)
- 记2016腾讯 TST 校招面试经历,电面、笔试写代码、技术面、hr面,共5轮
- 整理一些笔试题(要求手写代码的)
- 找工作知识储备(3)---从头说12种排序算法:原理、图解、动画视频演示、代码以及笔试面试题目中的应用
- Java面试手写代码No.3(Singleton)
- 找工作知识储备(3)---从头说12种排序算法:原理、图解、动画视频演示、代码以及笔试面试题目中的应用
- 找工作知识储备(3)---从头说12种排序算法:原理、图解、动画视频演示、代码以及笔试面试题目中的应用
- 面试常考的三个手写代码