数据结构算法学习总结-慕课网(八)归并排序(自底向上,从小到大)
1.回顾
上一节讲到自顶向下递归的归并排序的优化,我们完全可以自底向上归并,不需要使用递归
2.实战
main.cpp
#include <iostream>
#include "SortTestHelper.h"
#include "MergeSort.h"
#include "InsertSort.h"
using namespace std;
/**
* 自底向上的归并
*/
template<typename T>
void mergeSortBU(T arr[],int n){
for(int sz =1;sz <= n;sz+=sz){
for(int i = 0;i + sz < n;i+=sz+sz){
//优化1,近乎有序的数组进行插入排序
if(i >= i+sz+sz-1-15){
insertSort(arr,i,i+sz+sz-1);
}
//优化2,类似2 3|4 5这样的左右都是有序的,3比4小,那么整个数组就是从小到大的,不需要排序
if(arr[i+sz-1] > arr[i+sz-1+1]){
__merge(arr,i,i+sz-1,min(i+sz+sz-1,n-1));
}
}
}
}
int main(){
int n = 100000;
int* arr = SortTestHelper::generateNearlyOrderedArray(n,100);
int* arr1 = SortTestHelper::copyArray(arr,n);
SortTestHelper::testSort("Merge Sort BU:",mergeSortBU,arr,n);
SortTestHelper::testSort("Merge Sort:",mergeSort,arr1,n);
delete[] arr;
return 0;
}
MergeSort.h
#ifndef MERGESORT_H_
#define MERGESORT_H_
#include <iostream>
#include "InsertSort.h"
/**
* 将[l...mid]和[mid+1...r]两部分进行归并
*/
template<typename T>
void __merge(T arr[],int l,int mid,int r){
//临时空间,存贮arr的数组
T aux[r-l+1];
for(int i = l;i<=r;i++)
aux[i-l]=arr[i];
int i = l,j=mid+1;
for(int k = l;k<=r;k++){
//i>mid表示i所在数组已经归并完,j所在的数组没有归并完,还需要归并一次
if(i > mid){
arr[k] = aux[j-l];
j++;
}else if(j > r){//j>r表示j所在数组已经归并完,i所在的数组没有归并完,还需要归并一次
arr[k] = aux[i-l];
i++;
}else if(aux[i-l]<aux[j-l]){
arr[k] = aux[i-l];
i++;
}else{
arr[k] = aux[j-l];
j++;
}
}
}
/**
* 递归使用归并排序,对arr[l...r]的范围排序
*/
template<typename T>
void __mergeSort(T arr[],int l,int r){
// if(l >= r)
// return;
//优化2
if(l >= r-15){
insertSort(arr,l,r);
return;
}
int mid = (l+r)/2;
__mergeSort(arr,l,mid);
__mergeSort(arr,mid+1,r);
//优化1
if(arr[mid] > arr[mid+1]){
__merge(arr,l,mid,r);
}
}
template<typename T>
void mergeSort(T arr[],int n){
__mergeSort(arr,0,n-1);
}
#endif
运行结果
Merge Sort BU: : 0.007sMerge Sort: : 0.005s
总结
自底向上的归并和自顶向下的归并效率差不多,严格的说自顶向下的效率会更好一些
自底向上的归并有一个优势是,可以实现对链表的排序,有兴趣的同学可以自己研究一下
意见与建议
如果博友有任何问题或者建议,欢迎留言讨论