反向迭代器的删除

本文探讨了在C++中使用反向迭代器进行元素删除的两种方法:一是通过转换为正向迭代器使用erase,二是保存键值再重新插入。提供了具体的代码示例和解释。

正向迭代器可以正常使用erase操作,进行删除操作。但是反向迭代器如果直接使用erase传递一个反向迭代器的参数会报错,但是他们是继承的关系,所以可以使用base()进行转换已达到删除的目的。 即使用 (++it).base()作为erase的参数。

	multimap<int, int> mm;
	mm.insert(make_pair(3, 2));
	mm.insert(make_pair(3, 1));
	mm.insert(make_pair(1, 4));
	mm.insert(make_pair(2, 3));
	for (auto it : mm)
	{
		cout << it.first << "---" << it.second << endl;
	}
	cout << "----------" << endl;
	for (auto it = mm.rbegin(); it != mm.rend(); ++it)
	{
		if (it->second == 2)
		{
			mm.erase((++it).base());
			break;
		}
	}
	for (auto it : mm)
	{
		cout << it.first << "---" << it.second << endl;
	}

这是一种很机智的方法,当然再找到这个方法之前,总不能被卡主,想想还有没有其他的方法。有的,那就是将所有的键值数据全部保存,然后删除需要删除的元素即可。例:multimap的数据 <1,2><1,3><1,4><2,3><3,4><3,3>要删除<3,4>,原本可以使用正向迭代器删除,但是如果数据量特别大,或者就必须使用反向迭代器呢?使用反向迭代器将所有键值为3的都删除,前提是将键值为3的数据保存起来,然后再将保存的数据重新写入。

	multimap<int, int> mapTmp;
	mapTmp.insert(make_pair(3, 2));
	mapTmp.insert(make_pair(3, 1));
	mapTmp.insert(make_pair(1, 4));
	mapTmp.insert(make_pair(2, 3));

	for (auto it : mapTmp)
	{
		cout << it.first << "---" << it.second << endl;
	}
	cout << "------" << endl;
	auto it = mapTmp.rbegin();
	multimap<int, int>::size_type cnt = mapTmp.count(it->first);
	int x = cnt;
	vector<int> veTmp(cnt+1);
	int ii = 0;
	for (; cnt > 0; cnt--, it++)
	{
		//veTmp.push_back(it->second);
		veTmp[ii++] = it->second;
	}
	--it;
	int tmp = it->first;
	mapTmp.erase(it->first);
	for (int i = 0; i < x - 1; ++i)
	{
		mapTmp.insert(make_pair(tmp,veTmp[i]));
	}

	for (auto it : mapTmp)
	{
		cout << it.first << "---" << it.second << endl;
	}

好蠢的办法啊。。。

关于反向迭代器删除的详细信息,可以参考这位大佬的文章,感谢大佬分享。

https://blog.youkuaiyun.com/onlysingleboy/article/details/74504266

 

<think>嗯,用户问的是反向迭代器解引用的问题。首先,我得回忆一下反向迭代器在C++中的工作原理。反向迭代器是STL中的一部分,用于逆序遍历容器,比如vector、list或者deque。它们通过rbegin()和rend()来获取,但解引用的时候需要注意它们的实际指向。 我记得反向迭代器的内部实现其实是基于正向迭代器的,当使用rbegin()时,实际上它指向的是容器最后一个元素的后一个位置(也就是end()的位置),然后通过递减操作来移动到最后一个元素。所以当解引用反向迭代器时,实际上返回的是其内部保存的正向迭代器前一个位置的元素。这可能就是用户疑惑的地方,为什么解引用反向迭代器得到的是前一个元素的值。 比如,假设有一个vector<int> v{1,2,3,4},rbegin()指向的位置是v.end(),即第四个元素之后的位置。当解引用这个反向迭代器时,内部会先递减到第四个元素的位置,然后返回那个元素的引用。所以*v.rbegin()得到的是4。这可能导致用户在使用时产生误解,特别是当迭代器处于rend()的时候,解引用可能会引发未定义行为,因为此时反向迭代器指向的是第一个元素的前一个位置,无法递减了。 另外,反向迭代器的base()方法可以返回对应的正向迭代器。但需要注意的是,rit.base()返回的是当前反向迭代器内部保存的正向迭代器,而这个正向迭代器指向的是反向迭代器下一个元素的位置。例如,当反向迭代器rit指向元素3时,rit.base()会指向元素4的位置,也就是正向迭代器的位置。所以在将反向迭代器转换为正向迭代器时,可能需要调整位置,比如使用rit.base() -1来得到正确的元素。 用户可能在实践中遇到的问题是,比如在删除元素时,如果直接使用反向迭代器的base(),可能会导致错误的位置被删除。例如,当反向查找到某个元素后,要删除它,正确的做法是将反向迭代器转换为正向迭代器时调整位置,确保指向正确的元素。 总结一下,反向迭代器解引用的行为是因为其内部实现机制,需要理解其指向和实际的元素位置之间的关系。使用时要注意解引用的结果以及如何正确转换到正向迭代器,避免越界或者错误的元素操作。</think><< 反向迭代器解引用是C++中处理容器逆序遍历时的关键操作,但需要注意其行为与普通迭代器的差异。反向迭代器的解引用操作符`*`返回的并不是它实际指向的容器位置的值,而是其前一个位置的值。以下是详细解释: ### 核心机制 1. **反向迭代器设计** 反向迭代器(如`rbegin()`和`rend()`)通过内部保存一个普通迭代器实现。当反向迭代器指向容器元素时,其内部实际存储的是对应元素的下一个位置的普通迭代器。 **示例**: ```cpp std::vector<int> vec = {10, 20, 30}; auto rit = vec.rbegin(); // 实际存储的普通迭代器指向vec.end() std::cout << *rit; // 输出30(实际访问的是--vec.end()) ``` 2. **解引用操作** 解引用反向迭代器时,会先对内部存储的普通迭代器执行`--`操作,再返回其指向的值: ```cpp // 伪代码实现 reference operator*() const { iterator tmp = current; return *--tmp; // 先回退再解引用 } ``` 3. **base()方法** 通过`base()`方法获取反向迭代器对应的普通迭代器时,返回的是未调整的原始迭代器: ```cpp auto rit = vec.rbegin(); auto it = rit.base(); // 指向vec.end() ``` ### 典型问题场景 ```cpp std::vector<int> v{1, 2, 3, 4}; auto rit = v.rbegin() + 1; // 指向3 std::cout << *rit; // 输出3(实际访问的是v[2]) // 反向迭代器转换为普通迭代器时需要调整 auto it = rit.base(); // 指向4的位置(v.begin() + 3) auto valid_it = it - 1; // 正确指向3的位置(v.begin() + 2) ``` ### 注意事项 - **rend()解引用危险** ```cpp auto bad_rit = v.rend(); // *bad_rit; // 未定义行为(试图访问v.begin() - 1) ``` - **插入/删除操作** 使用反向迭代器删除元素时需转换: ```cpp v.erase((++rit).base()); // 安全删除3(需通过++调整反向迭代器) ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值