【问题标题】:Arranging odd and even numbers in a vector C++在向量 C++ 中排列奇数和偶数
【发布时间】:2020-06-25 13:12:44
【问题描述】:

我有这个问题:给定一个有 n 个数字的向量,对数字进行排序,使偶数在奇数位置,奇数在偶数位置。例如。如果我有向量 2 6 7 8 9 3 5 1,输出应该是 2 7 6 9 8 3 5 1 。计数应该从 1 开始。因此,实际上是索引 0 的位置 1 应该是偶数,实际上是索引 1 的位置 2 应该是奇数,依此类推。现在,如果奇数和偶数相同,这很容易,假设向量中有 4 个偶数和 4 个奇数,但是如果奇数的个数与上面示例中的偶数个数不同怎么办?我该如何解决。我将代码与我所做的尝试之一附加在一起,但它不起作用。我能得到一些帮助吗?我要求您保持简单,这意味着仅使用向量等。没有奇怪的方法或任何东西,因为我是初学者,我只知道基础知识。提前致谢! 不得不提的是,n initial 是全局声明的,是向量元素的个数,v_initial 是需要重新排列的元素的初始向量。

任务说将剩余的数字添加到向量的末尾。就像如果有 3 个奇数和 5 个偶数,那 2 个额外的偶数应该扔在向量的末尾

void vector_pozitii_pare_impare(int v_initial[])
{
    int v_pozitie[50],c1=0,c2=1;
    for (i = 0; i < n_initial; i++)
    {
        if (v_initial[i] % 2 == 0)
        {
            bool isTrue = 1;
            for (int k = i + 1; k < n_initial; k++)
            {
                if (v_initial[k] % 2 != 0)
                    isTrue = 0;
            }
            if (isTrue)
            {
                v_pozitie[c1] = v_initial[i];
                c1++;
            }
            else
            {
                v_pozitie[c1] = v_initial[i];
                c1 += 2;
            }
            
            
        }
        else
        {
            bool isTrue = 1;
            for (int j = i + 1; j < n_initial; j++)
            {
                if (v_initial[j] % 2 == 0)
                {
                    isTrue = 0;
                }

                if (isTrue)
                {
                    v_pozitie[c2] = v_initial[i];
                    c2++;
                }
                else
                {
                    v_pozitie[c2] = v_initial[i];
                    c2 += 2;
                }
            }
        }
    }

【问题讨论】:

  • 我在其中一次尝试中附加了代码,但它不起作用 -- 现在是学习如何使用该软件的好时机与您的编译器一起称为调试器。它允许您单步执行代码、监视变量等。
  • 如果您首先将语言更改为调用第一个元素 0,例如一个偶数位置,那么你可以说偶数值需要在偶数位置上,反之亦然。不确定这是否会导致一些混乱。您还举了一个输出应该的例子。这是唯一可能的解决方案还是众多解决方案之一?如果偶数/奇数的分布不均匀,会发生什么?我知道你在问在这种情况下该怎么做,但我在问你在这种情况下你想发生什么。
  • ",但是如果奇数个数与偶数个数不同怎么办?" - 如果任务没有澄清这种情况(或给出了一定的限制,这样这种情况就永远不会发生)我们对此无能为力。也许插入0?也许会抛出错误?该任务可能会澄清它。
  • 任务说将剩余的数字添加到向量的末尾。就像如果有 3 个奇数和 5 个偶数,则应该在向量的末尾抛出 2 个额外的偶数
  • 我建议你在写任何代码之前先把它画在纸上。看来你没有太多计划就直接开始编写代码了。

标签: c++ vector


【解决方案1】:

这可能不是一个完美的解决方案,它只是在没有经过测试或验证的情况下从我脑海中蹦出来,但这只是为了给你一个想法

(令A,B,C,D为奇数,0,1,2为偶数)

给定:

A 0 B C D 1 2(奇偶数的随机排序列表)

通缉:

A 0 B 1 C 2 D(输入序列已更改以匹配所需的奇/偶标准)

接下来,我们发明了从给予到通缉所需的步骤:

// look at 'A' -> match, next
// Result: A 0 B C D 1 2  

// look at '0' -> match, next
// Result: A 0 B C D 1 2

// look at 'B' -> match, next
// Result: A 0 B C D 1 2

// look at 'C' -> mismatch, remember index and find first match starting from index+1
// Result: A 0 B C D ->1<- 2 

// now swap the numbers found at the remembered index and the found one.
// Result: A 0 B 1 D C 2 

// continue until the whole list has been consumed.

正如我所说,这个算法可能并不完美,但我的目的是给你一个例子来说明如何解决这些问题。总是首先考虑代码是不好的,尤其是这样的问题。所以你应该首先考虑你从哪里开始,你想达到什么,然后仔细考虑如何一步一步地到达那里。

我觉得我不得不提一下,我没有提供实际代码中的示例,因为一旦你有了这个想法,执行应该非常简单。

哦,顺便说一句:您的代码几乎没有是 C++。

【讨论】:

  • 什么是 A、B、C 和 D?十六进制? A 和 C 是偶数。 B 和 D 是奇数。如果是这种情况,您的输出序列将变为 even even odd odd odd even even
  • @JohnFilleau 0, 1, 2 是一种值,A, B, C, D 是另一种值
  • 看例子,我想他想要一个稳定的结果。
  • 你在抱怨“你的代码几乎没有 C++”。首先你的代码在哪里?这是什么 ABC 东西?
  • @ArminMontigny 不,我没有抱怨它,这不是任何判断,我只是想指出这一点,因为我认为这对询问者来说可能很重要。我只是给出了一个关于算法的想法,故意没有使用特定的语言,因为我的印象是这将是实际问题的内容。
【解决方案2】:

一个简单但效率不高的解决方案是将向量拆分为 2 个向量,其中包含偶数和奇数,然后总是从偶数中取一个,从奇数中取一个,然后从未完全输入。

一些c++(实际上使用向量,但你可以用同样的方式使用数组,但需要更改指针算法) 我没有测试,但原理应该很清楚;不过效率不是很高

编辑:@AAAAAAAAAARGH 下面的答案概述了一个更好的算法思想,即就地且更高效。

void change_vector_even_uneven(std::vector<unsigned>& in_vec){
      std::vector<unsigned> even;
      std::vector<unsigned> uneven;
  
      for (auto it = in_vec.begin(); it != in_vec.end(); it++){
          if ((*it) % 2 == 0)) even.push_back(*it);
          else uneven.push_back(*it);
      }
      
      auto even_it = even.begin();
      auto uneven_it = uneven.begin();
      for (auto it = in_vec.begin(); it != in_vec.end(); it++){
          if (even_it == even.end()){
              (*it) = (*uneven_it);
              uneven_it++;
              continue; 
          }   
          if (uneven_it == uneven.end()){
              (*it) = (*even_it);
              even_it++;
              continue;
          }   
          if ((it - in_vec.begin()) % 2 == 0){
              (*it) = (*even_it);
              even_it++;
          }
          else{
              (*it) = (*uneven_it);
              uneven_it++;
          }   
      }   
  }  

