我有两个数组,两个都已排序。一个数组填充重复值,另一个数组填充应在第一个数组中取消的值。例如:
int * val = new int[11];
val[0] = 1; val[1] = 1;
val[2] = 2; val[3] = 2; val[4] = 2; val[5] = 2;
val[6] = 3;
val[7] = 4;
val[8] = 5; val[9] = 5; val[10] = 5;
int * invalid = new int[2]; invalid[0] = 2; invalid[1] = 5;
然后输出应该是这样的
int * valid = new int[4];
valid[0] = 1; valid[1] = 1;
valid[2] = 3;
valid[3] = 4;
如何使用for
循环有效地实现此目的?我想指出,我不想切换到vector
或list
这样的容器,因为我知道会有朝这个方向发表评论。我明确地希望使用数组。
答案 0 :(得分:3)
如果两者都被排序,这只是一个简单的O(N + M)算法:从零索引处的两个数组开始,并递增指向较小值的数组。如果增加目标数组,则复制,除非它等于无效数组。
此外,由于您只是删除项目,因此如果您不必保留原始数据,则可以避免使用某些副本:您可以保留计数器丢弃的项目数,并将相同的数组复制到{ {1}}如果currentIdx-discardedCount
大于零。
答案 1 :(得分:1)
首先,您应该计算源数组中满足条件的元素数量,然后为元素分配足够的内存。
这是一个示范程序
#include <iostream>
#include <algorithm>
#include <iterator>
int main()
{
const size_t N1 = 11;
const size_t N2 = 2;
int * val = new int[N1] { 1, 1, 2, 2, 2, 2, 3, 4, 5, 5, 5 };
int * invalid = new int[N2] { 2, 5 };
int *valid = nullptr;
auto n = std::count_if( val, val + N1,
[=]( int x ) { return !std::binary_search( invalid, invalid + N2, x ); } );
if ( n )
{
valid = new int[n];
std::copy_if( val, val + N1, valid,
[=]( int x ) { return !std::binary_search( invalid, invalid + N2, x ); } );
}
if ( valid ) std::copy( valid, valid + n, std::ostream_iterator<int>( std::cout, " " ) );
std::cout << std::endl;
return 0;
}
它的输出是
1 1 3 4
如果无效数组包含许多元素,您可以使用标准算法std::binary search
,或者只需编写lambda表达式,如
[=]( int x ) { return x != invalid[0] && x != invalid[1]; }
例如
#include <iostream>
#include <algorithm>
#include <iterator>
int main()
{
const size_t N1 = 11;
const size_t N2 = 2;
int * val = new int[N1] { 1, 1, 2, 2, 2, 2, 3, 4, 5, 5, 5 };
int * invalid = new int[N2] { 2, 5 };
int *valid = nullptr;
auto is_valid_element = [=]( int x ) { return x != invalid[0] && x != invalid[1]; };
auto n = std::count_if( val, val + N1, is_valid_element );
if ( n )
{
valid = new int[n];
std::copy_if( val, val + N1, valid, is_valid_element );
}
if ( valid ) std::copy( valid, valid + n, std::ostream_iterator<int>( std::cout, " " ) );
std::cout << std::endl;
return 0;
}
编译器应支持C ++ 2011。
答案 2 :(得分:0)
#include <iostream>
const int SIZE_1 = 11;
const int SIZE_2 = 2;
/*find out if item should be exclude from result array; this take linear time over the size of the invalids array*/
bool doNotInclude(int item, int invalids[], int size)
{
bool remove = false;
for(int i = 0; i < size; i++)
{
if(invalids[i] == item)
{
remove = true;
}
}
return remove;
}
int main() {
//array of values
int * val = new int[SIZE_1] { 1, 5, 2, 2, 2, 2, 3, 4, 1, 5, 5 };
//values to ignore
int * invalid = new int[SIZE_2] { 2, 5 };
//result array
int *valid = new int[SIZE_1];
//keep track of result array current index/ size
int currentIndex = 0;
/*check if elements of input array are in invalids, if not put them in the result array*/
for(int i = 0; i < SIZE_1; i++)
{
if(!doNotInclude(val[i], invalid, SIZE_2))
{
valid[currentIndex] = val[i];
currentIndex++;
}
}
//print result
//currentIndex is now the size of the valid array
for(int n = 0; n < currentIndex; n++)
{
std::cout << valid[n] << ' ';
}
}
这种方法是O(N * M)数组是否排序。
答案 3 :(得分:-3)
从概念上讲,算法就像这个伪代码:
int i, j;
j = 0;
for (i=0; i < length(val); i++) {
if (val[i] != VALUE_TO_DELETE) {
val[j++] = val[i];
}
}
... now discard, or ignore, anything in "val" beyond element #j.
我们只是遍历数组,复制任何不我们想要摆脱的值。 i
是用于查找值的光标,j
表示放置它们的位置。
元素#j
之外的值仍然存在,在物理上,但你忽略它们。
为了完整起见,如果我们正在寻找invalid
个数字:
int i, j, k;
boolean delete_me;
j = 0;
for (i=0; i < length(val); i++) {
// search the "invalid" list to see if the number is in it
delete_me = false;
for (k = 0; k < length(invalid); k++) {
if (val[i] == invalid[k]) {
delete_me = true;
break; // quit the loop as soon as we know ...
}
}
// copy what is NOT in it
if (!delete_me) { // notice: "if NOT" ...
val[j++] = val[i];
}
}