c#
.net
vb.net
data-structures
linked-list
Jonathan Allen
fonte
fonte
Respostas:
Editar
Resposta original ...
Encontrei resultados interessantes:
Lista vinculada (3,9 segundos)
Lista (2,4 segundos)
Mesmo se você acessar apenas os dados essencialmente, é muito mais lento !! Eu digo nunca use um LinkedList.
Aqui está outra comparação executando várias inserções (planejamos inserir um item no meio da lista)
Lista vinculada (51 segundos)
Lista (7,26 segundos)
Lista vinculada com referência do local onde inserir (0,04 segundos)
Portanto, somente se você planeja inserir vários itens e também tiver em algum lugar a referência de onde planeja inserir o item, use uma lista vinculada. Só porque você precisa inserir muitos itens, não o torna mais rápido, porque pesquisar no local em que você deseja inserir leva tempo.
fonte
list.AddLast(a);
nos dois últimos exemplos de LinkedList? Eu faço isso uma vez antes do loop, comolist.AddLast(new Temp(1,1,1,1));
no próximo ao último LinkedList, mas parece (para mim) que você está adicionando o dobro de objetos Temp nos próprios loops. (E quando eu me checar com um aplicativo de teste , com certeza, o dobro na LinkedList.)I say never use a linkedList.
é falho, como revela seu post posterior. Você pode querer editá-lo. 2) O que você está cronometrando? Instanciação, adição e enumeração em uma única etapa? Principalmente, instanciação e enumeração não são o que preocupam as pessoas, essas são etapas únicas. Cronometrar especificamente as inserções e adições daria uma idéia melhor. 3) Mais importante, você está adicionando mais do que o necessário a uma lista vinculada. Esta é uma comparação errada. Espalha a ideia errada sobre a lista vinculada.Na maioria dos casos,
List<T>
é mais útil.LinkedList<T>
terá menos custo ao adicionar / remover itens no meio da lista, ao passo queList<T>
apenas poderá adicionar / remover mais barato no final da lista.LinkedList<T>
é o mais eficiente se você estiver acessando dados seqüenciais (para frente ou para trás) - o acesso aleatório é relativamente caro, pois deve percorrer a cadeia a cada vez (daí o motivo de não ter um indexador). No entanto, como aList<T>
é essencialmente apenas um acesso aleatório de matriz (com um invólucro), tudo bem.List<T>
também oferece uma série de métodos de apoio -Find
,ToArray
, etc; no entanto, eles também estão disponíveisLinkedList<T>
no .NET 3.5 / C # 3.0 por meio de métodos de extensão - portanto, isso é menos importante.fonte
List<T>
eT[]
falhará por ser muito robusto (tudo uma laje),LinkedList<T>
lamentará por ser muito granular (laje por elemento).Pensar em uma lista vinculada como uma lista pode ser um pouco enganador. É mais como uma corrente. De fato, no .NET,
LinkedList<T>
nem sequer implementaIList<T>
. Não existe um conceito real de índice em uma lista vinculada, mesmo que pareça existir. Certamente, nenhum dos métodos fornecidos na classe aceita índices.As listas vinculadas podem ser vinculadas individualmente ou duplamente vinculadas. Isso se refere ao fato de cada elemento da cadeia ter um link apenas para o próximo (vinculado individualmente) ou para os elementos anteriores / próximos (vinculados duplamente).
LinkedList<T>
está duplamente ligado.Internamente,
List<T>
é apoiado por uma matriz. Isso fornece uma representação muito compacta na memória. Por outro lado,LinkedList<T>
envolve memória adicional para armazenar os links bidirecionais entre elementos sucessivos. Portanto, o espaço de memória de aLinkedList<T>
geralmente será maior do que paraList<T>
(com a ressalva de queList<T>
pode haver elementos de matriz internos não utilizados para melhorar o desempenho durante operações de acréscimo).Eles também têm características de desempenho diferentes:
Acrescentar
LinkedList<T>.AddLast(item)
tempo constanteList<T>.Add(item)
tempo constante amortizado, pior caso linearAnexar
LinkedList<T>.AddFirst(item)
tempo constanteList<T>.Insert(0, item)
tempo linearInserção
LinkedList<T>.AddBefore(node, item)
tempo constanteLinkedList<T>.AddAfter(node, item)
tempo constanteList<T>.Insert(index, item)
tempo linearRemoção
LinkedList<T>.Remove(item)
tempo linearLinkedList<T>.Remove(node)
tempo constanteList<T>.Remove(item)
tempo linearList<T>.RemoveAt(index)
tempo linearContagem
LinkedList<T>.Count
tempo constanteList<T>.Count
tempo constanteContém
LinkedList<T>.Contains(item)
tempo linearList<T>.Contains(item)
tempo linearClaro
LinkedList<T>.Clear()
tempo linearList<T>.Clear()
tempo linearComo você pode ver, eles são basicamente equivalentes. Na prática, a API de
LinkedList<T>
é mais complicada de usar e detalhes de suas necessidades internas se espalham pelo seu código.No entanto, se você precisar fazer muitas inserções / remoções de uma lista, ele oferece tempo constante.
List<T>
oferece tempo linear, pois itens extras na lista devem ser embaralhados após a inserção / remoção.fonte
As listas vinculadas fornecem inserção ou exclusão muito rápidas de um membro da lista. Cada membro de uma lista vinculada contém um ponteiro para o próximo membro da lista, para inserir um membro na posição i:
A desvantagem de uma lista vinculada é que o acesso aleatório não é possível. Para acessar um membro, é necessário percorrer a lista até que o membro desejado seja encontrado.
fonte
Minha resposta anterior não foi suficientemente precisa. Como realmente foi horrível: D Mas agora posso postar respostas muito mais úteis e corretas.
Eu fiz alguns testes adicionais. Você pode encontrar a fonte no seguinte link e verificar novamente em seu ambiente: https://github.com/ukushu/DataStructuresTestsAndOther.git
Resultados curtos:
A matriz precisa usar:
A lista precisa usar:
O LinkedList precisa usar:
Mais detalhes:
Interessante saber:
LinkedList<T>
internamente não é uma lista no .NET. É mesmo não implementaIList<T>
. E é por isso que existem índices e métodos ausentes relacionados a índices.LinkedList<T>
é uma coleção baseada em ponteiro de nó. No .NET está em implementação duplamente vinculada. Isso significa que os elementos anteriores / próximos têm um link para o elemento atual. E os dados são fragmentados - diferentes objetos de lista podem ser localizados em diferentes locais da RAM. Também haverá mais memória usada paraLinkedList<T>
que paraList<T>
ou Array.List<T>
em .Net é a alternativa de Java paraArrayList<T>
. Isso significa que este é um wrapper de matriz. Portanto, é alocado na memória como um bloco de dados contíguo. Se o tamanho dos dados alocados exceder 85000 bytes, ele será movido para Heap de Objetos Grandes. Dependendo do tamanho, isso pode levar à fragmentação da pilha (uma forma moderada de vazamento de memória). Mas, ao mesmo tempo, se o tamanho for <85000 bytes - isso fornece uma representação muito compacta e de acesso rápido na memória.Um único bloco contíguo é preferido para desempenho de acesso aleatório e consumo de memória, mas para coleções que precisam mudar de tamanho regularmente, uma estrutura como uma matriz geralmente precisa ser copiada para um novo local, enquanto uma lista vinculada precisa gerenciar a memória para os recém-inseridos / nós excluídos.
fonte
A diferença entre List e LinkedList está na implementação subjacente. Lista é uma coleção baseada em matriz (ArrayList). LinkedList é uma coleção baseada em ponteiro de nó (LinkedListNode). No uso no nível da API, os dois são praticamente os mesmos, pois implementam o mesmo conjunto de interfaces, como ICollection, IEnumerable, etc.
A principal diferença ocorre quando o desempenho é importante. Por exemplo, se você estiver implementando a lista que possui uma operação pesada "INSERT", o LinkedList supera a lista. Como o LinkedList pode fazê-lo em O (1), mas a Lista pode precisar expandir o tamanho da matriz subjacente. Para obter mais informações / detalhes, convém ler a diferença algorítmica entre o LinkedList e as estruturas de dados da matriz. http://en.wikipedia.org/wiki/Linked_list e matriz
Espero que esta ajuda,
fonte
Add
está sempre no final da matriz existente.List
é "bom o suficiente", mesmo que não seja O (1). O sério problema ocorre se você precisar de muitosAdd
s que não estão no final. Marc está apontando que a necessidade de mover dados existentes toda vez que você insere (não apenas quando o redimensionamento é necessário) é um custo de desempenho mais substancialList
.A principal vantagem das listas vinculadas sobre as matrizes é que os links nos fornecem a capacidade de reorganizar os itens com eficiência. Sedgewick, p. 91
fonte
Uma circunstância comum para usar o LinkedList é assim:
Suponha que você queira remover muitas cadeias de caracteres de uma lista de grandes dimensões, digamos 100.000. As cadeias a serem removidas podem ser consultadas no HashSet dic e acredita-se que a lista de cadeias contenha entre 30.000 a 60.000 dessas cadeias para remover.
Então, qual é o melhor tipo de lista para armazenar as 100.000 cordas? A resposta é LinkedList. Se eles estiverem armazenados em um ArrayList, a iteração e a remoção de Strings correspondentes levarão bilhões de operações, enquanto são necessárias cerca de 100.000 operações usando um iterador e o método remove ().
fonte
RemoveAll
para remover os itens de umList
sem mover muitos itens ou usar oWhere
LINQ para criar uma segunda lista.LinkedList
No entanto, usar um aqui acaba consumindo muito mais memória do que outros tipos de coleções e a perda da localidade da memória significa que será visivelmente mais lento para iterar, tornando-o um pouco pior que aList
.RemoveAll
equivalente em Java.RemoveAll
não estiver disponívelList
, você pode fazer um algoritmo de "compactação", que se pareceria com o loop de Tom, mas com dois índices e a necessidade de mover itens para manter um de cada vez na matriz interna da lista. A eficiência é O (n), o mesmo que o algoritmo de TomLinkedList
. Nas duas versões, o tempo para calcular a chave HashSet para as seqüências de caracteres domina. Este não é um bom exemplo de quando usarLinkedList
.Quando você precisar de acesso indexado interno, classificação (e após esta pesquisa binária) e o método "ToArray ()", use a Lista.
fonte
Essencialmente, um
List<>
no .NET é um invólucro sobre uma matriz . ALinkedList<>
é uma lista vinculada . Portanto, a questão se resume a: qual é a diferença entre uma matriz e uma lista vinculada e quando deve ser usada uma matriz em vez de uma lista vinculada. Provavelmente, os dois fatores mais importantes na sua decisão de qual usar se resumiriam a:fonte
Isso é adaptado da resposta aceita de Tono Nam , corrigindo algumas medidas erradas.
O teste:
E o código:
Você pode ver que os resultados estão de acordo com o desempenho teórico que outros documentaram aqui. Muito claro -
LinkedList<T>
ganha muito tempo em caso de inserções. Não testei a remoção no meio da lista, mas o resultado deve ser o mesmo. Obviamente, existemList<T>
outras áreas em que o desempenho é muito melhor, como o acesso aleatório O (1).fonte
Use
LinkedList<>
quandoToken Stream
,.Para todo o resto, é melhor usar
List<>
.fonte
LinkedListNode<T>
objetos no seu código. Se você pode fazer isso, é muito melhor do que usarList<T>
, especialmente para listas muito longas, onde inserções / remoções são frequentes.node.Value
lo sempre que quiser o elemento original). Então você reescreve o algoritmo para trabalhar com nós, não com valores brutos.Eu concordo com a maior parte do argumento exposto acima. E também concordo que a Lista parece uma escolha mais óbvia na maioria dos casos.
Mas quero apenas acrescentar que há muitas instâncias em que o LinkedList é uma escolha muito melhor do que List, para uma melhor eficiência.
Espero que alguém ache esses comentários úteis.
fonte
Tantas respostas médias aqui ...
Algumas implementações de lista vinculada usam blocos subjacentes de nós pré-alocados. Se eles não fizerem isso, o tempo constante / tempo linear será menos relevante, pois o desempenho da memória será ruim e o desempenho do cache ainda pior.
Use listas vinculadas quando
1) Você quer segurança da linha. Você pode criar melhores algos seguros para threads. Os custos de bloqueio dominam uma lista de estilos simultâneos.
2) Se você tem uma fila grande como estruturas e deseja remover ou adicionar qualquer lugar, exceto o final, o tempo todo. > 100K listas existem, mas não são tão comuns.
fonte
Fiz uma pergunta semelhante relacionada ao desempenho da coleção LinkedList e descobri que o implemento C # de Steven Cleary do Deque era uma solução. Diferentemente da coleção Fila, o Deque permite ativar / desativar itens na frente e atrás. É semelhante à lista vinculada, mas com desempenho aprimorado.
fonte
Deque
é "semelhante a lista ligada, mas com melhor desempenho" . Por favor qualificar essa afirmação:Deque
é o desempenho melhor do queLinkedList
, para o seu código específico . Seguindo o seu link, vejo que dois dias depois você aprendeu com Ivan Stoev que isso não era uma ineficiência do LinkedList, mas uma ineficiência no seu código. (E mesmo se tivesse sido uma ineficiência de LinkedList, que não justificam uma declaração geral que Deque é mais eficiente, apenas em casos específicos.)