合并两个排序的数组

转自:合并两个排序的数组 - 纯情小浩浩 - 博客园

~~~~~~~~~~~~~~~~~如有侵权,请联系作者及时删除~~~~~~~~~~~~~~~~~

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

复制代码

运行结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值