100分求STL解决办法~~

JeffHe 2006-03-24 05:37:43
偶使用的是VC6.0,使用STL时,碰到如下问题了:
已知一个vector和需要删除元素的下标位置,如何
用erase(remove_if(...))方式来完成该操作?

如:
vector<int> dd;//=[11 12 13 14 15 16 17 18 19]
现在要将dd下标为0,2,4的元素(即11,13,15)删除,
erase(remove_if(...))方式如何解决?是否需要使用
bind2nd()呢?
...全文
276 19 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
睡在床板下_ 2006-03-25
  • 打赏
  • 举报
回复
ugg(逸学堂(exuetang.net)) ( ) 信誉:100 2006-03-24 19:58:00 得分: 0


for(vector<int>::iterator it = dd.begin(); it != dd.end(); ++it)
{
it = erase(it);
}
----------------------------------
差不多了~~
xlsue 2006-03-25
  • 打赏
  • 举报
回复
我好像没发现有这个函数哦!
我认为可以这样:vector的iterator是随机的,可以使用iterator+下标,从vector的后面往前面移除下标为4,2,0的元素。
我也想看到更好的办法,期待中。。。
JeffHe 2006-03-25
  • 打赏
  • 举报
回复
xlsue(小林):是以下标进行删除~~ 而不是以值进行删除,
不知道如何在remove_if()中访问到vector[]的下标呢?
xlsue 2006-03-25
  • 打赏
  • 举报
回复
我觉得计数器和下标都差不多是同个意思,没有必要砖牛角尖吧?能达到程序意图的可以了
xlsue 2006-03-25
  • 打赏
  • 举报
回复
to 回复人:ricky460(阿酷):
你的程序符合楼主的,学习。
template <typename T>
void PRINT(const T& t)
{
for(typename T::const_iterator iter = t.begin() ; iter != t.end() ; ++ iter)
//这里前面要加typename
{
cout << *iter << " " ;
}
}
ricky460 2006-03-25
  • 打赏
  • 举报
回复
------------------------------------------------------------------------
JeffHe(雅永紫) ( ) 信誉:99 2006-03-25 08:56:00 得分: 0

xlsue(小林):是以下标进行删除~~ 而不是以值进行删除,
不知道如何在remove_if()中访问到vector[]的下标呢?
---------------------------------------------------------------------------

利用distance函数可以通过iterator得到下标 .

vector<int>::iterator iter ;
...........
int iIndex = distance(vInt.begin() , iter); //根据iterator得到索引 . . .



示例代码 :( 利用distance来删除制定下标元素)

int iOffset = 0 ;
for(vector<int>::iterator iter = vInt.begin() ; iter != vInt.end() ; ++ iter)
{
int iIndex = distance(vInt.begin() , iter) + iOffset;
if(iIndex == 0 || iIndex == 2 || iIndex == 4)
{
vInt.erase(iter , iter + 1);
iOffset += 1 ;
}
}

注解: 1: 这里加了一个变量iOffset , 这是因为 , 你在数组里删除一个元素 , 那么删除前下标2的元素 就对应于 删除后 下标1 的元素 . . . 每删除一个 ,就要累加一次 . .
2: 这段代码是有漏洞的 , 但是为了让楼主看得清晰明白 , 我没有加入纠错的代码.这里
需要加入判断是否是删除最后一个元素的代码 , 删除最后一个元素时 ,需要用另外的代码 . 代码很简单 ,就当是功课 , 让楼主自己写吧 . . .
3: 替代方法 :
int iIndex = 0 ;
for(.................)
{
if(iIndex == 0 || iIndex == 2 || iIndex == 4) DoSomething();
iIndex ++ ;
}
这种方法是最简单的 ,但我想 , 这并非是楼主所想要的 . . .


ricky460 2006-03-25
  • 打赏
  • 举报
回复
问题: 已知 vector , 和下标 , 利用erase , remove_if 删除元素 .
解决代码:
--------------------------------------------
#include "stdafx.h"
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std ;

//打印函数
template <typename T>
void PRINT(const T& t)
{
for(T::const_iterator iter = t.begin() ; iter != t.end() ; ++ iter)
{
cout << *iter << " " ;
}
}

//设置删除条件的仿函数
class DEL
{
int iIndex ; //定义一个iIndex来模拟vector的索引.
public:
DEL(){ iIndex = 0 ; }
bool operator()(int )
{
bool bReturn = (iIndex == 0 || iIndex == 2 || iIndex == 4) ;
iIndex ++ ;
return bReturn ;
}
};

