c ++取消数组元素,并相应地取消第二个数组中的元素 [英] c++ cancel array elements and cancel elements in second array accordingly

查看:175
本文介绍了c ++取消数组元素,并相应地取消第二个数组中的元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在c ++中,我有三个数组, int 数组被排序。第一个数组用重复值填充,第二个数组用第一个数组中指示无效值的值填充,最后一个数组存储 float 值。例如:

  int n = 11; 
int * val = new int [n] {1,1,2,2,2,2,3,4,5,5,5};
float * val2 = new float [n] {0.5,0.5,0.25,0.25,0.25,0.25,1,1,0.33,0.33,0.33};

int * invalid = new int [2] {2,5};

现在复制存储在 val 有效(即除 2 5 )并将对应于 val 中的有效值的 val2 中的值复制到 valid2 ,即除 0.25 0.33 之外的每个值,因为 code>对应于 0.25 (所有2个都位于 2-5 作为0.25的位置)和 5 对应于 0.33 (所有5个都位于 8-10 作为0.33的)。
然后输出应该像这样

  int * valid = new int [4] {1,1,3 ,4}; 
float * valid2 = new int [4] {0.5,0.5,1,1}

如何使用for循环有效地实现这个?我想指出,我不能切换到容器像矢量或列表,因为我知道将有这方面的意见。我需要使用数组。

解决方案

我们的初学者应该互相帮助:)



由于数组无效只有两个元素,因此您可以使用以下直接方法

  #include< iostream> 
#include< algorithm>
#include< iterator>

int main()
{
const size_t N = 11;
int * val = new int [N] {1,1,2,2,2,2,3,4,5,5,5};
float * val2 = new float [N] {0.5,0.5,0.25,0.25,0.25,0.25,1,1,0.33,0.33,0.33};


int * invalid = new int [2] {2,5};
int * valid = nullptr;
float * valid2 = nullptr;

auto is_valid_element = [=](int x){return x!= invalid [0]&& x!= invalid [1]; };

auto n = std :: count_if(val,val + N,is_valid_element);

if(n)
{
valid = new int [n];
valid2 = new float [n];

for(size_t i = 0,j = 0; i {
if(is_valid_element(val [i]))
{
valid [j] = val [i];
valid2 [j] = val2 [i];
j ++;
}
}
}

if(n)
{
std :: copy(valid,valid + n,std :: ostream_iterator< int>(std :: cout,));
std :: cout<< std :: endl;
std :: copy(valid2,valid2 + n,std :: ostream_iterator< float>(std :: cout,));
std :: cout<< std :: endl;
}

delete [] val;
delete [] val2;
delete [] invalid;
delete [] valid;
delete [] valid2;

return 0;
}

程序输出是

  1 1 3 4 
0.5 0.5 1 1

如果数组无效或数组val很大,那么首先可以在数组val中找到数组的第一个元素的下界无效,并从下界元素的索引开始。



因此,在循环之前,您应该使用标准算法 std :: lower_bound std :: upper_bound 找到循环的数组val中的第一个和最后一个实际索引。要确定数组中是否存在元素 invalid ,可以使用标准算法 std :: binary_search



这里是一个演示程序

  #include< iostream> 
#include< algorithm>
#include< iterator>

int main()
{
const size_t N = 11;
const size_t M = 2;

int * val = new int [N] {1,1,2,2,2,2,3,4,5,5,5};
float * val2 = new float [N] {0.5,0.5,0.25,0.25,0.25,0.25,1,1,0.33,0.33,0.33};
int * invalid = new int [M] {2,5};

int * valid = nullptr;
float * valid2 = nullptr;

auto it = std :: lower_bound(val,val + N,invalid [0]);
size_t lower = std :: distance(val,it);

it = std :: upper_bound(it,val + N,invalid [M-1]);
size_t upper = std :: distance(val,it);

auto invalid_element = [=](int x){return std :: binary_search(invalid,invalid + M,x); };

size_t n = N - std :: count_if(val + lower,val + upper,invalid_element);

if(n)
{
valid = new int [n];
valid2 = new float [n];

size_t i = 0;
for(size_t j = 0; j< lower; i ++,j ++)
{
valid [i] = val [j]
valid2 [i] = val2 [j];
}

for(size_t j = lower; j< upper; j ++)
{
if(!invalid_element(val [j]))
{
valid [i] = val [j];
valid2 [i] = val2 [j];
i ++;
}
}

for(size_t j = upper; j {
valid [i] j]。
valid2 [i] = val2 [j];
}
}

if(n)
{
std :: copy(valid,valid + n,std :: ostream_iterator< int> std :: cout,));
std :: cout<< std :: endl;
std :: copy(valid2,valid2 + n,std :: ostream_iterator< float>(std :: cout,));
std :: cout<< std :: endl;
}

delete [] val;
delete [] val2;
delete [] invalid;
delete [] valid;
delete [] valid2;


return 0;
}

