300 likes | 622 Views
主題 : Sorting ( 排序 ). 解題技巧 什麼是 sorting ? 基本的 sorting 方法 如何使用 qsort 例題講解 : A.299 歷年題目. 什麼是 sorting ?. 將給定的資料按照 特定的順序 排列好 由小到大 由大到小 例: 1, 7, 9, 5, 3 由小到大: 1, 3, 5, 7, 9 由大到小: 9, 7, 5, 3, 1. 什麼是 sorting ?. 只有數字能比大小嗎? John Bob 小明 小華 只要能 定義大小關係 ,就可以 sort
E N D
主題: Sorting (排序) • 解題技巧 • 什麼是 sorting? • 基本的 sorting 方法 • 如何使用 qsort • 例題講解: A.299 • 歷年題目
什麼是 sorting? • 將給定的資料按照特定的順序排列好 • 由小到大 • 由大到小 • 例: • 1, 7, 9, 5, 3 • 由小到大:1, 3, 5, 7, 9 • 由大到小:9, 7, 5, 3, 1
什麼是 sorting? • 只有數字能比大小嗎? • John Bob • 小明 小華 • 只要能定義大小關係,就可以 sort • J在 B之後 John > Bob • “明”筆畫比“華”少 小明 < 小華
常見的 sorting 演算法 • bubble sort • merge sort • quick sort • heap sort • integer sort
Bubble sort • 原理 • 就像氣泡會往上浮一樣,小的數字必須要往前進,而大的數字就必須往後退 • 每次比較相鄰的兩個數字,然後將小的放在前面的位置,而大的放在後面的位置
Example 1 5 3 7 9 1 7 9 5 3 stage 3 stage 1 1 7 9 5 3 1 3 5 7 9 1 7 5 9 3 1 7 5 3 9 1 3 5 7 9 1 7 5 3 9 stage 2 stage 4 1 5 7 3 9 1 5 3 7 9
swap • 方法 1: • 寫一個 swap 的 function,每次需要的時侯就可以 call 來用 • 注意不能直接傳值進去
swap • example: 將兩個整數互換 void swap( int *a, int *b){ int tmp; tmp = *a; *a = *b; *b = tmp; } int x, y; swap( &x, &y);
swap • 方法 2: • 利用 #define 定義 swap • 變數要記得宣告
swap • example: 將兩個整數互換 #define swap( x, y) (( t) = ( x), ( x) = ( y), ( y) = ( t)) int t; swap( x, y);
C code for ( i = 0 ; i <= n – 1 ; i++ ) for ( j = 0 ; j <= n – 2 ; j++) if ( num[ j] > num[ j+ 1] ) swap(&num[ j ] , &num[ j + 1]); 代n – i – 2會更快
Stable sort • 若是要 sort 的東西之中有大小相同的,如果 sort 完之後大小相同的排法是依照兩個東西 input 的順序排列的話,稱為 stable sort,如果不保證一定按照 input 的順序排的話,稱為 non-stable sort • input: 3 5 2 1 3 4 • stable sort: 1 2 33 4 5
Parallel array • 有時後在寫程式時為了方便起見會開幾個陣列來儲存而不是用 structure,這時如果按其中一個 array 的值來 sort 的話,要記得所有的 array 都要跟著做一樣的動作 • 例: • a[i] 代表身高,b[i] 代表體重,現在想按照身高來做 sort,則 b[i] 也應該做相對應的變動才能夠讓 a[i] 和 b[i] 代表同一個人的身高體重 • 在 swap(a[i], a[j]) 時也應該做 swap(b[i], b[j])的動作
qsort • C 內建的 sort function,一般來說比用 bubble sort 來的快。 • 需要自己寫一個 compare function
Example: qsort int tbl[] = {5, 6, 12, 3, 20, 8}; int comp_func( const void *a, const void *b) { int c, d; c = *(int *)(a); d = *(int *)(b); if (c > d) return (1); else if (c == d) return (0); else return (-1); } qsort(tbl, sizeof(tbl) / sizeof(tbl[0]), sizeof(tbl[0]), comp_func); 陣列指標 要 sort 的個數 每個要 sort 的 element 的大小 compare function
Example: qsort char tbl[][10] = {“Hello”, “OK”, “Test”, “BBS”, “Book”, “C”}; int comp_func( const void *a, const void *b) { char *c, *d; c = (char *)(a); d = (char *)(b); return (strcmp(c, d)); } qsort(tbl, sizeof(tbl) / sizeof(tbl[0]), sizeof(tbl[0]), comp_func);
Example: qsort #include <stdio.h> int num[5] = {1, 7, 9, 5, 3 }; int comp_func(const void *a, const void *b){ int c, d; c = *(int *)(a); d = *(int *)(b); return ( c – d ); } int main(void){ qsort(num, sizeof(num)/sizeof(num[0]), sizeof(num[0]), comp_func); /* qsort(num, 5, sizeof(num[0]), comp_func); */ return 0; }
qsort and bubble sort • bubble sort • 執行速度較慢 • 程式好寫好記,不容易忘 • qsort • 執行速度較快 • 需要自己寫 compare function • 不熟的話容易忘記格式
例題講解:A.299(http://acm.uva.es/p/v2/299.html) • 有一列火車總共有 L 節車廂,每節車廂都有個編號(從 1 ~ L)。現在車廂的順序亂掉了,而站長希望能把車廂的順序由 1 到 L 排好。唯一能做的方法是把相鄰的兩個車廂順序對調,請問,最少需要做幾次的車廂順序對調工作,而能讓車廂的順序由 1 到 L 排好。 • L 最大到 50
Sample input/output Sample input: 3 3 1 3 2 4 4 3 2 1 2 2 1 Sample output: Optimal train swapping takes 1 swaps. Optimal train swapping takes 6 swaps. Optimal train swapping takes 1 swaps. 總共會有幾組 test case 車廂的長度 車廂的編號
讀進 input 需要的資料結構 • int case_num • 總共有幾個 test case • int L • 車廂的長度 • int num[50] • 每個車廂的編號 • 因為 L 最大只有50,所以開一個長度50的整數陣列就夠了
分析 • 1 3 2 • noswap ( 1, 3) 1 3 2 • swap ( 2, 3) 1 2 3 • noswap ( 1, 2) 1 2 3 • 4 3 2 1 • swap ( 4, 3) 3 4 2 1 • swap ( 4, 2) 3 2 4 1 • swap ( 4, 1) 3 2 1 4 • swap ( 3, 2) 2 3 1 4 • swap ( 3, 1) 2 1 3 4 • swap ( 2, 1) 1 2 3 4
解法 • 換火車車廂的順序跟 bubble sort 的順序是一樣的 • 照著 bubble sort 的方法去做,每當 swap 發生的時候就在總次數的地方加一,最後得到的數字就是最少需要換的次數
Program structure read_case_num(); for ( i = 0; i < case_num; i++){ read_train_length(); read_train_number(); bubble_sort(); // 每次 swap 時把 counter 往上加 output_optimal_solution(); }
Program #include <stdio.h> #define swap( x, y) (( t) = ( x) , ( x) = ( y), ( y) = ( t)) int main(void){ int i, j, k, t, L, case_num, counter, num[50]; freopen(“data.in”, “r”, stdin); //若是要送到acm online judge,則這行要拿掉 scanf(“%d”, &case_num); for ( i = 0; i < case_num; i++){ counter = 0; scanf(“%d”, &L); for( j = 0; j < L; j++) scanf(“%d”, &num[j]); for( j = 0; j < L – 1; j++) for( k = 0; k < L – j – 1; k++) if ( num[k] > num[k + 1]) { counter++; swap( num[k], num[k + 1]); } printf(“Optimal train swapping takes %d swaps. \n”, counter); } return 0; }
例題講解:H.88.4http://www.cc.nccu.edu.tw/info_race88/Q.pdf例題講解:H.88.4http://www.cc.nccu.edu.tw/info_race88/Q.pdf • 了解題意 • input 格式、範圍,output 格式、要求 • 分析解法,需要什麼資料結構 • 架構程式,上機實作
漏洞與陷阱 • 漏洞 • 題目寫著“金、銀、銅牌的分配約為1: 2: 3”,那要是人數不是 6 的倍數怎麼辦? • 要是有同分的人落在金、銀牌之間的分界處,該怎麼解決? • Output 格式,欄位有多寬?不然該怎麼對齊? • 輸出 3 中,如果有得獎牌數一樣的國家,該 output 一個或是全部 output?有順序分別嗎? • 陷阱 • 人名有可能中間有空白字元分開,讀 input 時要特別小心
解法 • 依照得分高低排序 • 只要能正確的讀入 input,排序,再 output 就好 • 計算各種獎牌數量 • 加個 counter 計算一下獎牌數量 • 找出得獎牌最多的國家 • 用陣列計算每個國家得獎的數量 • 計算平均數、最高分、最低分和全距 • 簡單的數學式
解題重點 • 如何正確的讀入 input • C 有許多內建的 string function 可以利用,請期待明天的教學
歷年題目 • 練習題 • A.10008 What’s Cryptanalysis • http://acm.uva.es/p/v100/10008.html • A.10057 A Mid-summer Night’s Dream • http://acm.uva.es/p/v100/10057.html • A.612 DNA Sorting • http://acm.uva.es/p/v6/612.html • 挑戰題 • A.10125 Sumsets • http://acm.uva.es/p/v101/10125.html • 其他歷年題目 • H.88.4 • http://www.cc.nccu.edu.tw/info_race88/Q.pdf • H.89.1 對對碰 • http://www.cc.nccu.edu.tw/info_race89/doc/final_program.doc