A ordem de iteração através do std :: map é conhecida (e garantida pelo padrão)?

158

O que quero dizer é - sabemos que os std::mapelementos do são classificados de acordo com as chaves. Então, digamos que as chaves sejam números inteiros. Se eu iterar de std::map::begin()para std::map::end()usar a for, o padrão garante que eu iterarei consequentemente através dos elementos com chaves, classificados em ordem crescente?


Exemplo:

std::map<int, int> map_;
map_[1] = 2;
map_[2] = 3;
map_[3] = 4;
for( std::map<int, int>::iterator iter = map_.begin();
     iter != map_.end();
     ++iter )
{
    std::cout << iter->second;
}

Isso é garantido para impressão 234ou sua implementação está definida?


Razão da vida real: eu tenho um std::mapcom intchaves. Em situações muito raras, eu gostaria de percorrer todos os elementos, com chave, maior que um intvalor concreto . Sim, parece que std::vectorseria a melhor escolha, mas observe minhas "situações muito raras".


EDIT : Eu sei, que os elementos de std::mapsão classificados .. não há necessidade de apontar (para a maioria das respostas aqui). Eu até escrevi na minha pergunta.
Eu estava perguntando sobre os iteradores e o pedido quando estou iterando através de um contêiner. Obrigado @Kerrek SB pela resposta.

Kiril Kirov
fonte
6
Caso você não saiba: na vida real, use-o map::upper_boundpara encontrar o ponto para começar a iterar.
Steve Jessop
Eu sei disso e sei o lugar exato em que começaria a iterar. Eu apenas vaguei se a ordem é garantida.
22411 Kiril Kirov
Um vetor esparso não seria sensato se suas teclas (índices numéricos) variarem tremendamente em todo o quadro. Estou usando uma solução semelhante para a qual o índice numérico representa uma coordenada y cartesiana no espaço tridimensional. Usar um vetor nesse cenário aumentaria minha pegada de memória em gigabytes. Portanto, não acho que o vetor seja uma panacéia aqui, longe disso.
Jonathan Neufeld 04/10
Não entendi a pergunta e explicarei o motivo por meio de um experimento mental. Se você já sabe que os elementos estão ordenados, como a iteração pode não ser? O que significa ordenar, se não se aplica à iteração? Que outros casos existem onde a ordem importa, é detectável etc.? (A resposta foi dada por Konstantin .)
underscore_d

Respostas:

176

Sim, isso é garantido. Além disso, *begin()fornece o menor e *rbegin()o maior elemento, conforme determinado pelo operador de comparação, e dois valores principais ae bpara os quais a expressão !compare(a,b) && !compare(b,a)é verdadeira são considerados iguais. A função de comparação padrão é std::less<K>.

A ordenação não é um recurso de bônus da sorte, mas sim, é um aspecto fundamental da estrutura de dados, pois a ordenação é usada para determinar quando duas chaves são iguais (pela regra acima) e para executar uma pesquisa eficiente (essencialmente uma variável binária). pesquisa, que possui complexidade logarítmica no número de elementos).

Kerrek SB
fonte
std :: map é implementado usando árvores binárias, portanto tecnicamente nenhuma pesquisa binária é realizada.
Jupp0r
11
@ jupp0r: Estruturar um intervalo como uma árvore de pesquisa binária é um método específico para implementar a pesquisa binária no intervalo. "Pesquisa binária" é um conceito abstrato e não uma implementação específica. Não importa se você passa por desvios para uma matriz ou segue os nós do link; essas são apenas formas específicas de "dividir o intervalo".
Kerrek SB
1
Eu sei que este é um post antigo, mas para deixar claro, a "pesquisa eficiente" é relativa. Tecnicamente, ele std::unordered_maptem um tempo de pesquisa mais eficiente de O (1). A vantagem de std::mapestá na ordenação de chaves, mas não na pesquisa.
Adam Johnston
42

Isso é garantido pelos requisitos de contêiner associativo no padrão C ++. Por exemplo, veja 23.2.4 / 10 em C ++ 11:

A propriedade fundamental dos iteradores de contêineres associativos é que eles
percorrer os contêineres na ordem não descendente de chaves em que
não descendente é definido pela comparação usada para construí-los.
Para quaisquer dois iteradores dereferenciáveis ​​iej, de modo que a distância de iej seja
positivo,
  valor_comp (* j, * i) == falso