int main(int argc, char* argv[])
{
vector <int> vInt ;

for(int i = 11 ; i <= 19 ; i ++) vInt.push_back(i);

PRINT(vInt);

cout << endl << endl;

vInt.erase(remove_copy_if(vInt.begin() , vInt.end() , vInt.begin(), DEL()), vInt.end());

PRINT(vInt);

return 0;
}

----------------------------------------------
{ 如上代码在 VC6 ,WindowXP 下测试成功 }

注解:

1: 用了一个条件判断仿函数DEL , 在DEL中定义了一个iIndex来模拟vector的索引 , 在
vInt.erase中 , vInt每向后移动一个元素 , 就会调用一次 DEL.operator()(int );
DEL.iIndex就会递增一次 , 即 , iIndex是跟实际vector的索引是相符的 . . . . .
2: 这里用remove_copy_if来代替remove_if ,是因为,STL中 , remove_if 是一个比较特殊的
函数 , 它会在内部调用两次传进去的比较函数 . 即内部类似于:
remove_if(....)
{
find_if(.... , DEL)
.......
return remove_copy_if(.... , DEL) ;
}
由于DEL是传递值而非传地址 ,所以这里在计算iIndex会出现问题 . 所以 , 在这里我用
remove_copy_if来代替了remove_if . 楼主可以不用考虑这些具体细节 . . .


以上代码可以实现楼主的需求. 楼主可以修改一下,以满足动态传入删除元素的下标的需求 .
howyougen 2006-03-24
  • 打赏
  • 举报
回复
guangmingshizhe(流云飞翼) ( ) 说的对
删除一个元素后,元素的下标已经发生改变了,这是问题所在吧


using namespace std;

struct mycond
{
mutable int i;
mycond(){i=-1;}
bool operator()(int) const
{
i++;
return (i%2 == 0) && (i<5) ;
}
};

int main()
{
//0,2,4的元素(即11,13,15)删除
int a[] = {11, 12, 13, 14, 15, 16, 17, 18, 19};
vector<int> dd(a, a + sizeof(a)/sizeof(a[0]) );//=[11 12 13 14 15 16 17 18 19]
for(vector<int>::iterator it = dd.begin(); it != dd.end(); ++it)
{
cout<< *it<< " ";
}
cout<< endl;

replace_if(dd.begin(), dd.end(), mycond(),-1234567); //先替换成-1234567
dd.erase(remove(dd.begin(),dd.end(),-1234567),dd.end()); //再删除

for(vector<int>::iterator it = dd.begin(); it != dd.end(); ++it)
{
cout<< *it<< " ";
}
cout<< endl;
system("pause");
}
guyanhun 2006-03-24
  • 打赏
  • 举报
回复
dd.erase(remove_if(dd.begin(), dd.end(),compose2( std::logical_and<bool>(),std::bind2nd(std::modulus<int>() ,2),std::bind2nd(std::less<int>(),16) ) ), dd.end());

guyanhun 2006-03-24
  • 打赏
  • 举报
