如何编写一个修改列表的函数,以便复制所有奇数元素并删除所有偶数元素?

How do I write a function that modifies a list such that all odd elements get duplicated and all even elements removed?

我正在尝试编写一个函数,通过删除偶数和复制奇数来修改数组列表。 我的代码在删除偶数方面工作得很好。但是,它只会复制一些奇数。

例如。我的列表包含:12 11 13 14 15 13 10 L.duplicateORremove() 之后的列表 L 应包含: 11 11 13 13 15 15 13 13

但这就是我得到的:11 13 13 15 13 13

我需要一些帮助来弄清楚为什么我会得到这个结果。

到目前为止,这是我的代码:

template <class Type>
void arrayListType <Type>::duplicateORremove()
{
    for(int i=0; i<length; i++)
    {
        if(list[i]%2==0)
        {
            for (int j = i; j < length - 1; j++)
              list[j] = list[j + 1];
            length--;
        }
        else
        {
            for (int j = length; j > i; j--)
              list[j] = list[j - 1]; 
            list[i+1] = list[i];
            i++;
            length++;
        }
    }
}

这就是我的 class 定义和主要内容的样子:

template < class Type >
  class arrayListType {
    public:
      arrayListType(int size = 100);
      ~arrayListType();
      void insertEnd(const Type & insertItem);
      void print() const;
      void duplicateORremove();

    protected:
      Type * list; //array to hold the list elements
      int length; //stores length of list
      int maxSize; //stores maximum size of the list
  };

template < class Type >
  arrayListType < Type > ::arrayListType(int size) {
    if (size < 0) {
      cerr << "The array size must be positive. Creating " <<
        "an array of size 100. " << endl;
      maxSize = 100;
    } else
      maxSize = size;
    length = 0;
    list = new Type[maxSize];
    assert(list != NULL);
  }

template < class Type >
  arrayListType < Type > ::~arrayListType() {
    delete[] list;
  }

template < class Type >
void arrayListType < Type > ::insertEnd(const Type & insertItem) {
    if (length >= maxSize)
      cerr<<"Cannot insert in a full list" << endl;
    else {
      list[length] = insertItem; 
      length++;
    }
  }

template < class Type >
void arrayListType < Type > ::print() const {
    for (int i = 0; i < length; i++)
      cout << list[i] << " ";
    cout << endl;
}
int main()
{
    arrayListType <int> L;
    L.insertEnd(12);
    L.insertEnd(11);
    L.insertEnd(13);
    L.insertEnd(14);
    L.insertEnd(15);
    L.insertEnd(13);
    L.insertEnd(10);
    cout << "List L before L.duplicateORremove() contains:" << endl;
    L.print();
    L.duplicateORremove();
    cout << "List L after L.duplicateORremove() contains:" << endl;
    L.print();

这是一个使用 Range-v3 库的解决方案。

  • 您可以对原始范围的视图进行操作。
  • 删除偶数元素。
  • 复制剩余列表的每个元素(奇数)。
  • 然后将视图转换回矢量并return它。

[Demo]

#include <fmt/ranges.h>
#include <range/v3/all.hpp>

template <typename Range>
auto duplicate_or_remove(Range&& r) {
    using namespace ranges::v3;

    auto even = [](int i) { return 0 == i % 2; };
    
    return r
        | views::remove_if(even)
        | views::for_each([](auto e){ return yield_from(views::repeat_n(e, 2)); })
        | to_vector;
}

int main() {
    std::vector<int> v{12, 11, 13, 14, 15, 13, 10};
    fmt::print("{}", duplicate_or_remove(v));
}

// Outputs:
//
//   [11, 11, 13, 13, 15, 15, 13, 13]

回到您的代码,注意您不能简单地处理您的输入列表。如果列表只包含奇数会怎样?对于第一个元素,您将超出为列表保留的内存。相反,如果你需要坚持使用数组,你可以做的是:

  • 计算输入列表中的奇数元素。
  • 创建一个新数组,其大小是输入列表中奇数元素数量的两倍。
  • 遍历输入列表,对于每个奇数元素,将其添加到新创建的数组中两次。
  • Return 由新数组及其大小组成的一对。
  • 如果您传递的是数组而不是指针,下面的代码还使用了一个很好的技巧来避免将数组的长度传递给函数。

[Demo]

#include <iostream>  // cout
#include <utility>  // pair

auto is_odd = [](int i){ return (i % 2) == 1; };

template <size_t length>
size_t count_odd_elements(int (&list)[length]) {
    size_t ret{};
    for (size_t i{0}; i < length; ++i) {
        if (is_odd(list[i])) {
            ret++;
        }
    }
    return ret;
}

template <size_t length>
auto duplicate_or_remove(int (&list)[length]) {
    size_t odd_elements{ count_odd_elements(list) };

    size_t ret_size{odd_elements * 2};
    int* ret = new int[ret_size];

    size_t head{};
    for (size_t i{0}; i < length; ++i) {
        int n{ list[i] };

        if (is_odd(n)) {
            ret[head++] = n;
            ret[head++] = n;
        }
    }

    return std::pair<int*, size_t>{ret, ret_size};
}

void print_list(int list[], size_t length) {
    std::cout << "[";
    for (size_t i{0}; i < length; ++i) {
        std::cout << ((i == 0) ? "" : ", ") << list[i];
    }
    std::cout << "]";
}

int main() {
    int arrlist[] = {12, 11, 13, 14, 15, 13, 10};
    auto [result, result_size] = duplicate_or_remove(arrlist);
    print_list(result, result_size);
    delete[] result;
}

// Outputs:
//
//   [11, 11, 13, 13, 15, 15, 13, 13]

同样,使用 std::vector 而不是数组可以简化很多事情:

[Demo]

#include <fmt/ranges.h>
#include <iostream>  // cout
#include <vector>

auto is_odd = [](int i){ return (i % 2) == 1; };

auto duplicate_or_remove(const std::vector<int>& list) {
    std::vector<int> ret{};
    for (auto i : list) {
        if (is_odd(i)) {
            ret.push_back(i);
            ret.push_back(i);
        }
    }
    return ret;
}

int main() {
    std::vector<int> v{12, 11, 13, 14, 15, 13, 10};
    auto result{ duplicate_or_remove(v) };
    fmt::print("{}", result);
}
#include <iostream>

using namespace std;
void duplicateORremove(int list[], int length) {

    for(int i=0; i<length; i++)
    {
        if(list[i]%2==0)
        {
            for (int j = i; j < length - 1; j++)
              list[j] = list[j + 1];
            length--;
            i-=1;
        }
        else
        {
            for (int j = length; j > i; j--)
              list[j] = list[j - 1]; 
            list[i+1] = list[i];
            i++;
            length++;
        }
    }
    for (int i=0; i<length; i++) {
        cout << list[i];
        cout << " ";
    }
}

int main()
{
    int arrlist[] = {12, 11, 13, 14, 15, 13, 10};
    duplicateORremove(arrlist, 7);
    return 0;
}

您没有重置 'i' 值以在找到偶数时从之前的状态遍历。由于在循环时跳过了奇数代替偶数,因此您最终会得到一个结果中缺少某些值的结果。缺失值的数量将等于您输入中偶数的数量。

只需添加重置条件即可。

Link到运行以上代码:Online cpp compiler