需求:有兩個非遞減排序的數組A1和A2,內存在A1的末尾有足夠多的空余空間容納A2,請實現一個函數,把A2中的所有數字插入A1中,並且所有的數字都是排序的。
例如數組A1{ 1,5,7,8,9,17,20 }和數組A2{ 0,2,4,6,7,17,18,23,25 },合並后的結果應為{ 0,1,2,3,5,7,7,8,9,17,17,18,20,23,25 }。
分析:
思路一
直接從兩個數組頭部開始合並。
1.從A2開始遍歷第一個數字;
2.由於A1中如果數字比A2小的話,A1和A2的數字都不需要變動,因此查找A1中第一個比A2當前數字的小的元素;
3.如果找到了A1中的最后一個數字都比當前A2的數字小,說明A2當前數字以及后面所有的數字都比A1的最后一個數字大,直接把A2當前的數字以及后面所有的數字都依次放到A1最后一個元素的后面即完成合並;
4.如果找到了A1中的其中一個數字比A2大,則把A1的這個數字以及后面的所有數字都往后移動1個位置;
5.把A2的這個數字放到步驟2中找到的A1的元素的位置,完成了A2的第1個數字的合並;
6.繼續開始A2的下一個數字,重復步驟2直到數組A2的最后一個數字都已經被放到A1中。
從頭開始合並發,由於要在遍歷數組A2的同時還要查找A1中比A2大的元素,並且還要移動A1的元素,假設待合並的兩個數組的數字個數分別為m和n,則時間復雜度為O(m*n)。
見示例代碼mergeArrayFromHead。
思路二
從兩個數組的尾部開始合並。
1.由於合並后的數組長度是A1的長度加上A2的長度,所以可以獲取最終數組的最后一個數字的位置;
2.同時從數組A1和A2的最后一個數字開始往前遍歷;
3.如果A2的當前數字比A1大,說明A2數組的這個數字排在靠后的位置,所以最終數組的最后一個位置應該填上A2數組的數字,然后A2往前遍歷下一個數字;否則,最終數組的最后一個位置應該填上A1數組的數字,然后A1往前遍歷下一個數字。
4.當確定了最終數組的最后一個位置的數字之后,繼續確定倒數第二個數字的值,通過步驟3結果比較當前A2和A1的數組的數字。繼續步驟3。
5.當數組A2的最后一個數字都已經被放到最中的數組A1中之后,任務結束。
從尾開始替換法,由於只需要同時遍歷數組A1和A2就完成了處理,假設待合並的兩個數組的數字個數分別為m和n,則時間復雜度為O(m+n)。
見示例代碼mergeArrayFromTail。
擴展需求見:https://www.cnblogs.com/huangwenhao/p/11172206.html
c++示例代碼:
1 #include <iostream> 2 3 using namespace std; 4 5 /************************************************************************/ 6 /* @brif 從頭開始合並數組B的數字到數組A中 7 /* @param arrA 非遞減排序的整數數組A 8 /* @param numA 數組A的數字的數量 9 /* @param arrB 非遞減排序的整數數組B 10 /* @param numB 數組B的數字的數量 11 /* @return true表示合並成功 false表示合並失敗 12 /************************************************************************/ 13 bool mergeArrayFromHead(int* arrA, const int numA, const int* arrB, const int numB) 14 { 15 if (!arrA || !arrB || numA < 0 || numB < 0) 16 { 17 cout << "傳參有問題" << endl; 18 return false; 19 } 20 21 int newLenA = numA; 22 int currIndexA = 0; 23 24 for (int i = 0; i < numB; ++i) 25 { 26 //查找到下一個比B數字大的數 27 while (currIndexA < newLenA && arrA[currIndexA] < arrB[i]) 28 { 29 ++currIndexA; 30 } 31 //假如A的最后一個元素都比B當前的數字小,就B和后面所有的數字都放到A最后一個數字的后面,結束循環 32 if (currIndexA == newLenA) 33 { 34 for (int j = i; j < numB; ++j) 35 { 36 arrA[currIndexA] = arrB[j]; 37 ++currIndexA; 38 } 39 } 40 else 41 { 42 //當前A的數字比B的數字大,從當前A的數字開始,所有數字都往后移動1位,把B的數字放在當前A的數字的位置 43 for (int j = newLenA; j >= currIndexA; --j) 44 { 45 arrA[j + 1] = arrA[j]; 46 } 47 arrA[currIndexA] = arrB[i]; 48 //移動到下一個 49 ++currIndexA; 50 //由於增加了一個數字,數組新長度加1 51 ++newLenA; 52 } 53 } 54 return true; 55 } 56 57 /************************************************************************/ 58 /* @brif 從尾開始合並數組B的數字到數組A中 59 /* @param arrA 非遞減排序的整數數組A 60 /* @param numA 數組A的數字的數量 61 /* @param arrB 非遞減排序的整數數組B 62 /* @param numB 數組B的數字的數量 63 /* @return true表示合並成功 false表示合並失敗 64 /************************************************************************/ 65 bool mergeArrayFromTail(int* arrA, const int numA, const int* arrB, const int numB) 66 { 67 if (!arrA || !arrB || numA < 0 || numB < 0) 68 { 69 cout << "傳參有問題" << endl; 70 return false; 71 } 72 73 int currIndex = numA + numB -1; 74 int currIndexA = numA, currIndexB = numB; 75 for (int i = currIndexB-1, j = currIndexA-1; i > 0 && j > 0;) 76 { 77 //如果B數組的數字比較大或者相等,則把B的數字放在當前位置,否則把A的數字放在當前位置 78 if (arrA[j] <= arrB[i]) 79 { 80 arrA[currIndex] = arrB[i]; 81 --i; 82 } 83 else 84 { 85 arrA[currIndex] = arrA[j]; 86 --j; 87 } 88 --currIndex; 89 } 90 return true; 91 } 92 93 int main() 94 { 95 int arrA1[100] = { 1,5,7,8,9,17,20 }; 96 int arrB1[100] = { 0,2,4,6,7,17,18,23,25 }; 97 98 int arrA2[100] = { 1,5,7,8,9,17,20 }; 99 int arrB2[100] = { 0,2,4,6,7,17,18,23,25 }; 100 101 int lenA = 7; 102 int lenB = 9; 103 104 cout << "原始數組A:" << endl; 105 for (int i = 0; i < lenA; ++i) 106 { 107 cout << arrA1[i] << "\t"; 108 } 109 110 cout << endl << endl << "原始數組B:" << endl; 111 for (int i = 0; i < lenB; ++i) 112 { 113 cout << arrB1[i] << "\t"; 114 } 115 116 bool success = mergeArrayFromHead(arrA1, lenA, arrB1, lenB); 117 cout << endl << endl << "從頭開始合並法" << endl; 118 if (!success) 119 { 120 cout << "合並失敗" << endl; 121 } 122 else 123 { 124 for (int i = 0; i < lenB + lenA; ++i) 125 { 126 cout << arrA1[i] << "\t"; 127 } 128 } 129 130 success = mergeArrayFromTail(arrA2, lenA, arrB2, lenB); 131 cout << endl << endl << "從尾開始合並法" << endl; 132 if (!success) 133 { 134 cout << "合並失敗" << endl; 135 } 136 else 137 { 138 for (int i = 0; i < lenB + lenA; ++i) 139 { 140 cout << arrA2[i] << "\t"; 141 } 142 } 143 144 cout << endl << endl; 145 return 0; 146 }
運行結果