Удаление четного числа в массиве и сдвиг элементов - PullRequest
2 голосов
/ 02 мая 2019

Я пытаюсь написать код, в котором проводится исследование четных чисел, затем удаляются четные числа, а затем сдвигаются все остальные элементы.

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 ]

3 голосов
/ 02 мая 2019

Это похоже на домашнее задание или школьное задание. Так в чем же проблема с размещенным кодом?

Дело в том, что когда вы удаляете четное число по индексу i, вы помещаете число, которое раньше было по индексу i + 1, в индекс i. Затем вы продолжите итерацию внешнего цикла, которая проверит индекс i + 1, который является числом, которое было в исходной позиции i + 2 в массиве. Таким образом, число, которое начиналось с Array[i + 1], а теперь находится в Array[i], никогда не проверяется.

Простой способ исправить это - уменьшить i при уменьшении N.

1 голос
/ 03 мая 2019

Несмотря на то, что я уже ответил, мне не удается понять причину, по которой люди продвигаются через двойной цикл, повторяя данные снова и снова, с каждым сокращением.

Я полностью согласен со всеми советами по использованию контейнеров. Кроме того, решение для алгоритмов не требует контейнера (вы можете использовать его в собственном массиве), но контейнеры по-прежнему делают его проще и чище. Тем не менее ...

Я описал этот алгоритм в общем комментарии выше. вам не нужны вложенные циклы для этого. Вам нужен указатель чтения и указатель записи. Вот и все .

#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';
}

Те же результаты.

0 голосов
/ 02 мая 2019

Идиоматическим решением в 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

0 голосов
/ 02 мая 2019

Вы можете использовать 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";
    }
}
...