删除数组中的偶数并移动元素

时间:2019-05-02 17:39:18

标签: c++ arrays shift

我正在尝试编写一个研究偶数的代码,然后删除偶数,然后移动所有其他元素。

i 用于偏移量,是数组中元素的实际位置。

k 是数组中偶数的位置。

int k;
for(i=0; i < N; i++)
{
    if(Array[i] % 2 == 0)
    {
       for(k=i+1; k < N; k++)
       {
            Array[k-1] = Array[k];
       }
       N--;
    }
}

Array = [2,10,3,5,8,7,3,3,7,10] 应该删除偶数,但是10 保持在 Array = [10,3,5,7,3,3,7]。

现在我要花3个多小时来弄清楚代码中有什么问题。

4 个答案:

答案 0 :(得分:3)

这似乎是某种家庭作业或学校作业。那么所发布的代码的实际问题是什么?

这是当您删除索引i上的偶数时,您将曾经在索引i + 1上的数字放到索引i中。然后,继续外循环迭代,这将检查索引i + 1,它是数组中原始i + 2位置的数字。因此,永远不会检查从Array[i + 1]开始到现在在Array[i]中的数字。

解决此问题的一种简单方法是递减i时递减N

答案 1 :(得分:1)

尽管已经回答了,但我看不到人们通过双重for循环来驱动这一点的原因,每次重复减少一次又一次地重复移动数据。

我完全同意有关使用容器的所有建议。此外,算法解决方案不需要容器(您可以可以在本机阵列上使用它),但是容器仍然使容器更容易和更清洁。那就是...

我在上面的一般注释中描述了该算法。您不需要嵌套循环。您需要一个读指针和一个写指针。 就是这样

#include <iostream>

size_t remove_even(int *arr, size_t n)
{
    int *rptr = arr, *wptr = arr;

    while (n-- > 0)
    {
        if (*rptr % 2 != 0)
            *wptr++ = *rptr;
        ++rptr;
    }
    return (wptr - arr);
}

int main()
{
    int arr[] = { 2,10,3,5,8,7,3,3,7,10 };
    size_t n = remove_even(arr, sizeof arr / sizeof *arr);

    for (size_t i=0; i<n; ++i)
        std::cout << arr[i] << ' ';
    std::cout << '\n';
}

输出

3 5 7 3 3 7 

如果您认为这没什么用,我邀请您用一百万个随机整数填充数组,然后尝试两种解决方案(“嵌套循环”方法与上面看到的方法)。


在本机阵列上使用std::remove_if

仅出于清楚起见而提供,上面的代码基本上完成标准算法std::remove_if的工作。我们需要做的就是提供迭代器(数组的偏移量和大小会很好地工作),并且知道如何解释结果。

#include <iostream>
#include <algorithm>

int main()
{
    int arr[] = { 2,10,3,5,8,7,3,3,7,10 };
    auto it = std::remove_if(std::begin(arr), std::end(arr),
                             [](int x){ return x%2 == 0; });

    for (size_t i=0; i<(it - arr); ++i)
        std::cout << arr[i] << ' ';
    std::cout << '\n';
}

相同的结果。

答案 2 :(得分:0)

您可以使用std::vector和标准函数std::erase_if +向量erase函数来做到这一点:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> Array = {2, 10, 3, 5, 8, 7, 3, 3, 7, 10};

    auto it = std::remove_if(
        Array.begin(),
        Array.end(),
        [](int x) { return (x & 1) == 0 && x != 10; }
    );

    Array.erase(it, Array.end());

    for(int x : Array) {
        std::cout << x << "\n";
    }
}

输出:

10
3
5
7
3
3
7
10

编辑:很难做到:

#include <iostream>

int main() {
    int Array[] = {2, 10, 3, 5, 8, 7, 3, 3, 7, 10};
    size_t N = sizeof(Array) / sizeof(int);

    for(size_t i = 0; i < N;) {
        if((Array[i] & 1) == 0 && Array[i] != 10) {
            for(size_t k = i + 1; k < N; ++k) {
                Array[k - 1] = Array[k];
            }
            --N;
        } else
            ++i; // only step i if you didn't shift the other values down
    }
    for(size_t i = 0; i < N; ++i) {
        std::cout << Array[i] << "\n";
    }
}

或更简单:

#include <iostream>

int main() {
    int Array[] = {2, 10, 3, 5, 8, 7, 3, 3, 7, 10};
    size_t N = sizeof(Array) / sizeof(int);
    size_t k = 0;

    for(size_t i = 0; i < N; ++i) {
        if((Array[i] & 1) || Array[i] == 10) {
            // step k after having saved this value 
            Array[k++] = Array[i];
        }
    }
    N = k;
    for(size_t i = 0; i < N; ++i) {
        std::cout << Array[i] << "\n";
    }
}

答案 3 :(得分:0)

在C ++中,惯用的解决方案是使用STL算法。

此示例使用C样式数组。

int Array[100] = {2,10,3,5,8,7,3,3,7,10};
int N = 10;

// our remove_if predicate
auto removeEvenExceptFirst10 = [first10 = true](int const& num) mutable {
    if (num == 10 && first10) {
        first10 = false;
        return false;
    }

    return num % 2 == 0;
};

auto newN = std::remove_if(
    std::begin(Array), std::begin(Array) + N,
    removeEvenExceptFirst10
);

N = std::distance(std::begin(Array), newN);

Live demo