【问题标题】:fusion of two arrays sorted融合两个排序的数组
【发布时间】:2018-10-13 21:00:06
【问题描述】:
void fus(int *A, int *B, int *C, int n, int m) {
    int j, k, d = n + m;
    for (i = 0, j = 0, k = 0; j < m && i < n && k < d; i++, j++, k++) {
        if ((*(A+i)) < (*(B+j))) {
            (*(C+k)) = (*(A+i));
        } else
            (*(C+k)) = (*(B+j));
    }
}

我是否可以将所有这些条件放在for 中?

不知道为什么不行,想得到一个排序好的数组

【问题讨论】:

  • ij 不必在每次迭代中递增。如果A[i] &lt; B[j]j 否则增加i
  • 仍然不起作用,因为如果我们像你说的那样增加 i ,我们将没有第二个数组的值。

标签: c algorithm sorting


【解决方案1】:

Rabbid76 发现了问题。

A[i]*(A + i) 更容易/更清晰

另外,如果AB 的长度不同[它们可以在合并排序合并操作中],我们需要两个额外的循环来复制AB 中较长的剩余部分

另外,最好使用描述性更强的名称,而不是 ij 等。

这是一个更正的版本[请原谅无偿的风格清理]:

void
fus(int *A, int *B, int *C, int nA, int nB)
{
    int iC = 0;
    int iA = 0;
    int iB = 0;

    for (;  (iA < nA) && (iB < nB);  ++iC) {
        if (A[iA] <= B[iB])
            C[iC] = A[iA++];
        else
            C[iC] = B[iB++];
    }

    for (;  iA < nA;  ++iA, ++iC)
        C[iC] = A[iA];

    for (;  iB < nB;  ++iB, ++iC)
        C[iC] = B[iB];
}

【讨论】:

  • 您关于需要复制AB 的其余元素的评论是正确的,但不正确:它与AB 的长度无关。它总是需要的。
  • @chqrlie 很有趣。但是,IMO,由于 canneed 的“强度”,这句话 not 暗示循环是可选的,只是长度不匹配是可选的。但是,我们可以这样做:s/if the/if and when the/s/if the/to cover the case when the/
  • @chqrlie 但是,如果长度匹配,额外的循环可选的,我们可以有一个“快速路径”函数fus_fast 来消除它们,需要一个单长度参数 nC,单循环条件:iC &lt; nC; 然后,fus 变为 fus_slow,我们现在有 void fus(int *A,int *B,int *C,int nA,int nB) { if (nA == nB) fus_fast(A,B,C,nA * 2); else fus_slow(A,B,C,nA,nB); } 如果数组长度是幂,则出现快速路径总是 2,并且 [因为他正在学习] OP 可能是从这个假设开始的。
  • 恐怕你弄错了:当(iA &lt; nA) &amp;&amp; (iB &lt; nB) 失败时,第一个循环停止,而iAiB 失败的唯一可能性是nA 和@ 987654346@ 都是 0 开始的。否则,由于只有iAiB 之一在循环体中递增,因此这两个条件不能同时失败。
【解决方案2】:

i 和 j 不必在每次迭代中递增。如果 A[i]

创建一个循环,只要i&lt;nj&lt;m 持续:

for(i=0, j=0, k=0; j<m && i<n; k++)
{
    if ( A[i] < B[j] )
       C[k] = A[i++];
    else
       C[k] = B[j++];
}      

在此循环结束时,i == nj == m,但不能同时填满。
所以你必须将丢失的其余部分复制到容器中:

for(; i<n; i++, k++)
    C[k] = A[i];
for(; j<m; j++, k++)
    C[k] = B[j];

完整的代码可能如下所示:

void fus(int *A, int *B, int *C, int n, int m)
{
    int i=0, j=0, k=0;

    for(; j<m && i<n; k++)
        C[k] = A[i] < B[j] ? A[i++] : B[j++];

    for(; i<n; i++, k++)
        C[k] = A[i];
    for(; j<m; j++, k++)
        C[k] = B[j];
}

当然,这甚至可以更短的表达:

void fus(int *A, int *B, int *C, int n, int m)
{
    int i=0, j=0, k=0;  
    while (i<n || j<m)
        C[k++] = i!=n && (j==m || A[i] < B[j]) ? A[i++] : B[j++];
}

【讨论】:

  • 这是一个非常紧凑的替代方案,代价是许多冗余测试。
【解决方案3】:

您应该只增加ij,具体取决于您采用的元素。此外,无需针对d 测试k,此测试与ij 上的测试相比是多余的。

另请注意,除非您在i == nj == m 时完成从AB 复制剩余元素,否则融合是不完整的。

这是一个使用数组索引语法的经过修正和改进的版本,测试更少:

void fus(const int *A, const int *B, int *C, int n, int m) {
    int i = 0, j = 0, k = 0;
    if (i < n && j < m) {
        for (;;) {
            if (A[i] <= B[j]) {
                C[k++] = A[i++];
                if (i == n)
                    break;
            } else {
                C[k++] = B[j++];
                if (j == m)
                    break;
            }
        }
    }
    while (i < n)
        C[k++] = A[i++];
    while (j < m)
        C[k++] = B[j++];
}

【讨论】:

  • for(;;) 代表什么?
  • @Aladin: 是一个没有条件的for循环,意思是永远循环,相当于while (true) {...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-25
  • 1970-01-01
  • 2019-09-09
  • 1970-01-01
  • 2021-10-11
相关资源
最近更新 更多