数据结构算法学习总结-慕课网(八)归并排序(自底向上,从小到大)
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
总结
自底向上的归并和自顶向下的归并效率差不多,严格的说自顶向下的效率会更好一些
自底向上的归并有一个优势是,可以实现对链表的排序,有兴趣的同学可以自己研究一下
意见与建议
如果博友有任何问题或者建议,欢迎留言讨论