如何在std::map中查找键并反向迭代至首个元素?
问题描述
我有一个存储类指针的std::map,需要查找某个键后反向迭代至首个元素。由于std::map::reverse_iterator不支持std::map::find()方法,我目前采用的临时方案是:递减普通iterator至begin()之前的位置,再在循环外单独处理首个元素。想问有没有其他实现方法?std::map是否存在rfind()方法?
当前使用的代码
if( MnbObj->ParNoMapa.IsEmpty() && MnbObj->TipoMan == "D" ) // Desligou, procurar à frente { // Trocar por iterator itFind = MapFind.find( itManobra->first ); if( itFind != MapFind.end() ) { ++itFind; while( itFind != MapFind.end() ) { MnbFind = itFind->second; if( MnbFind->EqpId->UndSig == Unidade && MnbFind->EqpId->CodOper == Equipamento ) { if( MnbFind->TipoMan == "D" ) { Logger->AddLogEntry("Manobra "+itManobra->first+ " faltou religamento antes de "+ MnbFind->DtHoraMan.FormatString("dd/mm/yyyy hh:nn:ss"), evsDontCare); break; } else { if( !MnbFind->Reconhece.IsEmpty() ) MnbObj->ParNoMapa = itFind->first; break; } } ++itFind; } } } else if( MnbObj->ParNoMapa.IsEmpty() && MnbObj->TipoMan == "L" ) // Ligou, procurar para trás { itFind = MapFind.find( itManobra->first ); if( itFind != MapFind.begin() ) { --itFind; while( itFind != MapFind.begin() ) { MnbFind = itFind->second; if( MnbFind->EqpId->UndSig == Unidade && MnbFind->EqpId->CodOper == Equipamento ) { if( MnbFind->TipoMan == "L" ) { Logger->AddLogEntry("Manobra "+itManobra->first+ " faltou desligamento após "+ MnbFind->DtHoraMan.FormatString("dd/mm/yyyy hh:nn:ss"), evsDontCare); break; } else { if( !MnbFind->Reconhece.IsEmpty() ) MnbObj->ParNoMapa = itFind->first; break; } } --itFind; } // resolver o primeiro itFind = MapFind.begin(); MnbFind = itFind->second; if( MnbFind->EqpId->UndSig == Unidade && MnbFind->EqpId->CodOper == Equipamento ) { if( MnbFind->TipoMan == "L" ) { Logger->AddLogEntry("Manobra "+itManobra->first+ " faltou desligamento após "+ MnbFind->DtHoraMan.FormatString("dd/mm/yyyy hh:nn:ss"), evsDontCare); } else { itManobra->second->ParNoMapa = itFind->first; } } } }
解决方案
首先明确:std::map没有原生的rfind()方法,但有两种更优雅的方式实现需求:
方法1:将普通iterator转换为reverse_iterator
std::reverse_iterator可通过普通iterator直接构造,找到目标位置的iterator后,用它初始化反向迭代器,就能直接从目标位置的前一个元素开始,遍历到原map的首个元素(对应反向迭代器的rend()),无需单独处理边界元素。
示例代码:
// 先找到目标迭代器 auto itFind = MapFind.find(itManobra->first); if (itFind != MapFind.end()) { // 构造反向迭代器,指向itFind的前一个元素 std::reverse_iterator<decltype(itFind)> r_it(itFind); // 遍历从目标位置前一个到首个元素的所有内容 for (; r_it != MapFind.rend(); ++r_it) { MnbFind = r_it->second; // 直接复用你的判断逻辑 if (MnbFind->EqpId->UndSig == Unidade && MnbFind->EqpId->CodOper == Equipamento) { if (MnbFind->TipoMan == "L") { Logger->AddLogEntry("Manobra "+itManobra->first+ " faltou desligamento após "+ MnbFind->DtHoraMan.FormatString("dd/mm/yyyy hh:nn:ss"), evsDontCare); break; } else { if (!MnbFind->Reconhece.IsEmpty()) MnbObj->ParNoMapa = r_it->first; break; } } } }
方法2:用do-while循环合并边界处理
如果不想用反向迭代器,可以优化现有逻辑,用do-while循环一次性覆盖包括begin()在内的所有元素,避免循环外的冗余代码:
auto itFind = MapFind.find(itManobra->first); if (itFind != MapFind.begin()) { auto current = std::prev(itFind); do { MnbFind = current->second; // 复用你的判断逻辑 if (MnbFind->EqpId->UndSig == Unidade && MnbFind->EqpId->CodOper == Equipamento) { if (MnbFind->TipoMan == "L") { Logger->AddLogEntry("Manobra "+itManobra->first+ " faltou desligamento após "+ MnbFind->DtHoraMan.FormatString("dd/mm/yyyy hh:nn:ss"), evsDontCare); break; } else { if (!MnbFind->Reconhece.IsEmpty()) MnbObj->ParNoMapa = current->first; break; } } // 到达首元素时终止循环 if (current == MapFind.begin()) break; --current; } while (true); }
为什么std::map没有rfind()?
std::map是有序容器,键唯一且按固定顺序排列,find()已经能以O(log n)的效率定位到唯一键,反向查找没有额外效率优势——你需要的“反向迭代”本质是找到键后向前遍历,而非从容器末尾反向查找键,因此标准库未提供rfind()方法。
内容的提问来源于stack exchange,提问作者Jayme Jeffman
相关产品推荐
相关产品推荐

