归并排序 笔试面试手写代码常考
2014-09-14 12:19
316 查看
归并排序是将两个或者两个以上的有序序列进行合并的一种排序算法。采用了分治的思想。
它的主要思路是将序列分为两个子序列,对于两个最终有序的子序列进行合并,得到有序的整体序列。
如何保证子序列有序呢?对子序列采用同样的方式进行划分,当子序列长度为1时,子序列有序,此时合并相邻的子序列。
层层返回,不断地进行合并,最终完整的序列就是一个有序的序列。
归并排序可以很清晰地以递归的方式实现。
![](http://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的调用过程如下:
![](http://img.blog.csdn.net/20140513143552593?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGluZ2Zlbmd0ZW5nZmVp/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
最后分析一下归并排序的时间复杂度:
![](http://img.blog.csdn.net/20140513143615796?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGluZ2Zlbmd0ZW5nZmVp/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
求解上述式子有:
![](http://img.blog.csdn.net/20140513143631109?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGluZ2Zlbmd0ZW5nZmVp/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](http://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)。
相关文章推荐
- 归并排序 笔试面试手写代码常考
- 整理一些笔试题(要求手写代码的)
- 【笔试&面试】C#的托管代码与非托管代码
- 从头说12种排序算法:原理、图解、动画视频演示、代码以及笔试面试题目中的应用 .
- 找工作知识储备(3)---从头说12种排序算法:原理、图解、动画视频演示、代码以及笔试面试题目中的应用
- 排序算法--从头说12种排序算法:原理、图解、动画视频演示、代码以及笔试面试题目中的应用
- 链表的一些常见笔试面试问题总结及代码
- 笔试面试最常涉及到的12种排序算法(包括插入排序、二分插入排序、希尔排序、选择排序、冒泡排序、鸡尾酒排序、快速排序、堆排序、归并排序、桶排序、计数排序和基数排序)进行了详解。每一种算法都有基本介绍、算
- 从头说12种排序算法:原理、图解、动画视频演示、代码以及笔试面试题目中的应用
- 找工作知识储备(3)---从头说12种排序算法:原理、图解、动画视频演示、代码以及笔试面试题目中的应用
- 找工作知识储备(3)---从头说12种排序算法:原理、图解、动画视频演示、代码以及笔试面试题目中的应用
- 找工作知识储备(3)---从头说12种排序算法:原理、图解、动画视频演示、代码以及笔试面试题目中的应用
- 整理一些笔试题(要求手写代码的) 2011年以前的
- C/C++ 笔试、面试题目汇总1——代码相关
- 笔试面试必会代码 以及必看书籍
- C/C++ 笔试、面试题目汇总1——代码相关
- 面试常考手写代码之--二叉树层次遍历(BFS)
- 从头说12种排序算法:原理、图解、动画视频演示、代码以及笔试面试题目中的应用
- 从头说12种排序算法:原理、图解、动画视频演示、代码以及笔试面试题目中的应用
- 整理一些笔试题(要求手写代码的)