You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 18:40:56