合並兩個排序的數組


需求:有兩個非遞減排序的數組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 }

運行結果

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com