其输出为

  1 1 3 4 
0.5 0.5 1 1



p>这个程序比第一个程序更大,但同时更高效:)



你可以做更专业的程序。例如你可以替换语句

  size_t n = N-std :: count_if(val + lower,val + upper,invalid_element) ; 

  size_t n = N-std :: count_if(std :: next(val,lower),std :: next(val,upper),invalid_element); 

或者使用带索引的循环,而不是使用循环迭代器。



然而,最有效的方法是编写一个类似于标准算法 std :: set_difference p>

这是一个演示程序

  #include< iostream> 
#include< algorithm>
#include< iterator>

int main()
{
const size_t N = 11;
const size_t M = 2;

int * val = new int [N] {1,1,2,2,2,2,3,4,5,5,5};
float * val2 = new float [N] {0.5,0.5,0.25,0.25,0.25,0.25,1,1,0.33,0.33,0.33};
int * invalid = new int [M] {2,5};

int * valid = nullptr;
float * valid2 = nullptr;

auto it = std :: lower_bound(val,val + N,invalid [0]);
size_t lower = std :: distance(val,it);

it = std :: upper_bound(it,val + N,invalid [M-1]);
size_t upper = std :: distance(val,it);

size_t i; // index in val;
size_t j; // index in invalid;
size_t n; // val中有效元素的总数

i = lower;
j = 0;
n = 0;

//计数无效元素
while(i!= upper)
{
if(val [i] {
++ i;
}
else if(invalid [j]< val [i])
{
++ j;
}
else
{
++ i;
++ n;
}
}

n = N - n;

if(n)
{
valid = new int [n];
valid2 = new float [n];

size_t k; // index in valid and valid2

i = j = k = 0;

while(i!= N&& j!= M)
{
if(val [i] {
valid [k] = val [i];
valid2 [k] = val2 [i];
++ k;
++ i;
}
else if(invalid [j]< val [i])
{
++ j;
}
else
{
++ i;
}
}

for(; i!= N; k ++,i ++)
{
valid [k] = val [i]
valid2 [k] = val2 [i];
}
}

if(n)
{
std :: copy(valid,valid + n,std :: ostream_iterator< int> std :: cout,));
std :: cout<< std :: endl;
std :: copy(valid2,valid2 + n,std :: ostream_iterator< float>(std :: cout,));
std :: cout<< std :: endl;
}

delete [] val;
delete [] val2;
delete [] invalid;
delete [] valid;
delete [] valid2;

return 0;
}

其输出与上述相同

  1 1 3 4 
0.5 0.5 1 1


In c++ I got three arrays, the int arrays are sorted. The first array is filled with repeating values, the second one is filled with values that indicate an invalid value in the first array and the last one stores float values. For example:

int n = 11;
int   * val = new int[n]{1, 1, 2, 2, 2, 2, 3, 4, 5, 5, 5};
float * val2 = new float[n] {0.5, 0.5, 0.25, 0.25, 0.25, 0.25, 1, 1, 0.33, 0.33, 0.33};

int * invalid = new int[2]{ 2, 5};

Now copy the valid values stored in val to valid (i.e. every value except for 2 and 5) and copy the values in val2 corresponding to the valid values in val to valid2, i.e. every value except 0.25 and 0.33, because 2 corresponds to 0.25 (all 2's are on positions 2-5 as the 0.25's), and 5 corresponds to 0.33 (all 5's are on positions 8-10 as the 0.33's). Then the output shall be like this

int * valid = new int[4]{ 1, 1, 3, 4};
float * valid2 = new int[4]{0.5, 0.5, 1, 1}

How can I implement this efficiently using a for loop? I want to point out that I can not switch to containers like vector or list, because I know there will be comments going in that direction. I explicitly need to work with arrays.

解决方案

We beginners should help each other.:)

