Percebi que a maioria das linguagens funcionais emprega uma lista vinculada individual (uma lista de "contras") como seus tipos de lista mais fundamentais. Exemplos incluem Common Lisp, Haskell e F #. Isso é diferente dos idiomas principais, onde os tipos de lista nativos são matrizes.
Por que é que?
Para o Common Lisp (sendo digitado dinamicamente), tenho a ideia de que os contras são gerais o suficiente para também serem a base de listas, árvores etc. Isso pode ser uma pequena razão.
Para linguagens de tipo estaticamente, no entanto, não consigo encontrar um bom raciocínio, posso até encontrar contra-argumentos:
- O estilo funcional incentiva a imutabilidade; portanto, a facilidade de inserção da lista vinculada é menos uma vantagem,
- O estilo funcional incentiva a imutabilidade, assim como o compartilhamento de dados; é mais fácil compartilhar "parcialmente" que uma lista vinculada,
- Você também pode fazer a correspondência de padrões em uma matriz regular e ainda melhor (você pode facilmente dobrar da direita para a esquerda, por exemplo),
- Além disso, você obtém acesso aleatório gratuitamente,
- E (uma vantagem prática) se o idioma for digitado estaticamente, você poderá empregar um layout de memória regular e obter um aumento de velocidade no cache.
Então, por que preferir listas vinculadas?
an array is easier to share "partially" than a linked list
precisa de esclarecimentos sobre o que você quer dizer. Devido à sua natureza recursiva, o oposto é verdadeiro como eu o entendo - você pode compartilhar parcialmente uma lista vinculada mais facilmente passando qualquer nó nela, enquanto uma matriz precisaria gastar tempo fazendo uma nova cópia. Ou em termos de compartilhamento de dados, duas listas vinculadas podem apontar para o mesmo sufixo, o que simplesmente não é possível com matrizes.Respostas:
O fator mais importante é que você pode anexar uma lista vinculada imutável individualmente em O (1), o que permite criar recursivamente listas de elementos n em O (n), desta maneira:
Se você fizesse isso usando matrizes imutáveis, o tempo de execução seria quadrático, pois cada
cons
operação precisaria copiar toda a matriz, levando a um tempo de execução quadrático.Eu suponho que, compartilhando "parcialmente", você quer dizer que pode pegar um subarray de uma matriz no tempo O (1), enquanto que nas listas vinculadas você pode pegar o rabo no tempo O (1) e todo o resto precisa de O (n). Isso é verdade.
No entanto, levar o rabo é suficiente em muitos casos. E você deve levar em conta que ser capaz de criar sub-matrizes de maneira barata não ajuda se você não tiver como criar matrizes de maneira barata. E (sem otimizações inteligentes do compilador), não há como criar uma matriz barata passo a passo.
fonte
Eu acho que tudo se resume a listas sendo facilmente implementadas em código funcional.
Esquema:
Haskell:
Matrizes são mais difíceis e não são tão bonitas de implementar. Se você quiser que eles sejam extremamente rápidos, eles terão que ser escritos em baixo nível.
Além disso, a recursão funciona muito melhor em listas do que em matrizes. Considere o número de vezes que você consumiu / gerou recursivamente uma lista e indexou uma matriz.
fonte
Uma lista vinculada individualmente é a estrutura de dados persistente mais simples .
Estruturas de dados persistentes são essenciais para uma programação puramente funcional e de alto desempenho.
fonte
Você pode usar nós Contras facilmente apenas se tiver um idioma coletado pelo lixo.
Contras Os nós correspondem muito ao estilo de programação funcional de chamadas recursivas e valores imutáveis. Portanto, ele se encaixa bem no modelo do programador mental.
E não se esqueça de razões históricas. Por que eles ainda são chamados Nós de Contras e, pior ainda, usam carro e cdr como acessadores? As pessoas aprendem isso com livros e cursos e depois o usam.
Você está certo, no mundo real, as matrizes são muito mais fáceis de usar, consomem apenas metade do espaço de memória e têm muito desempenho devido a falhas no nível do cache. Não há razão para usá-los com linguagens imperativas.
fonte
As listas vinculadas são importantes pelo seguinte motivo:
Depois de pegar um número como 3 e convertê-lo para a sequência sucessora como
succ(succ(succ(zero)))
e, em seguida, use a substituição com{succ=List node with some memory space}
e{zero = end of list}
você terminará com uma lista vinculada (de tamanho 3).A parte importante é números, substituição e espaço na memória e zero.
fonte