分析:如果不考慮時間復雜度,最簡單的思路應該是從頭掃描這個數組,每碰到一個偶數時,拿出這個數字,並把位於這個數字後面的所有數字往前挪動一位。挪完之後在數組的末尾有一個空位,這時把該偶數放入這個空位。由於碰到一個偶數,需要移動O(n)個數字,因此總的時間復雜度是O(n2)。
要求的是把奇數放在數組的前半部分,偶數放在數組的後半部分,因此所有的奇數應該位於偶數的前面。也就是說我們在掃描這個數組的時候,如果發現有偶數出現在奇數的前面,我們可以交換他們的順序,交換之後就符合要求了。
因此我們可以維護兩個指針,第一個指針初始化為數組的第一個數字,它只向後移動;第二個指針初始化為數組的最後一個數字,它只向前移動。在兩個指針相遇之前,第一個指針總是位於第二個指針的前面。如果第一個指針指向的數字是偶數而第二個指針指向的數字是奇數,我們就交換這兩個數字。
1 #include<stdio.h> 2 #include<tchar.h> 3 4 void Reorder(int *pData, unsigned int length, bool (*func)(int)); 5 bool isEven(int n); 6 7 /*思路:使用兩個指針,一個指向數組的一個數字,只向後移動, 8 一個指向數組的最後一個數字, 只向前移動,再兩個指針相遇前, 9 如果第一個指針指向的是偶數,第二個指向的是奇數,就交換這兩個數字 10 */ 11 void ReorderOddEven_1(int *pData, unsigned int length) 12 { 13 if(pData == NULL || length == 0) 14 return; 15 16 int *pBegin = pData; 17 int *pEnd = pData + length - 1; 18 19 while(pBegin < pEnd) 20 { 21 while(pBegin < pEnd && (*pBegin & 0x1) != 0) 22 pBegin ++; 23 while(pBegin < pEnd && (*pEnd & 0x1) == 0) 24 pEnd --; 25 26 if(pBegin < pEnd) 27 { 28 int temp = *pBegin; 29 *pBegin = *pEnd; 30 *pEnd = temp; 31 } 32 } 33 } 34 35 //方法2和方法1思路是一樣的,只是將方法1的函數給解耦成兩部分,提高了代碼的復用性。 36 void ReorderOddEven_2(int *pData, unsigned int length) 37 { 38 Reorder(pData, length, isEven); 39 } 40 41 void Reorder(int *pData, unsigned int length, bool (*func)(int)) 42 { 43 if(pData == NULL || length == 0) 44 return; 45 46 int *pBegin = pData; 47 int *pEnd = pData + length - 1; 48 49 while(pBegin < pEnd) 50 { 51 while(pBegin < pEnd && !func(*pBegin)) 52 pBegin ++; 53 54 while(pBegin < pEnd && func(*pEnd)) 55 pEnd --; 56 57 if(pBegin < pEnd) 58 { 59 int temp = *pBegin; 60 *pBegin = *pEnd; 61 *pEnd = temp; 62 } 63 } 64 } 65 66 bool isEven(int n) 67 { 68 return (n & 1) == 0; 69 } 70 71 void PrintArray(int numbers[], int length) 72 { 73 if(length < 0) 74 return; 75 for(int i = 0 ; i < length ; ++i) 76 printf("%d\t", numbers[i]); 77 78 printf("\n"); 79 } 80 81 int main() 82 { 83 //使用方法1測試 84 int numbersOne[] = {1, 2, 3, 4, 5, 6, 7}; 85 int lengthOne = sizeof(numbersOne) / sizeof(int); 86 printf("Test for solution 1:\n"); 87 PrintArray(numbersOne, lengthOne); 88 ReorderOddEven_1(numbersOne,lengthOne); 89 PrintArray(numbersOne, lengthOne); 90 printf("\n"); 91 92 //使用方法2測試 93 int numbersTwo[] = {2, 4, 6, 1, 3, 5, 7}; 94 int lengthTwo = sizeof(numbersTwo) / sizeof(int); 95 printf("Test for solution 2:\n"); 96 PrintArray(numbersTwo,lengthTwo); 97 ReorderOddEven_2(numbersTwo,lengthTwo); 98 PrintArray(numbersTwo, lengthTwo); 99 100 return 0 ; 101 }
還有一種思路,使用兩個指針,一個在前一個在後,當在前的遇到奇數時,就和在後的數進行交換。有一個細節是,若數組一開始就是奇數,則在前的和在和的指向的是同一個數,交換後數組不變,直到遇到第一個偶數時,在前的指針超過在後的指針。
1 #include<iostream> 2 //#include<algorithm> 可省略swap 3 using namespace std; 4 5 void swap(int* num1, int* num2) 6 { 7 int temp = *num1; 8 *num1 = *num2; 9 *num2 = temp; 10 } 11 bool isEven(int n) 12 { 13 return (n & 1)==0; 14 } 15 16 void Reorder(int *pData, unsigned int length, bool (*func)(int)) 17 { 18 if(length < 0 || pData == NULL) 19 return; 20 else{ 21 int i = -1; 22 for(int j =0 ; j < length; j++) 23 { 24 /*當數組中的數字為奇數時,交換i,j指向的兩個數字 25 當起始數字為奇數時,此時交換的數字是相同的, 26 當中間有偶數時,條件語句不滿足,跳過,此時j繼續增加,i不變, 27 然後遇到奇數時,j指向奇數,滿足條件,i指向前一個奇數,i++後, 28 此時i指向此奇數後面的偶數,交換兩數。 29 */ 30 if(!func(*(pData+j))) 31 { 32 i++; 33 swap(*(pData+i), *(pData+j)); 34 } 35 } 36 } 37 } 38 39 void PrintArray(int numbers[], int length) 40 { 41 if(length < 0) 42 return; 43 for(int i = 0 ; i < length ; ++i) 44 printf("%d\t", numbers[i]); 45 46 printf("\n"); 47 } 48 49 int main() 50 { 51 int numbers[] = {3,4,5,6,7,8,9,10,1,2}; 52 int length = sizeof(numbers) / sizeof(int); 53 54 PrintArray(numbers, length) ; 55 56 Reorder(numbers, length, isEven); 57 58 PrintArray(numbers, length); 59 60 return 0; 61 }