As the array invalid has only two elements then you can use the following straightforward approach

#include <iostream>
#include <algorithm>
#include <iterator>

int main() 
{
    const size_t N = 11;
    int   *val  = new int[N] { 1, 1, 2, 2, 2, 2, 3, 4, 5, 5, 5 };
    float *val2 = new float[N] { 0.5, 0.5, 0.25, 0.25, 0.25, 0.25, 1, 1, 0.33, 0.33, 0.33 };


    int *invalid  = new int[2] { 2, 5 };
    int   *valid  = nullptr;
    float *valid2 = nullptr;

    auto is_valid_element = [=]( int x ) { return x != invalid[0] && x != invalid[1]; };

    auto n = std::count_if( val, val + N, is_valid_element );

    if ( n )
    {
        valid  = new int[n];
        valid2 = new float[n];

        for ( size_t i = 0, j = 0; i < N; i++ )
        {
            if ( is_valid_element( val[i] ) )
            {
                valid[j]  = val[i];
                valid2[j] = val2[i];
                j++;
            }
        }
    }

    if ( n ) 
    {
        std::copy( valid, valid + n, std::ostream_iterator<int>( std::cout, " " ) );
        std::cout << std::endl;
        std::copy( valid2, valid2 + n, std::ostream_iterator<float>( std::cout, " " ) );
        std::cout << std::endl;
    }       

    delete [] val;
    delete [] val2;
    delete [] invalid;
    delete [] valid;
    delete [] valid2;

    return 0;
}

The program output is

1 1 3 4 
0.5 0.5 1 1 

If the array invalid or array val is large then you can at first find the lower bound of the first element of the array invalid in the array val and start with the index of the lower bound element. The same is valid for upper bound.

So before the loop you should use standard algorithms std::lower_bound and std::upper_bound to find the first and the last actual indices in the array val for the loop. To determine whether an element is present in the array invalid you can use standard algorithm std::binary_search.

Here is a demonstrative program

#include <iostream>
#include <algorithm>
#include <iterator>

int main() 
{
    const size_t N = 11;
    const size_t M = 2;

    int   *val      = new int[N] { 1, 1, 2, 2, 2, 2, 3, 4, 5, 5, 5 };
    float *val2     = new float[N] { 0.5, 0.5, 0.25, 0.25, 0.25, 0.25, 1, 1, 0.33, 0.33, 0.33 };
    int   *invalid  = new int[M] { 2, 5 };

    int   *valid  = nullptr;
    float *valid2 = nullptr;

    auto it = std::lower_bound( val, val + N, invalid[0] );
    size_t lower = std::distance( val, it );

    it = std::upper_bound( it, val + N, invalid[M-1] );
    size_t upper = std::distance( val, it );

    auto invalid_element = [=]( int x ) { return std::binary_search( invalid, invalid + M, x ); };

    size_t n = N - std::count_if( val + lower, val + upper, invalid_element );

    if ( n )
    {
        valid  = new int[n];
        valid2 = new float[n];

        size_t i = 0;
        for ( size_t j = 0; j < lower; i++, j++ )
        {
            valid[i]  = val[j];
            valid2[i] = val2[j];
        }

        for ( size_t j = lower; j < upper; j++ )
        {
            if ( !invalid_element( val[j] ) )
            {
                valid[i]  = val[j];
                valid2[i] = val2[j];
                i++;
            }
        }

        for ( size_t j = upper; j < N; i++, j++ )
        {
            valid[i]  = val[j];
            valid2[i] = val2[j];
        }
    }

    if ( n ) 
    {
        std::copy( valid, valid + n, std::ostream_iterator<int>( std::cout, " " ) );
        std::cout << std::endl;
        std::copy( valid2, valid2 + n, std::ostream_iterator<float>( std::cout, " " ) );
        std::cout << std::endl;
    }       

    delete [] val;
    delete [] val2;
    delete [] invalid;
    delete [] valid;
    delete [] valid2;


    return 0;
}

