這個題目隱約是在某個部落格上看到過,後來書籤掉了,一直找不到原文,所以只好自己寫了一個解法,但願沒有出錯。
題目描述
已知一個字元數組,其中儲存有R、G、B字元,要求將所有的字元按照RGB的順序進行排序。比如給定一個數組為char s[] = "RGBBRGGBGB",則排序後應該為RRGGGGBBBB。
分析
解法1)這個題目有點類似於快速排序中用到的劃分數組的方法,但是這裡有三個字元,因此需要調用劃分方法兩次,第一次以'B' 劃分,第二次以'G'劃分,這樣兩次劃分後就可以將原來的字元數組劃分成RGB順序。這個方法比較自然,容易想到,代碼如下。這個方法的缺點是需要遍曆兩遍數組。
/*劃分函數*/void partition(char *a, int lo, int hi, char t){ int m = lo-1; for (int i=lo; i<=hi; i++) { if (a[i] != t) { swap(a, ++m, i); } }}/*主函數*/void sort(char *a){ int len = strlen(a); partition(a, 0, len-1, 'G'); //以G劃分 partition(a, 0, len-1, 'B'); //以B劃分}
解法2)其實還有一個只需要遍曆一遍數組的方法,當然該方法雖然只遍曆一遍數組,但是需要交換的次數並未減少。主要是設定兩個變數r和g分別指示當前R和G字元所在的位置,遍曆數組。
1)如果第i個位置為字元R,則與前面的指示變數r的後一個字元也就是++r處的字元交換,並++g,此時還需要判斷交換後的i裡面儲存的字元是否是G,如果是G,則需要將其與g處的字元交換;
2)如果第i個位置為字元G,則將其與++g處的字元交換即可。++g指向的總是下一個應該交換G的位置,++r指向的是下一個需要交換R的位置。
3)如果第i個位置為字元B,則什麼都不做,繼續遍曆。
void sort2(char *a, int lo, int hi, char *target) { int r, g; //++r和++g分別指向R和G交換的位置 r = g = lo - 1; for (int i=lo; i<=hi; i++) { if (a[i] == target[0]) { //target數組為"RG",因此target[0]='R',這是遇到R的情況 swap(a, ++r, i); ++g; if (a[i] == target[1]) swap(a, g, i); } else if (a[i] == target[1]) { //target[1]='G',這是遇到G的情況 swap(a, ++g, i); } else { //遇到B的情況,什麼都不做 ; } }}
解法3)如果不考慮用交換的思想,可以直接統計RGB各個字元的個數,然後從頭開始對數組重新賦值為RGB即可。那樣簡單多了,哈哈。但是如果換一個題,要求是對正數、負數、0按照一定順序排列,那就必須用交換了。