e 23.2.4 / 11

Para contêineres associativos com chaves exclusivas, a condição mais forte é válida,
  value_comp (* i, * j)! = false.
Konstantin Oznobihin
fonte
32

Eu acho que há uma confusão nas estruturas de dados.

Na maioria dos idiomas, a mapé simplesmente um AssociativeContainer: ele mapeia uma chave para um valor. Nos idiomas "mais recentes", isso geralmente é alcançado usando um mapa de hash, portanto, nenhuma ordem é garantida.

Em C ++, no entanto, isso não é assim:

  • std::mapé um contêiner associativo classificado
  • std::unordered_map é um contêiner associativo baseado em tabela de hash introduzido no C ++ 11

Portanto, para esclarecer as garantias sobre o pedido.

No C ++ 03:

  • std::set, std::multiset, std::mapE std::multimapsão garantidos para ser ordenados de acordo com as teclas (e o critério fornecido)
  • in std::multisete std::multimap, a norma não impõe nenhuma garantia de ordem a elementos equivalentes (ou seja, aqueles que se comparam da mesma forma)

No C ++ 11:

  • std::set, std::multiset, std::mapE std::multimapsão garantidos para ser ordenados de acordo com as teclas (e o critério fornecido)
  • em std::multisete std::multimap, a Norma impõe que elementos equivalentes (aqueles que se comparam iguais) sejam ordenados de acordo com sua ordem de inserção (primeiro inseridos primeiro)
  • std::unordered_*recipientes não são, como o nome indica, ordenado. Mais notavelmente, a ordem dos elementos pode mudar quando o contêiner é modificado (mediante inserção / exclusão).

Quando a Norma diz que os elementos são ordenados de certa forma, significa que:

  • ao iterar, você vê os elementos na ordem definida
  • ao iterar ao contrário, você vê os elementos na ordem oposta

Espero que isso esclareça qualquer confusão.

Matthieu M.
fonte
Isso não tem nada a ver com a minha pergunta, desculpe :) Eu sei qual é o pedido e quais - não. E eu estou pedindo o pedido quando estou iterando pelos elementos.
21411 Kiril Kirov
10
@KirilKirov: bem, a definição de um contêiner associativo ordenado é que, ao iterá-lo, os elementos são ordenados.
Matthieu M.
Bem, eu acho que você está certo, mas eu não sabia o que e isso é exatamente o que eu estava pedindo :)
Kiril Kirov
4

Isso é garantido para imprimir 234 ou sua implementação está definida?

Sim, std::mapé um contêiner classificado, encomendado pelo Keycom o fornecido Comparator. Portanto, é garantido.

Eu gostaria de percorrer todos os elementos, com chave, maiores que um valor int concreto.

Isso é certamente possível.

jpalecek
fonte
3

Sim ... os elementos em um std::maptêm uma ordem estrita estrita, o que significa que os elementos serão compostos por um conjunto (ou seja, não haverá repetições de chaves "iguais"), e a igualdade é determinada pelo teste em qualquer duas chaves A e B, que se a chave A não for menor que a chave B e B não for menor que A, a chave A será igual à chave B.

Dito isto, você não pode classificar adequadamente os elementos de a std::mapse a ordem fraca desse tipo for ambígua (no seu caso, onde você está usando números inteiros como o tipo de chave, isso não é um problema). Você deve ser capaz de definir uma operação que defina uma ordem total do tipo que você está usando para as chaves no seu std::map, caso contrário, você terá apenas um pedido parcial para seus elementos, ou poset, que possui propriedade onde A pode não ser comparável a B. O que normalmente acontecerá nesse cenário é que você poderá inserir os pares de chave / valor, mas poderá acabar com pares de chave / valor duplicados se percorrer o mapa inteiro e / ou detectar "falta" pares de chave / valor quando você tenta executar um std::map::find()par específico de chave / valor no mapa.

Jason
fonte
Como as outras respostas, isso realmente não responde à minha pergunta, obrigado de qualquer maneira.
Kiril Kirov
-3

begin () pode fornecer o menor elemento. Mas isso depende da implementação. É especificado no padrão C ++? Caso contrário, é perigoso fazer essa suposição.

pyang
fonte