zoukankan      html  css  js  c++  java
  • 合并两个排序的数组

    需求:有两个非递减排序的数组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] << "	";
    108     }
    109 
    110     cout << endl << endl << "原始数组B:" << endl;
    111     for (int i = 0; i < lenB; ++i)
    112     {
    113         cout << arrB1[i] << "	";
    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] << "	";
    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] << "	";
    141         }
    142     }
    143 
    144     cout << endl << endl;
    145     return 0;
    146 }

    运行结果

  • 相关阅读:
    [Luogu P3626] [APIO2009] 会议中心
    杭电 1869 六度分离 (求每两个节点间的距离)
    杭电 1874 畅通工程续 (求某节点到某节点的最短路径)
    最短路径模板
    杭电 2544 最短路径
    POJ 1287 Networking (最小生成树模板题)
    NYOJ 1875 畅通工程再续 (无节点间距离求最小生成树)
    POJ 2485 Highways (求最小生成树中最大的边)
    杭电 1233 还是畅通工程 (最小生成树)
    杭电 1863 畅通工程 (最小生成树)
  • 原文地址:https://www.cnblogs.com/huangwenhao/p/11175427.html
Copyright © 2011-2022 走看看