【讨论】:

    【解决方案3】:

    解决方案很简单。我们将偶数和奇数排序成一个数据结构。在一个循环中,我们遍历所有源值。如果它们是偶数(val & 2 == 0),我们将它们添加到 std::deque 的末尾以表示偶数,如果是奇数,我们将它们添加到 std::deque 以表示赔率。

    稍后,我们将提取std::deque前面的值。

    所以,我们有先进先出的原则。 std::deque 已针对此类目的进行了优化。

    稍后,我们创建一个循环,其中包含一个交替分支。我们交替地从偶数队列中提取数据,然后从奇数队列中提取数据。如果队列为空,我们不会提取数据。

    我们不需要额外的std::vector,可以重复使用旧的。

    这样,我们就不需要注意相同数量的偶数和赔率。它当然会一直有效。

    请查看以下数百万种可能的解决方案之一:

    #include <iostream>
    #include <vector>
    #include <deque>
    
    int main() {
    
        std::vector testData{ 2, 6, 7, 8, 9, 3, 5, 1 };
    
        // Show initial data
        std::cout << "\nInitial data: ";
        for (const int i : testData) std::cout << i << ' ';
        std::cout << '\n';
    
        // We will use a deques to store odd and even numbers
        // With that we can efficiently push back and pop front
        std::deque<int> evenNumbers{};
        std::deque<int> oddNumbers{};
    
        // Sort the original data into the specific container
        for (const int number : testData)
            if (number % 2 == 0) 
                evenNumbers.push_back(number);
            else 
                oddNumbers.push_back(number);
    
        // Take alternating the data from the even and the odd values
        bool takeEven{ true };
        for (size_t i{}; !evenNumbers.empty() && !oddNumbers.empty(); ) {
    
            if (takeEven) {  // Take even numbers
                if (not evenNumbers.empty()) {          // As long as there are even values
                    testData[i] = evenNumbers.front();  // Get the value from the front
                    evenNumbers.pop_front();            // Remove first value
                    ++i;
                }
            } 
            else { // Now we take odd numbers
                if (not oddNumbers.empty()) {           // As long as there are odd values
                    testData[i] = oddNumbers.front();   // Get the value from the front
                    oddNumbers.pop_front();             // Remove first value
                    ++i;
                }
            }
            // Next take the other container
            takeEven = not takeEven;
        }
    
        // Show result
        std::cout << "\nResult:       ";
        for (const int i : testData) std::cout << i << ' ';
        std::cout << '\n';
    
        return 0;
    }
    

    【讨论】:

      【解决方案4】:

      这是另一种解决方案(使用 STL),以防您想要 稳定 的结果(也就是说,您的值的顺序被保留)。

        #include <algorithm>
        #include <vector>
      
        auto ints = std::vector<int>{ 2, 6, 7, 8, 9, 3, 5, 1 };
      
        // split list to even/odd sections -> [2, 6, 8, 7, 9, 3, 5, 1]
        const auto it = std::stable_partition(
          ints.begin(), ints.end(), [](auto value) { return value % 2 == 0; });
      
        auto results = std::vector<int>{};
        results.reserve(ints.size());
      
        // merge both parts with equal size
        auto a = ints.begin(), b = it;
        while (a != it && b != ints.end()) {
          results.push_back(*a++);
          results.push_back(*b++);
        }
      
        // copy remaining values to end of list
        std::copy(a, it, std::back_inserter(results));
        std::copy(b, ints.end(), std::back_inserter(results));
      

      结果是[2, 7, 6, 9, 8, 3, 5, 1]。复杂度为O(n)

      【讨论】:

        【解决方案5】:

        与其他一些答案一样,此答案会划分数据,然后重新组合结果。标准库std::partition_copy 用于将偶数和奇数分隔到两个容器中。然后interleave 函数通过从两个输入范围交替复制来组装结果。

        #include <algorithm>
        #include <iostream>
        #include <vector>
        
        template <typename InIt1, typename InIt2, typename OutIt>
        OutIt interleave(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt dest)
        {
            for (;;) {
                if (first1 == last1) {
                    return std::copy(first2, last2, dest);
                }
                *dest++ = *first1++;
        
                if (first2 == last2) {
                    return std::copy(first1, last1, dest);
                }
                *dest++ = *first2++;
            }
        }
        
        void reorder_even_odd(std::vector<int> &data)
        {
            auto is_even = [](int value) { return (value & 1) == 0; };
        
            // split
            std::vector<int> even, odd;
            std::partition_copy(begin(data), end(data), back_inserter(even), back_inserter(odd), is_even);
        
            // merge
            interleave(begin(even), end(even), begin(odd), end(odd), begin(data));
        }
        
        int main()
        {
            std::vector<int> data{ 2, 6, 7, 8, 9, 3, 5, 1 };
        
            reorder_even_odd(data);
        
            for (int value : data) {
                std::cout << value << ' ';
            }
            std::cout << '\n';
        }
        

        Demo on Compiler Explorer

        【讨论】:

          【解决方案6】:

          按照建议,我正在使用向量和 STL。 无需成为伟大的数学家即可理解 v_pozitie 将从奇数对和偶数对开始,并以不在初始对中的整数结束。 然后我在 v_positie 中更新三个迭代器(不需要临时容器来计算结果):偶数、奇数和结束,(避免 push_back)并且会这样编码:

          #include <vector>
          #include <algorithm>
          
          void vector_pozitii_pare_impare(std::vector<int>& v_initial, std::vector<int>& v_pozitie) {
          
            int nodd (0), neven (0);
            std::for_each (v_initial.begin (), v_initial.end (), [&nodd] (const int& n) {
              nodd += n%2;
            });
            neven = v_initial.size () - nodd;
          
            int npair (neven < nodd ?neven:nodd); 
            npair *=2;
            std::vector<int>::iterator iend (&v_pozitie [npair]), ieven (v_pozitie.begin ()), iodd (&v_pozitie [1]);
          
            std::for_each (v_initial.begin (), v_initial.end (), [&iend, &ieven, &iodd, &npair] (const int& s) {
              if (npair) {
                switch (s%2) {
                case 0 :
                  *ieven++ = s;
                  ++ieven;
                  break;
                case 1 :
                  *iodd++ = s;
                  ++iodd;
                  break;
                }
                --npair;
              }
              else *iend++ = s;
            });
          }
          
          int main (int argc, char* argv []) {
            const int N = 8;
            int tab [N] = {2, 6, 7, 8, 9, 3, 5, 1};
            std::vector<int> v_initial (tab, (int*)&tab [N]);
            std::cout << "\tv_initial == ";
            std::for_each (v_initial.begin (), v_initial.end (), [] (const int& s) {std::cout << s << "  ";});
            std::cout << std::endl;
          
            std::vector<int> v_pozitie (v_initial.size (), -1);
            vector_pozitii_pare_impare (v_initial, v_pozitie);
            
            std::cout << "\tv_pozitie == ";
            std::for_each (v_pozitie.begin (), v_pozitie.end (), [] (const int& s) {std::cout << s << "  ";});
            std::cout << std::endl;  
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-02-12
            • 2016-06-13
            • 2016-04-25
            • 2021-11-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多