Je travaille sur un petit projet de Haskell qui nécessite un tampon circulaire. J'ai réussi à créer une mémoire tampon en utilisant des tableaux qui ont une rotation O (1), mais qui nécessite bien sûr O (N) pour l'insertion/la suppression. J'ai trouvé une implémentation en utilisant des listes qui semblent prendre O (1) pour l'insertion et la suppression, mais comme elle maintient une liste gauche et droite, croiser une certaine frontière quand la rotation prendra le temps O (N). Dans un langage impératif, je pourrais implémenter un tampon circulaire doublement lié avec O (1) insertion, suppression et rotation. Je pense que ce n'est pas possible dans un langage purement fonctionnel comme Haskell, mais j'aimerais savoir si je me trompe.O (1) tampon circulaire en haskell?
Répondre
La monade ST
permet de décrire et d'exécuter des algorithmes impératifs dans Haskell. Vous pouvez utiliser STRef
s pour les pointeurs modifiables de votre liste doublement chaînée.
Les algorithmes autonomes décrits à l'aide de ST
sont exécutés à l'aide de runST
. Différentes exécutions runST
peuvent ne pas partager ST
structures de données (STRef
, STArray
, ..).
Si l'algorithme n'est pas "autonome" et que la structure de données doit être maintenue avec les opérations d'E/S effectuées entre ses utilisations, vous pouvez utiliser stToIO
pour y accéder dans la monade IO
.
En ce qui concerne si c'est purement fonctionnel ou non - je suppose que ce n'est pas?
Si vous pouvez traiter amorti O (1) opérations, vous pouvez probablement utiliser soit Data.Sequence
de l'emballage conteneurs ou Data.Dequeue
du paquet dequeue. Le premier utilise finger trees, tandis que le second utilise la "Dequeue du banquier" du Purely Functional Data Structures d'Okasaki (une version antérieure en ligne here).
Il semble que vous ayez besoin de quelque chose d'un peu plus compliqué que cela (puisque vous avez mentionné des listes à double liaison), mais peut-être que cela vous aidera. Cette fonction agit comme map
sur une liste cyclique mutable:
mapOnCycling f = concat . tail . iterate (map f)
utilisation comme:
*Main> (+1) `mapOnCycling` [3,2,1]
[4,3,2,5,4,3,6,5,4,7,6,5,8,7,6,9,8,7,10,9...]
Et voici celui qui agit comme mapAccumL:
mapAccumLOnCycling f acc xs =
let (acc', xs') = mapAccumL f acc xs
in xs' ++ mapAccumLOnCycling f acc' xs'
Quoi qu'il en soit, si vous vous souciez d'élaborer encore plus sur ce que votre structure de données doit être capable de "faire", je serais vraiment intéressé à en entendre parler.
EDIT: comme camccann mentionné, vous pouvez utiliser Data.Sequence
pour ce qui, selon la documentation devrait vous donner de la complexité de temps O1 (est-il une telle chose comme O1 amorti le temps?) Pour l'affichage ou l'ajout d'éléments à la fois aux côtés gauche et droit de la séquence, ainsi que de modifier les extrémités le long du chemin. Si cela aura la performance dont vous avez besoin, je ne suis pas sûr.
Vous pouvez traiter "l'emplacement actuel" comme l'extrémité gauche de la séquence. Ici nous naviguons d'avant en arrière le long d'une séquence, produisant une liste infinie de valeurs.Désolé si elle ne compile pas, je n'ai pas GHC au moment:
shuttle (viewl-> a <: as) = a : shuttle $ rotate (a+1 <| as)
where rotate | even a = rotateForward
| otherwise = rotateBack
rotateBack (viewr-> as' :> a') = a' <| as'
rotateForward (viewl-> a' <: as') = as' |> a'
Voir le commentaire sur la question d'origine pour une fonctionnalité plus spécifique. – Edward
Mis à jour ma réponse, qui je pense vous donne ce que vous recherchez dans une solution purement fonctionnelle – jberryman
Par ailleurs, amortis O (1) est parfaitement raisonnable - cela signifie simplement que des opérations coûteuses peuvent se produire, mais avec une fréquence inversement proportionnelle à leur coût. Par exemple, une opération peut être O (1) la plupart du temps et O (N) occasionnellement, mais tant que cette dernière n'est pas plus commune qu'une fois sur N opérations, la complexité amortie est toujours O (1). C'est génial pour la plupart des objectifs, mais pas tellement pour soft-realtime que par les commentaires sur la question ici ... –
- 1. Tampon circulaire dans VB.NET
- 2. Irrégularités de pointeur de tampon circulaire
- 3. Obtenir le milieu d'une gamme Ix en O (1) temps dans Haskell
- 4. Affichage des données dans un tampon circulaire en temps réel
- 5. Comment coder un tampon circulaire simple en C/C++?
- 6. Quelle structure de données pour O (1) insertion/suppression aléatoire et O (1) accès aléatoire?
- 7. Comment puis-je prouver que 1/n est O (1)?
- 8. Fonction qui est Big O (1) mais pas Ω (1)
- 9. Suggestions pour la gestion d'index concise dans le tampon circulaire
- 10. Comment itérez-vous en arrière sur un tampon circulaire sans condition?
- 11. Pourquoi passer du planificateur O (1) à CFS qui est O (log N)?
- 12. dépendance circulaire (?) En C++
- 13. Inverse une chaîne dans Java, dans O (1)?
- 14. Recherche de dictionnaire (O (1)) vs Linq où
- 15. Pourquoi insérer au milieu d'une liste chaînée O (1)?
- 16. Collection 'correcte' à utiliser pour obtenir des objets en O (1) en C# .NET?
- 17. circulaire C++ en-tête comprend
- 18. circulaire Référence
- 19. circulaire Référence- LINQ to SQL
- 20. Comportement incohérent avec Haskell
- 21. retour en arrière dans haskell
- 22. match circulaire
- 23. MySQL O WH EN QUESTION?
- 24. Makefile dépendance circulaire
- 25. Palindromes en Haskell
- 26. fichier i/o en C++
- 27. dépendance circulaire
- 28. décalage circulaire c
- 29. Haskell convertissant Float en Int
- 30. Implémentation d'un fichier journal de taille fixe ou d'un tampon circulaire sur le disque
Si « traversant une certaine frontière » lors de la rotation prend O (n), quel est le coût quand il ne traverse pas la frontière? Si c'est O (1) et que vous avez seulement une probabilité 1/N de traverser la frontière, la rotation prend O (1) en moyenne. – finnw
A droite, mais en effectuant une opération séquentielle, vous avez la garantie de la traverser à un moment donné, et la complexité temporelle est importante pour chaque rotation, car cela finira probablement par être une application soft-realtime. – Edward
Je n'ai jamais utilisé un tampon circulaire; Est-il facile de donner une brève description de ce que fait votre tampon? Dans votre application devrait-il "écraser" des éléments? – jberryman