归并排序
归并排序的一般步骤是先划分、再排序、后合并,这也就符合了分治法的思想
对序列r[]用归并排序进行升序排列,s为开始下标,t为末尾下标,m为中间下标,伪代码如下:
1、如果s==t,则待排序区间只有一个元素,算法结束
2、计算中点:m=(s+t)/2;
3、对前半部分序列r[s]~r[m]进行升序排序,对后半部分r[m+1]~r[t]进行升序排序
4、合并两个升序序列
c++算法如下:
#include<iostream>
using namespace std;
void merge(int r[], int temp[], int s, int m, int t){ //合并子序列(按从小到大合并)
//i是前半部分的下标,j是后半部分的下标,k则是临时数组temp的下标
int i = s, j = m + 1, k = s;
while (i <= m && j <= t){
if (r[i] < r[j]){
temp[k++] = r[i++]; //取值小者放入temp
}
else{
temp[k++] = r[j++];
}
}
while (i <= m){ //若前半部分序列未处理完,则直接加到临时数组temp中
temp[k++] = r[i++];
}
while (j <= t){ //若后半部分序列未处理完,则直接加到临时数组temp中
temp[k++] = r[j++];
}
}
void mergeSort(int r[], int s, int t){ //对序列r[s]-r[t]进行归并排序
int m, temp[100]; //m是划分点,temp是临时数组
if (s == t){ //如果s==t,说明只有一个元素了,则返回(递归边界)
return;
}
else{ //递归
//划分,即使s+t为奇数也能向上取整,不影响排序结果
m = (s + t) / 2;
mergeSort(r, s, m); //递归前半部分
mergeSort(r, m + 1, t);//递归后半部分
merge(r, temp, s, m, t);//合并两个有序子序列,结果保存在temp中
for (int i = s; i <= t; i++){ //将排序后的temp传回r数组中
r[i] = temp[i];
}
}
}
void main(){
int r[8] = { 15,8, 3, 24, 6, 30, 13, 4 };
mergeSort(r, 0, 7); //从0开始到n-1
for (int i = 0; i < 8; i++){
cout << r[i] << "\t";
}
}
运行结果:
算法的复杂度分析:
1、其中用到了临时数组temp,故空间复杂度为O(N)
2、其中的递推公式为:T(N) = 2T(N/2) + O(N),所以时间复杂度为O(N*log2N)
【注意】归并排序的比较次数是所有排序中最少的,因为它一开始只是不断的划分,真正的比较发生在合并为有序序列时