本次用c++实现归并排序,代码来自慕课网实战课程,算法与数据结构,我在学习过程中记录下来方便以后看。
c++
template<typename T>
void __merge(T arr[], int l, int mid, int r){
// 经测试,传递aux数组的性能效果并不好
T aux[r-l+1];
//复制数组开辟新的空间注意有i个偏移量
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 ++ ){
//先判断索引的合法性
if( i > mid ) { arr[k] = aux[j-l]; j ++;}
else if( j > r ){ 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;
int mid = (l+r)/2;
__mergeSort(arr, l, mid);
__mergeSort(arr, mid+1, r);
__merge(arr, l, mid, r);
}
template<typename T>
void mergeSort(T arr[], int n){
__mergeSort( arr , 0 , n-1 );
}
nt main() {
int n = 50000;
// 测试1 一般性测试
cout<<"Test for Random Array, size = "<<n<<", random range [0, "<<n<<"]"<<endl;
int* arr1 = SortTestHelper::generateRandomArray(n,0,n);
int* arr2 =SortTestHelper::copyIntArray(arr1, n);
SortTestHelper::testSort("Merge Sort", mergeSort, arr2, n);
delete[] arr1;
delete[] arr2;
cout<<endl;
// 测试2 测试近乎有序的数组
int swapTimes = 100;
cout<<"Test for Random Nearly Ordered Array, size = "<<n<<", swap time = "<<swapTimes<<endl;
arr1 = SortTestHelper::generateNearlyOrderedArray(n,swapTimes);
arr2 = SortTestHelper::copyIntArray(arr1, n);
SortTestHelper::testSort("Merge Sort", mergeSort, arr2, n);
delete(arr1);
delete(arr2);
return 0;
}
//辅助函数
/*srand和rand()配合使用产生伪随机数序列。rand函数在产生随机数前,需要系统提供的生成伪随机数序列的种子,
rand根据这个种子的值产生一系列随机数。如果系统提供的种子没有变化,每次调用rand函数生成的伪随机数序列都是一样的。
srand(unsigned seed)通过参数seed改变系统提供的种子值,从而可以使得每次调用rand函数生成的伪随机数序列不同,
从而实现真正意义上的“随机”。通常可以利用系统时间来改变系统的种子值,即srand(time(NULL)),
可以为rand函数提供不同的种子值,进而产生不同的随机数序列*/
amespace SortTestHelper {
int *generateRandomArray(int n, int range_l, int range_r) {
int *arr = new int[n];
//生成随机数函数,srand需要一个时间种子。来保证每次生成的序列不一样
srand(time(NULL));
for (int i = 0; i < n; i++)
arr[i] = rand() % (range_r - range_l + 1) + range_l;
return arr;
}
int *generateNearlyOrderedArray(int n, int swapTimes){
int *arr = new int[n];
for(int i = 0 ; i < n ; i ++ )
arr[i] = i;
srand(time(NULL));
for( int i = 0 ; i < swapTimes ; i ++ ){
int posx = rand()%n;
int posy = rand()%n;
swap( arr[posx] , arr[posy] );
}
return arr;
}
int *copyIntArray(int a[], int n){
int *arr = new int[n];
copy(a, a+n, arr);
return arr;
}
template<typename T>
void printArray(T arr[], int n) {
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
cout << endl;
return;
}
template<typename T>
bool isSorted(T arr[], int n) {
for (int i = 0; i < n - 1; i++)
if (arr[i] > arr[i + 1])
return false;
return true;
}
template<typename T>
void testSort(const string &sortName, void (*sort)(T[], int), T arr[], int n) {
clock_t startTime = clock();
sort(arr, n);
clock_t endTime = clock();
cout << sortName << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << " s"<<endl;
assert(isSorted(arr, n));
return;
}
};
2017,3.2更新
前面的排序过程都是从上到下的递归过程,本次更新从下往上迭代在某些场景中很快,比如说没有使用用数组下标获取数组值的过程,这个在链表排序中很有用。
//其中i+sz<n为了防止越界,下面的最小值函数也是为了防止最后一组不足i+sz+sz的情况
for(int sz=1;sz<=n;sz+=sz){
for(int i=0;i+sz<n;i+=sz+sz){
//对arr[i....i+sz-1]和arr[i+sz......i+sz+sz-1]
__merge(arr,i,i+sz-1,min(i+sz+sz-1,n-1);}
}