//msort.c that contains merge sort (兩個不同版本) // @CopyLeft by tsaiwn@cs.nctu.edu.tw // 注意: msort( ) 用法與程式庫 qsort( )一樣; useMgSort( ) 則用法不一樣! #include #include #include "mystu.h" // 認真的同學可以研究這兩個 merge sort 是如何把資料排序好! ////// // 再宣告一次也沒關係: (但要宣告一樣才可!) void useMgSort(Student*x, int n, int(*comp)(Student*,int,int)); // 注意上面這版本的用法! 還有, 所需的 compare function 的寫法也不同! // 以下的 msort( ) 與 qsort( )用法完全相同的版本寫在後半部 void msort(void*x, int n,int sz, int(*comp)(const void*, const void*)); ////// // 注意在 mystu.h 裡面除了要先有 struct Student 的定義, 還有.. // 裡面要放這兩個 merge sort 函數的宣告! // 這樣, 你只要 #include "mystu.h" 就可使用這兩個函數! // 不然, 你要自己把上面這宣告 copy 到你程式內! (讓Compiler編譯時看的) // 還有, 這檔案中很多函數, 但我只有開放這 useMgSort( ), 和 msort( ) /// 其他的函數都用 "static" 保護起來, 只在這檔案(file)內有效! // 注意! 關於資料結構 (struct), // 注意這例子我故意用 Student 而不是 Student_t 免得你以為依定要有 _t // 不過, 一般是建議要尾巴有 _t 以方便辨識是 type! /// 可以用 Student 是因為我在 mytstu.h 內用 typedef 再弄出 Student 來用 ! /// gcc yourMain.c msort.c ////// // In fact, we do NOT have to use copy2tmp/copyBack functions. // Why? Because of using struct, the copy jobs become very simple! // Thus, you can simply do these jobs directly in the sorting prog. static void copy2tmp(Student*a, Student*t, int k, int i){ t[k] = a[i]; } static void copyBack(Student*a, Student*t, int i){ a[i] = t[i]; } static void merge(Student*, Student*, int left, int right, int m, int(*)(Student*,int, int)); static void mergeSort(Student*a, Student*tmp, // sorting array a[ ] int left, int right, int(*comp)(Student*,int,int)) { int mid; // sorting from a[left] to a[right] if(left >= right) return; // nothing to do :-) if(left+1 == right) { // two elements if( comp(a, left, right) <= 0 ) return; // 順序符合不用做 :-) }// 2 elements mid = (left+right)/2; mergeSort(a, tmp, left, mid, comp); // left..mid 算左半 mergeSort(a, tmp, mid+1, right, comp); // mid+1 .. right merge(a, tmp, left, right, mid, comp); // 注意要把比較函數傳過去 } // mergeSort( void merge(Student *a, Student* tt, int left, int right, int mid, int(*comp)(Student*,int,int)) { int i, r, to; // 注意我故意用變數 tt 免得你以為一定要寫 tmp i = to = left; r = mid+1; while((i <= mid) && (r <= right)) { // 左右都還有資料 if(comp(a, i, r) <= 0) { // a[i]= right) return; // nothing to do :-) if(left+1 == right) { // two elements if( comp(a+left*sz, a+right*sz) <= 0 ) return; // 順序符合不用做 :-) }// 2 elements if(left+2 == right) { // three elements if( comp(a+left*sz, a+left*sz+sz) <= 0 && comp(a+right*sz-sz, a+right*sz) <= 0 ) return; // 順序符合不用做 :-) }// 3 elements mid = (left+right)/2; mergeSort22(a, t, sz, left, mid, comp); // left..mid 算左半 mergeSort22(a, t, sz, mid+1, right, comp); // mid+1 .. right merge22(a, t, sz, left, right, mid, comp); // 注意要把比較函數傳過去 } // mergeSort22( void merge22(void *a, void* tt, int sz, int left, int right, int mid, int(*comp)(const void*, const void*)) { int i, r, to; // 注意我故意用變數 tt 免得你以為一定要寫 t int len; i = to = left; r = mid+1; while((i <= mid) && (r <= right)) { // 左右都還有資料 if(comp(a+i*sz, a+r*sz) <= 0) { // a[i]