Удаление элементов из массива

328
22 марта 2017, 18:31

Нужно удалить чётные элементы из массива. Как сделать так, чтобы элемент удалялся, а не просто вместо него был 0.

#include <iostream>
#include <ctime>
using namespace std;
int main(int argc, char *argv[])
{
setlocale(LC_ALL, "Russian");
srand(time(0));
int *ptr = new int [100];
    for(int i = 0; i < 10; i++){
        ptr[i] = (rand() % 100);
        cout << ptr[i] << "\t";
        if (ptr[i] % 2 == 0)
            ptr[i] = ptr[i + 1];
    }
    cout << endl;
    for(int i = 0; i < 10; i++)
        cout << ptr[i] << "\t";
    delete [] ptr;
    cout << endl;
return 0;
}

Answer 1

Выберите, какой из способов вам больше подходит.

#include <iostream>
#include <stdlib.h>
using namespace std;
int main ()
{
  int *p = new int [100];
  int n = 0;
  // первый способ: сразу заносим в массив только нечетные
  for (int i = 0; i < 10; i++) {
    p[n] = rand() % 100;
    cout << p[n] << ' ';
    if (p[n] % 2)
      n++;
  }
  cout << '\n';
  for (int i = 0; i < n; i++)
    cout << p[i] << ' ';
  cout << '\n';

  // второй способ: заносим любые 10
  for (int i = 0; i < 10; i++) {
    p[i] = rand() % 100;
    cout << p[i] << ' ';
  }
  cout << '\n';
  n = 0;
  // выбрасываем четные
  for (int i = 0; i < 10; i++)
    if (p[i] % 2)
      p[n++] = p[i];
  for (int i = 0; i < n; i++)
    cout << p[i] << ' ';
  cout << '\n';
  delete [] p;
}

В любом случае переменная n содержит количество нужных элементов в массиве.

Answer 2
// l - размер массива
int j = 0;
for (int i = 0; i < l; i++) if (ptr[i] % 2) ptr[j++] = ptr[i];
// теперь j - новый размер массива

Если же четные числа нужно фильтровать при заполнении массива, то их можно просто сразу делать нечетными:

ptr[i] = (rand() % 50) * 2 + 1;
Answer 3

Сначала замечание относительно вашего кода. В данном цикле

for(int i = 0; i < 10; i++){
    ptr[i] = (rand() % 100);
    cout << ptr[i] << "\t";
    if (ptr[i] % 2 == 0)
        ptr[i] = ptr[i + 1];
}

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

Это плохой стиль программирования, когда в один цикл пытаются "впихнуть" решение нескольких задач одновременно. Во-первых, такой код не является повторно используемым, так как в каждом отдельном случае не все задачи, которые решаются в первоначальном цикле, потребуются в последующем.

Во-вторых, такой код осложняет его понимание, так как логика программы, когда все смешано в одной "куче", не всегда является интуитивно понятной.

В-третьих, такой код обычно ведет к появлению ошибок и сложностям в его отладке.

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

Относительно вашей программы это означает, что

  1. программа должна сначала инициализировать массив;
  2. программа должна вывести инициализированный массив на консоль;
  3. программа должна "удалить" четные элементы из массива;
  4. вывести на консоль ту часть массива, которая содержит актуальные элементы после удаления из массива элементов с четными значениями.

К тому же непонятно, почему выделяется массив из 100 элементов, а в цикле используется значение для обработки 10 элементов.

В массиве нельзя удалить элементы. Можно лишь переписать значения его элементов и хранить значение числа актуальных элементов в массиве, которое может быть меньше или равно общему числу элементов в массиве. Или же можно динамически создать новый массив и туда переписать элементы, удовлетворяющие выбранному критерию.

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

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

#include <iostream>
#include <algorithm>
#include <iterator>
#include <cstdlib>
#include <ctime>
int main() 
{
    const size_t N = 20;
    int a[N];
    std::srand( ( unsigned int )std::time( nullptr ) );
    std::generate( std::begin( a ), std::end( a ), [=] { return std::rand() % N; } );
    for ( auto x : a ) std::cout << x << ' ';
    std::cout << std::endl;
    size_t n = std::distance( std::begin( a ), 
        std::remove_if( std::begin( a ), std::end( a ), []( int x ) { return x % 2 == 0; } ) );

    for ( size_t i = 0; i < n; i++ ) std::cout << a[i] << ' ';
    std::cout << std::endl;
    return 0;
}

Вывод программы на консоль может выглядеть следующим образом

6 19 3 5 16 8 7 8 10 12 1 6 13 6 15 6 16 5 16 19 
19 3 5 7 1 13 15 5 19 

В этой программе используется массив из 20 элементов (вы можете использовать любое число в пределах разумного для размера массива). После "удаления" элементов с четными значениями, в программе сохраняется число актуальных элементов в массиве в переменной n.

Вот та же самая программа, но без использования стандартных алгоритмов.

