本次用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);}
}