- 归并排序
今天写了最后一个排序算法,归并排序。
归并是将两个或者两个以上的有序表组合成一个新的有序表。首先是两个两个元素进行归并,然后以两个元素排好序为一个单位,两个单位也就是四个元素进行归并,一次类推,这就是一个递归返回的过程。因此函数是递归调用的,首先将大表分为两部分,再将剩下的两部分再分为两部分,然后调用Merge函数,Merge函数的作用是将两部分的表合为一个有序表。
空间复杂度是,辅助空间恰好占了n个单元,所以是O(n)
时间复杂度:每一趟归并的时间复杂度是O(n),一共要进行O(log2n)次归并操作,因此时间复杂度是O(nlog2n)
归并排序是一种稳定的排序
代码
void merge(int num[],int low,int mid,int high)
{
for(int k=low;k<=high;k++)
{
b[k]=num[k];
}
int i,j;
int x=0;
for(i=low,j=mid+1,x=low;i<=mid&&j<=high;x++)
{
if(b[i]<=b[j])
{
num[x]=b[i++];
}
else
{
num[x]=b[j++];
}
}
while(i<=mid)
{
num[x++]=b[i++];
}
while(j<=high)
{
num[x++]=b[j++];
}
}
void MergeSort(int num[],int low,int high)
{
if(low<high)
{
int mid =(low+high)/2;
MergeSort(num,low,mid);
MergeSort(num,mid+1,high);
merge(num,low,mid,high);
}
}
与排序有关的面试问题
最佳的排序算法是:
每钟排序都有其优缺点,首先需要向面试官询问一些问题
- 数据情况: 数据是已经排序还是基本已经排序,数据集有多大,可有重复的键值吗?
- 排序的要求是什么:需要针对最坏情况和最好情况或者平均情况进行性能优化吗?排序算法需要稳定吗?
- 系统的要求是什么:待排序数据是小于、等于还是大于可用内存?
排序例题:主目录服务器从多个部门目录服务器中接收已按用户ID排序的账户列表,那么能够在该主目录服务器中创建按用户ID排序的、综合全部账户的主列表的最佳方式是什么?
思路分析
数据特征:子列表已排序。将几个已排序的字列表进行排序,很像归并排序。在归并排序的最后阶段,在递归调用已经对子列表进行排序后,接下来就是合并列表,在归并排序中,合并操作时间复杂度为O(n),但是在这个例题中并不是两个归并,确定下一个需要合并的元素,需要扫描k个列表,扫描操作为O(k),需要为每一个排序的元素执行该操作,因此算法的复杂度为O(kn),如果K值较小,那没关系,如果k值较大,那就很影响总体时间。
因此应该着重优化如何从k个元素中找出最小或者最大的元素,这时候想到堆排序,大顶堆或者小顶堆中的堆顶就是最大或者最小的元素,并且每次调整堆的时间复杂度为O(log2n),如此找出最小元素的时间复杂度是O(log2k),每一个元素都要进行该操作,因此得到总体时间复杂度为O(nlog2k)