回复
dd.erase(remove_if(dd.begin(), dd.end(),compose2( logical_and<bool>(),bind2nd(modulus<int>() ,2),bind2nd(less<int>(),16) ), dd.end());
xlsue 2006-03-24
  • 打赏
  • 举报
回复
ugg(逸学堂(exuetang.net)) ( ) 信誉:100 2006-03-24 19:58:00 得分: 0


for(vector<int>::iterator it = dd.begin(); it != dd.end(); ++it)
{
it = erase(it);
}
------------------------------------------
打断一下,上面的代码是啥意思? 有erase(Iterator)这个函数?上面的代码好像有bug哦?


xlsue 2006-03-24
  • 打赏
  • 举报
回复
不明白楼主是想以下标0,2,4删除还是以值删除?
逸学堂 2006-03-24
  • 打赏
  • 举报
回复
for(vector<int>::iterator it = dd.begin(); it != dd.end(); ++it)
{
it = erase(it);
}
xiaocai0001 2006-03-24
  • 打赏
  • 举报
回复
MSDN上的一个例子:
......
Numbers[0] = 10 ;
Numbers[1] = 20 ;
Numbers[2] = 10 ;
Numbers[3] = 15 ;
Numbers[4] = 12 ;
Numbers[5] = 7 ;
Numbers[6] = 9 ;
Numbers[7] = 10 ;


cout << "Before calling remove_if" << endl ;

// print content of Numbers
cout << "Numbers { " ;
for(it = start; it != end; it++)
cout << *it << " " ;
cout << " }\n" << endl ;

// remove all elements from Numbers that <= 10
last = remove_if(start, end, bind2nd(less_equal<int>(), 10) ) ;
......

一般用remove_if操作时, 对容器内元素的值有条件判定的, 像你这样的只是对容器的下标操作时, 可以直接用迭代器找到对应的下标, 然后erase()就可以了
妍妍 2006-03-24
  • 打赏
  • 举报
回复
删除一个元素后,元素的下标已经发生改变了,这是问题所在吧
citywanderer2005 2006-03-24
  • 打赏
  • 举报
回复
remove_if(dd.begin(), dd.end(), greater)
表示删除整个vector中满足条件(即使greater函数为真)的元素,它的返回值是被删除元素后的第二个元素的iterator。因为remove不会改变vector的size,所以最后空留的空间由原vector中的最后几个元素填充,这里就要用erase删除后面的重复的元素。
citywanderer2005 2006-03-24
  • 打赏
  • 举报
回复
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool greater( int value )
{
return (value == 11 || value == 13 || value == 15);
}

int main()
{
//0,2,4的元素(即11,13,15)删除
int a[] = {11, 12, 13, 14, 15, 16, 17, 18, 19};
vector<int> dd(a, a + sizeof(a)/sizeof(a[0]) -1);//=[11 12 13 14 15 16 17 18 19]
for(vector<int>::iterator it = dd.begin(); it != dd.end(); ++it)
{
cout<< *it<< " ";
}
cout<< endl;

dd.erase(remove_if(dd.begin(), dd.end(), greater), dd.end());

for(vector<int>::iterator it = dd.begin(); it != dd.end(); ++it)
{
cout<< *it<< " ";
}
cout<< endl;
}
jiezhi 2006-03-24
  • 打赏
  • 举报
回复
这样的问题还是看看STL Ref吧
expert2000 2006-03-24
  • 打赏
  • 举报
回复
好贴。我也不懂。正好学习学习
STL和标准 我经常提及C++标准,因为《Effective STL》专注于可移植的,与标准一致的C++。理论上,我在这本书里演示的一切都可以用于每个C++实现。实际上,那不是真的。编译器的缺陷和STL实现凑合成防止一些有效的代码编译或表现出它们应该有的行为。那是很常见的情况,我描述了这些问题,而且解释了你应该怎么变通地解决他们。 有时候,最容易的变通办法是使用另一个STL实现。附录B给一个这种情况的例子。实际上,STL用得越多,编译器和库实现的区别就越重要。程序员在设法让合法的代码编译时遇到困难,他们通常责备他们的编译器,但对于STL,编译器可能是好的,而STL实现是不良的。为了强调你得依赖编译器和库实现的事实,我使用你的STL平台。一个STL平台是一个特定编译器和一个标准模板库特定实现的组合。在本书里,如果我提及一个编译器问题,你能确信我意思是编译器有问题。但是,如果我说你的STL平台有问题,你应该理解为“可能是编译器缺陷,可能是库缺陷,或许都有”。 我一般提及你的“编译器们”——复数。那是我长期相信你通过确保代码可以在多于一个的编译器上工作的方法来改进你的代码质量(特别是移植性)的产物。此外,使用多个编译器一般可以简化拆解由STL的使用不当造成的错误信息难题。(条款49致力于解码此类消息的方法。) 关于与标准一致的代码,我强调的另一个方面是你应该避免构造未定义行为。这样的构造可能在运行期做任何事情。不幸的是,这意味着它们可能正好做了你想要的,而那会导致一种错误的安全感。太多程序员以为未定义行为总会导致一个明显的问题,例如,一个分段错误或其他灾难性的错误。未定义行为的结果实际上更为狡猾,例如,破坏极少引用的数据。它们也可以通过程序运行。我发现一个未定义行为的好定义是“为我工作,为你工作,在开发和QA期间工作,但在你最重要的用户面前爆炸了”。避免未定义行为很重要,所以我指出了它会出现的通常情况。你应该训练你自己警惕这样的情况。

65,186

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