Its output is

1 1 3 4 
0.5 0.5 1 1 

This program is more large than the first one but at the same time it is more efficient.:)

You can do the program more professionally looked. For example you can substitute statement

size_t n = N - std::count_if( val + lower, val + upper, invalid_element );

for

size_t n = N - std::count_if( std::next( val, lower ), std::next( val, upper ), invalid_element );

Or instead of using loops with indices you could use loops with iterators.

However the most efficient approach is to write an algorithm similar to the standard algorithm std::set_difference.

Here is a demonstrative program

#include <iostream>
#include <algorithm>
#include <iterator>

int main() 
{
    const size_t N = 11;
    const size_t M = 2;

    int   *val      = new int[N] { 1, 1, 2, 2, 2, 2, 3, 4, 5, 5, 5 };
    float *val2     = new float[N] { 0.5, 0.5, 0.25, 0.25, 0.25, 0.25, 1, 1, 0.33, 0.33, 0.33 };
    int   *invalid  = new int[M] { 2, 5 };

    int   *valid  = nullptr;
    float *valid2 = nullptr;

    auto it = std::lower_bound( val, val + N, invalid[0] );
    size_t lower = std::distance( val, it );

    it = std::upper_bound( it, val + N, invalid[M-1] );
    size_t upper = std::distance( val, it );

    size_t i;   //  index in val;
    size_t j;   //  index in invalid;
    size_t n;   //  total number of valid elements in val

    i = lower;
    j = 0;
    n = 0;

    //  counting invalid elements
    while ( i != upper )
    {
        if ( val[i] < invalid[j] )
        {
            ++i;
        }
        else if ( invalid[j] < val[i] )
        {
            ++j;
        }
        else
        {
            ++i;
            ++n;
        }
    }

    n = N - n;

    if ( n )
    {
        valid  = new int[n];
        valid2 = new float[n];

        size_t k;   //  index in valid and valid2

        i = j = k = 0;

        while ( i != N && j != M )
        {
            if ( val[i] < invalid[j] )
            {
                valid[k]  = val[i];
                valid2[k] = val2[i];
                ++k;
                ++i;
            }
            else if ( invalid[j] < val[i] )
            {
                ++j;
            }
            else
            {
                ++i;
            }
        }

        for ( ; i != N; k++, i++ )
        {
            valid[k] = val[i];
            valid2[k] = val2[i];
        }
    }

    if ( n ) 
    {
        std::copy( valid, valid + n, std::ostream_iterator<int>( std::cout, " " ) );
        std::cout << std::endl;
        std::copy( valid2, valid2 + n, std::ostream_iterator<float>( std::cout, " " ) );
        std::cout << std::endl;
    }       

    delete [] val;
    delete [] val2;
    delete [] invalid;
    delete [] valid;
    delete [] valid2;

    return 0;
}

Its output is the same as shown above

1 1 3 4 
0.5 0.5 1 1

这篇关于c ++取消数组元素,并相应地取消第二个数组中的元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