-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathColaDePrioridadConListas.hs
178 lines (148 loc) · 5.96 KB
/
ColaDePrioridadConListas.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
-- ColaDePrioridadConListas.hs
-- El tipo de datos de las colas de prioridad mediante listas.
-- José A. Alonso Jiménez <https://jaalonso.github.io>
-- Sevilla, 05-julio-2023
-- ---------------------------------------------------------------------
{-# LANGUAGE FlexibleInstances #-}
{-# OPTIONS_GHC -fno-warn-unused-top-binds #-}
module TAD.ColaDePrioridadConListas
(CPrioridad,
vacia, -- Ord a => CPrioridad a
inserta, -- Ord a => a -> CPrioridad a -> CPrioridad a
primero, -- Ord a => CPrioridad a -> a
resto, -- Ord a => CPrioridad a -> CPrioridad a
esVacia, -- Ord a => CPrioridad a -> Bool
) where
import Test.QuickCheck
-- Colas de prioridad mediante listas.
newtype CPrioridad a = CP [a]
deriving Eq
-- (escribeColaDePrioridad c) es la cadena correspondiente a la cola de
-- prioridad c. Por ejemplo,
-- λ> escribeColaDePrioridad (inserta 5 (inserta 2 (inserta 3 vacia)))
-- "2 | 3 | 5"
escribeColaDePrioridad :: Show a => CPrioridad a -> String
escribeColaDePrioridad (CP []) = "-"
escribeColaDePrioridad (CP [x]) = show x
escribeColaDePrioridad (CP (x:xs)) = show x ++ " | " ++ escribeColaDePrioridad (CP xs)
-- Procedimiento de escritura de colas de prioridad.
instance Show a => Show (CPrioridad a) where
show = escribeColaDePrioridad
-- Ejemplo de cola de prioridad
-- λ> inserta 5 (inserta 2 (inserta 3 vacia))
-- 2 | 3 | 5
-- vacia es la cola de prioridad vacía. Por ejemplo,
-- λ> vacia
-- CP []
vacia :: Ord a => CPrioridad a
vacia = CP []
-- (inserta x c) es la cola obtenida añadiendo el elemento x a la cola
-- de prioridad c. Por ejemplo,
-- λ> inserta 5 (foldr inserta vacia [3,1,7,2,9])
-- 1 | 2 | 3 | 5 | 7 | 9
inserta :: Ord a => a -> CPrioridad a -> CPrioridad a
inserta x (CP q) = CP (ins x q)
where ins y [] = [y]
ins y r@(e:r') | y < e = y:r
| otherwise = e:ins y r'
-- (primero c) es el primer elemento de la cola de prioridad c. Por
-- ejemplo,
-- primero (foldr inserta vacia [3,1,7,2,9]) == 1
primero :: Ord a => CPrioridad a -> a
primero (CP(x:_)) = x
primero _ = error "primero: cola de prioridad vacia"
-- (resto c) es la cola de prioridad obtenida eliminando el primer
-- elemento de la cola de prioridad c. Por ejemplo,
-- λ> resto (foldr inserta vacia [3,1,7,2,9])
-- 2 | 3 | 7 | 9
resto :: Ord a => CPrioridad a -> CPrioridad a
resto (CP (_:xs)) = CP xs
resto _ = error "resto: cola de prioridad vacia"
-- (esVacia c) se verifica si la cola de prioridad c es vacía. Por
-- ejemplo,
-- esVacia (foldr inserta vacia [3,1,7,2,9]) == False
-- esVacia vacia == True
esVacia :: Ord a => CPrioridad a -> Bool
esVacia (CP xs) = null xs
-- Generador de colas de prioridad
-- ===============================
-- genCPrioridad es un generador de colas de enteros. Por ejemplo,
-- λ> sample genCPrioridad
-- -
-- 0 | 0
-- 4
-- -4 | -3 | 6 | 6
-- -7 | -6 | -2 | 0
-- -10 | -10 | -5 | 1 | 4 | 6 | 6 | 9 | 10
-- -
-- -13 | -11 | -9 | -5 | -2 | -1 | 0 | 1 | 2 | 2 | 13 | 14
-- -15 | -13 | -13 | -5 | -3 | -1 | 3 | 5 | 7 | 9 | 9 | 14 | 16
-- -
-- -17 | -15 | -14 | -5 | -2 | 1 | 1 | 2 | 5 | 7
genCPrioridad :: (Arbitrary a, Num a, Ord a) => Gen (CPrioridad a)
genCPrioridad = do
xs <- listOf arbitrary
return (foldr inserta vacia xs)
-- El tipo cola de prioridad es una instancia del arbitrario.
instance (Arbitrary a, Num a, Ord a) => Arbitrary (CPrioridad a) where
arbitrary = genCPrioridad
-- Propiedades de las colas de prioridad
-- =====================================
-- Propiedad. Si se añade dos elementos a una cola de prioridad se
-- obtiene la misma cola de prioridad idependientemente del orden en
-- que se añadan los elementos.
prop_inserta_conmuta :: Int -> Int -> CPrioridad Int -> Bool
prop_inserta_conmuta x y c =
inserta x (inserta y c) == inserta y (inserta x c)
-- Comprobación.
-- λ> quickCheck prop_inserta_conmuta
-- +++ OK, passed 100 tests.
-- Propiedad. La cabeza de la cola de prioridad obtenida añadiendo un
-- elemento x a la cola de prioridad vacía es x.
prop_primero_inserta_vacia :: Int -> CPrioridad Int -> Bool
prop_primero_inserta_vacia x _ =
primero (inserta x vacia) == x
-- Comprobación.
-- λ> quickCheck prop_primero_inserta_vacia
-- +++ OK, passed 100 tests.
-- Propiedad. El primer elemento de una cola de prioridad c no cambia
-- cuando se le añade un elemento mayor o igual que algún elemento de c.
prop_primero_inserta :: Int -> Int -> CPrioridad Int -> Property
prop_primero_inserta x y c =
x <= y ==> primero (inserta y c') == primero c'
where c' = inserta x c
-- Comprobación.
-- λ> quickCheck prop_primero_inserta
-- +++ OK, passed 100 tests.
-- Propiedad. El resto de añadir un elemento a la cola de prioridad
-- vacía es la cola vacía.
prop_resto_inserta_vacia :: Int -> Bool
prop_resto_inserta_vacia x =
resto (inserta x vacia) == vacia
-- Comprobación.
-- λ> quickCheck prop_resto_inserta_vacia
-- +++ OK, passed 100 tests.
-- Propiedad. El resto de la cola de prioridad obtenida añadiendo un
-- elemento y a una cola c' (que tiene algún elemento menor o igual que
-- y) es la cola que se obtiene añadiendo y al resto de c'.
prop_resto_inserta :: Int -> Int -> CPrioridad Int -> Property
prop_resto_inserta x y c =
x <= y ==> resto (inserta y c') == inserta y (resto c')
where c' = inserta x c
-- Comprobación:
-- λ> quickCheck prop_resto_inserta
-- +++ OK, passed 100 tests.
-- Propiedad. vacia es una cola vacía.
prop_vacia_es_vacia :: Bool
prop_vacia_es_vacia = esVacia (vacia :: CPrioridad Int)
-- Comprobación.
-- λ> quickCheck prop_vacia_es_vacia
-- +++ OK, passed 100 tests.
-- Propiedad. Si se añade un elemento a una cola de prioridad se obtiene
-- una cola no vacía.
prop_inserta_no_es_vacia :: Int -> CPrioridad Int -> Bool
prop_inserta_no_es_vacia x c =
not (esVacia (inserta x c))
-- Comprobación.
-- λ> quickCheck prop_inserta_no_es_vacia
-- +++ OK, passed 100 tests.