自学笔记之归并排序
归并排序主要利用了分治思想,它的过程如下:
1.分解成子问题:将n个元素分解为两个具有n/2的子问题。
2.递归求解子问题:利用递归排序这两个子问题。
3.归并子问题:归并子问题的解来产生排序好的答案。
归并排序中最终要的一步是将两个子问题的解合并,在这里我们设计一个函数Merge(A,p,q,r),其中A代表待排序的数组,p,q,r分别表示数组的下标,满足p<=q<r.假设A[p,q]和A[q+1,r]分别是已经排序好的数组,调用这个函数能将其组合为一个排序好的数组A[p…r]。
实现的伪代码如下:
实现过程是利用两个数组来存储已经排序好的子数组,然后将这两个数组合并为一个数组并存储在原数组中。下图1-1为图示过程:
图1-1 归并过程图示
下面为归并算法的伪代码:
假设数组的起始下标为1,我们就可以调用Merge-sort(A,1,A.length)实现归并排序。
时间复杂度分析:
由于归并排序的过程就是将一个问题分解为两个同等大小的子问题,并将所得的结果组合。这样我们可以得到时间复杂度的关系式如下:
下图利用递归树求解这个表达式:
最后可以求出归并排序的时间复杂度为O(nlgn)。
下图为实现的C++代码:
#include<iostream>
using namespace std;
#define INFTY 2147483647;
void mergesort(int *,int,int);
void merge(int *,int,int,int);
int main()
{
int A[10]={3,54,75,34,23,54,345,577,4357,4765};
mergesort(A,0,9);
for(int i=0;i<10;i++)
{
cout<<A[i]<<" ";
}
cin.get();
return 0;
}
void mergesort(int *arr,int p,int r)
{
int q;
if(p<r)
{
q=(p+r)/2;
mergesort(arr,p,q);
mergesort(arr,q+1,r);
merge(arr,p,q,r);
}
}
void merge(int *arr,int p,int q,int r)
{
int *l1=new int [q-p+2];
int *l2=new int [r-q+1];
for(int i=0;i<q-p+1;i++)
l1[i]=arr[p+i];
for(int i=0;i<r-q;i++)
l2[i]=arr[q+i+1];
l2[r-q]=INFTY;
l1[q-p+1]=INFTY;
int i=0;
int j=0;
for(int k=p;k<=r;k++)
{
if(l1[i]<=l2[j])
{
arr[k]=l1[i];
i++;
}
else
{
arr[k]=l2[j];
j++;
}
}
delete [] l1;
delete [] l2;
}