#include <iostream>
#include <cstdlib>
#include <ctime>
int main() 
{
    const size_t N = 20;
    int a[N];
    std::srand( ( unsigned int )std::time( nullptr ) );
    for ( size_t i = 0; i < N; i++ ) a[i] = std::rand() % N;
    for ( auto x : a ) std::cout << x << ' ';
    std::cout << std::endl;
    size_t n = 0;
    for ( size_t i = 0; i < N; i++ )
    {
        if ( a[i] % 2 != 0 )
        {
            if ( i != n ) a[n] = a[i];
            ++n;
        }
    }
    for ( size_t i = 0; i < n; i++ ) std::cout << a[i] << ' ';
    std::cout << std::endl;
    return 0;
}

Если вы действительно хотите удалить четные элементы из массива, то массив придется распределять динамически. Затем следует подсчитать число нечетных элементов в исходном массиве. Распределить динамически массив с числом элементов, равных числу нечетных элементов в массиве, и переписать их в новый массив. В этом случае программа может выглядеть следующим образом

#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <ctime>
int main() 
{
    const size_t N = 20;
    int *a = new int[N];
    std::srand( ( unsigned int )std::time( nullptr ) );
    std::generate_n( a, N, [=] { return std::rand() % N; } );
    for ( size_t i = 0; i < N; i++ ) std::cout << a[i] << ' ';
    std::cout << std::endl;
    auto odd = []( int x ) { return x % 2 != 0; };
    size_t n = std::count_if( a, a + N, odd );
    int *tmp = new int[n];
    std::copy_if( a, a + N, tmp, odd );
    delete [] a;
    a = tmp;
    for ( size_t i = 0; i < n; i++ ) std::cout << a[i] << ' ';
    std::cout << std::endl;
    delete [] a;
    return 0;
}

Ее вывод на консоль, к примеру, будет

17 4 19 12 13 17 17 4 3 16 6 19 12 14 3 9 16 9 10 10 
17 19 13 17 17 3 19 3 9 9 

Та же самая программа без использования стандартных алгоритмов может иметь следующий вид

#include <iostream>
#include <cstdlib>
#include <ctime>
int main() 
{
    const size_t N = 20;
    int *a = new int[N];
    std::srand( ( unsigned int )std::time( nullptr ) );
    for ( size_t i = 0; i < N; i++ ) a[i] = std::rand() % N;
    for ( size_t i = 0; i < N; i++ ) std::cout << a[i] << ' ';
    std::cout << std::endl;
    size_t n = 0;
    for ( size_t i = 0; i < N; i++ )
    {
        n += a[i] % 2 != 0;
    }
    int *tmp = new int[n];
    for ( size_t i = 0, j = 0; i < N; i++ )
    {
        if ( a[i] % 2 != 0 ) tmp[j++] = a[i];
    }
    delete [] a;
    a = tmp;
    for ( size_t i = 0; i < n; i++ ) std::cout << a[i] << ' ';
    std::cout << std::endl;
    delete [] a;
    return 0;
}

Когда имеет место динамическое выделение памяти для массивов, то в этом случае лучше иметь дело со стандартным классом std::vactor, который сам будет следить за правильным перераспределением памяти. Программа для вектора может выглядеть как

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <cstdlib>
#include <ctime>
int main() 
{
    const size_t N = 20;
    std::vector<int> v;
    v.reserve( N );
    std::srand( ( unsigned int )std::time( nullptr ) );
    std::generate_n( std::back_inserter( v ), N, [=] { return  std::rand() % N; } );
    for ( int x : v  ) std::cout << x << ' ';
    std::cout << std::endl;
    v.erase( std::remove_if( v.begin(), v.end(), []( int x ){ return x % 2 == 0; } ),
             v.end() );
    for ( int x : v  ) std::cout << x << ' ';
    std::cout << std::endl;
    return 0;
}

Примерный вывод программы на консоль:

0 7 17 6 18 17 14 10 6 19 12 1 5 4 11 19 9 18 13 14 
7 17 17 19 1 5 11 19 9 13 
Answer 4

Либо создавать новый массив, исключая выбранные элементы, либо использовать контейнеры (std::vector или std::list).
Они имеют метод erase(const_iterator position), принимающий итератор удаляемого элемента.

В вашем случае намного проще будет сначала делать проверку на четность, а потом уже добавлять элемент в массив:

#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
int main()
{
    srand(time(NULL));
    std::vector<int> v;
    for(int i = 0; i < 10; ++i)
    {
        int val = rand() % 100;
        std::cout << val << "\t";
        if(val % 2 != 0)
            v.push_back(val);
    }
    std::cout << std::endl;
    for(int i = 0; i < v.size(); ++i)
    {
        std::cout << v[i] << "\t";
    }
    std::cout << std::endl;
}
Answer 5
// k - индекс
// n - размер массива
for (int i(k); i < n; i++)
{
   a[i] = a[i+1]
}
n--;
READ ALSO
перезадание переменной типа &ldquo;класс&rdquo;

перезадание переменной типа “класс”

Не совсем понимаю, как работать с классами в си

192
Компаратор для set [требует правки]

Компаратор для set [требует правки]

Подскажите пожалуйста как написать свой компаратор для setЭто будет использоваться в целях спортивного программирования

313
Перевод const char* в const u_char*

Перевод const char* в const u_char*

Я работаю с двумя функциями из сторонних библиотекОдна возвращает const char*, а другая принимает const u_char*

217