需求:有两个非递减排序的数组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 }
运行结果