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