Suponha que eu tenha um tamanho std::vector
(vamos chamá-lo myVec
) N
. Qual é a maneira mais simples de construir um novo vetor que consiste em uma cópia dos elementos X a Y, onde 0 <= X <= Y <= N-1? Por exemplo, myVec [100000]
através myVec [100999]
de um vetor de tamanho 150000
.
Se isso não puder ser feito eficientemente com um vetor, existe outro tipo de dados STL que eu deveria usar?
Respostas:
É uma operação O (N) para construir o novo vetor, mas não há realmente uma maneira melhor.
fonte
O(Y-X)
, ou diríamosO(Z) where Z=Y-X
.vector<T> newVec(myVec.begin() + 100000, myVec.begin() + 101000);
?Basta usar o construtor de vetores.
fonte
operator[]
retorna uma referência. É apenas no ponto em que você lê ou escreve a referência que se tornaria uma violação de acesso. Como não fazemos nenhum dos dois, mas obtemos o endereço, não invocamos o UB.std::vector<T>(input_iterator, input_iterator)
, no seu casofoo = std::vector<T>(myVec.begin () + 100000, myVec.begin () + 150000);
, veja por exemplo aquifonte
Hoje em dia, usamos
span
s! Então você escreveria:para obter um intervalo de 1000 elementos do mesmo tipo que
myvec
's. Ou uma forma mais concisa:(mas não gosto muito disso, pois o significado de cada argumento numérico não é totalmente claro; e fica pior se o tamanho e o start_pos forem da mesma ordem de magnitude.)
De qualquer forma, lembre-se de que não é uma cópia, é apenas uma visão dos dados no vetor, portanto, tenha cuidado. Se você quiser uma cópia real, poderá:
Notas:
gsl
significa Biblioteca de suporte a diretrizes. Para obter mais informaçõesgsl
, consulte: http://www.modernescpp.com/index.php/c-core-guideline-the-guidelines-support-library .gsl
, consulte: https://github.com/Microsoft/GSLspan
. Você usariastd::span
e#include <span>
não#include <gsl/span>
.std::vector
tem um zilhão de construtores, é super fácil cair em um que você não pretendia usar; portanto, tenha cuidado.fonte
cbegin
ecend
apenas pelo princípio;)std::cbegin
etc mesmo.Se ambos não vão ser modificadas (sem adição / exclusão de itens - modificar os já existentes é bom, desde que você preste atenção aos problemas de threading), você pode simplesmente passar em torno
data.begin() + 100000
edata.begin() + 101000
, e fingir que eles são obegin()
eend()
de um vector menor.Ou, como é garantido que o armazenamento vetorial seja contíguo, você pode simplesmente transmitir uma matriz de 1000 itens:
Ambas as técnicas levam tempo constante, mas exigem que o comprimento dos dados não aumente, desencadeando uma realocação.
fonte
Essa discussão é bastante antiga, mas a mais simples ainda não foi mencionada, com a inicialização da lista :
Requer c ++ 11 ou superior.
Exemplo de uso:
Resultado:
fonte
Você não mencionou o tipo
std::vector<...> myVec
, mas se é um tipo ou estrutura / classe simples que não inclui ponteiros e deseja a melhor eficiência, pode fazer uma cópia direta da memória (que eu acho que será mais rápida que a outras respostas fornecidas). Aqui está um exemplo geral destd::vector<type> myVec
ondetype
, neste caso, éint
:fonte
std::vector(myVec.begin () + 100000, myVec.begin () + 150000);
, a versão mais longa deste não produzirá exatamente o mesmo assembly?std::vector<>(iter, iter)
paramemmove()
, se apropriado (se o construtor for trivial, para uma definição adequada de trivial).memcpy
. Faça umstd::copy
ou um construtor que aceite um intervalo (dois iteradores), e o compilador e a biblioteca std.l conspirarão para chamarmemcpy
quando apropriado.Você poderia apenas usar
insert
fonte
Você pode usar a cópia STL com desempenho O (M) quando M é o tamanho do subvetor.
fonte
newvec.reserve(10100 - 10000);
. Definitivamente, é uma opção e tecnicamente funcionará. Mas dos dois que você vai recomendar?A única maneira de projetar uma coleção que não é tempo linear é fazê-lo preguiçosamente, onde o "vetor" resultante é na verdade um subtipo que delega à coleção original. Por exemplo, o
List#subseq
método de Scala cria uma sub-sequência em tempo constante. No entanto, isso funciona apenas se a coleção é imutável e se o idioma subjacente ostenta a coleta de lixo.fonte
Postando esta tarde apenas para outras pessoas ... aposto que o primeiro codificador já está pronto. Para tipos de dados simples, nenhuma cópia é necessária, basta reverter para bons métodos antigos de código C.
Em seguida, passe o ponteiro pe um len para qualquer coisa que precise de um subvetor.
notelen deve ser !!
len < myVec.size()-start
fonte
Talvez o array_view / span na biblioteca GSL seja uma boa opção.
Aqui também está uma implementação de arquivo único: array_view .
fonte
Copie elementos de um vetor para outro facilmente
Neste exemplo, estou usando um vetor de pares para facilitar a compreensão de
`
'
Como você pode ver, pode copiar facilmente elementos de um vetor para outro, se quiser copiar elementos do índice 10 para 16, por exemplo, usaríamos
e se você quiser elementos do índice 10 para algum índice do final, nesse caso
Espero que isso ajude, basta lembrar no último caso
v.end()-5 > v.begin()+10
fonte
Outra opção: Útil, por exemplo, ao se mover entre a
thrust::device_vector
e athrust::host_vector
, onde você não pode usar o construtor.Também deve ser complexidade O (N)
Você pode combinar isso com o melhor código da resposta
fonte