Trabalho Prático no 1

Módulo de árvores binárias

Métodos de Programação II

Introdução

Este trabalho deve ser realizado por grupos com um máximo de três alunos. O trabalho deve ser entregue até ao dia 31 de Março na recepção do Departamento de Informática e nele deve constar a listagem do código escrito assim como um pequeno relatório em cuja primeira página deverá constar a identificação dos membros do grupo (número; nome e curso).

Enunciado

Este trabalho prático vem no seguimento do primeiro trabalho realizado na disciplina de Métodos de Programação I. Nesse trabalho foi construído um módulo de árvores binárias na linguagem Haskell. Vamos agora implementar um módulo de árvores só que, desta vez, em C. Apresenta-se o enunciado do trabalho da disciplina de Método de Programação I em apêndice onde são contextualizadas as funções que se pretendem codificar. Uma possível resolução também é apresentada.

O objectivo deste trabalho pode então ser expresso em termos muito simples: pretende-se realizar um módulo C com funcionalidade análoga ao módulo apresentado para Haskell . Por ``funcionalidade análoga'' entende-se uma funcionalidade devidamente ajustada ao paradigma imperativo. A título de exemplo: quando em Haskell tornamos o tipo de árvores instância da classe Show é evidente que não existe correspondente directo em C. No entanto, no módulo realizado deverá existir uma função que permita visualizar o conteúdo de uma árvore (afinal a razão pela qual a referida instância foi requerida).

No relatório pode também referir em que medida foi possível adoptar as codificações fornecidas como ``modelo'' das realizadas (e, quando não foi, que justificação encontra para esse facto).

Valorizações


Enunciado do trabalho 1 de MP1

As árvores binárias são uma estrutura de dados já estudada no decorrer deste curso.

Pretende-se realizar um módulo de árvores binárias em C. Para isso vamos considerar o seguinte fragmento de código.

module ArvBin where

import List


data ArvBin a = Vazia | Nodo a (ArvBin a) (ArvBin a) deriving Eq


vazia :: ArvBin a -> Bool
vazia Vazia = True
vazia _ = False

esq :: ArvBin a -> ArvBin a
esq (Nodo x y z) = y

dir :: ArvBin a -> ArvBin a
dir (Nodo x y z) = z

val :: ArvBin a -> a
val (Nodo x y z) = x

Pretende-se agora completar código deste módulo por forma a incluir a funcionalidade descrita abaixo.

Vamos designar por traço de uma árvore um percurso da raiz até uma sub-árvore vazia. Assim, e a título de exemplo, a árvore

(Nodo 5 (Nodo 3 (Nodo 1 Vazia Vazia) (Nodo 4 Vazia Vazia)) Vazia)
possui como traços as sequências [5,3,1]; [5,3,4] e [5].

Um das principais motivos para a utilização das árvores binárias é o facto de permitirem uma pesquisa mais eficiente. Para isso devem ser construídas de uma forma particular: em qualquer nodo, os valores armazenados na sub-árvore esquerda devem ser inferiores ao valor desse nodo e os armazenados na sub-árvore direita superiores. Nesse caso, para pesquisar um elemento numa árvore, necessitamos de procurar unicamente uma das sub-árvores o que torna o processo de busca mais eficiente. Em Haskell podemos definir essa função como

elemAB :: (Ord a) => a -> ArvBin a -> Bool
elemAB x Vazia = False
elemAB x (Nodo v e d) = x==v || if x<v
                                then (elemAB x e)
                                else (elemAB x d)

Uma árvore que satisfaça o invariante descrito acima designa-se por "árvore binária de procura".

Uma estrutura de dados também implementada em árvores binárias é a "Heap". Uma "Heap" é uma árvore binária onde cada traço está ordenado de forma crescente.

Valorização

As árvores binárias podem ser generalizadas retirando a restrição de existirem exactamente duas sub-árvores em cada nodo não vazio. Uma árvore genérica é então uma árvore com um número arbitrário de sub-árvores.

Resolução do trabalho de MP1

module ArvBin where
import List

data ArvBin a = Vazia | Nodo a (ArvBin a) (ArvBin a) deriving Eq

vazia :: ArvBin a -> Bool
vazia Vazia = True
vazia _ = False

esq :: ArvBin a -> ArvBin a
esq (Nodo x y z) = y

dir :: ArvBin a -> ArvBin a
dir (Nodo x y z) = z

val :: ArvBin a -> a
val (Nodo x y z) = x

peso :: ArvBin a -> Int
peso Vazia = 0
peso (Nodo _ e d) = max (peso e) (peso d)

instance Show a => Show (ArvBin a) where
    showsPrec _ Vazia = showString "_"
    showsPrec _ (Nodo x e d) = showString "{" . (shows x) .
                               showString ":" . (shows e) .
                               showString "|" . (shows d) .
                               showString "}"

in_order :: ArvBin a -> [a]
in_order Vazia = []
in_order (Nodo x e d) = (in_order e) ++ [x] ++ (in_order d)

pre_order :: ArvBin a -> [a]
pre_order Vazia = []
pre_order (Nodo x e d) = x:(pre_order e) ++ (pre_order d)

pos_order :: ArvBin a -> [a]
pos_order Vazia = []
pos_order (Nodo x e d) = (pos_order e) ++ (pos_order d) ++ [x]

traces :: ArvBin a -> [[a]]
traces Vazia = [[]]
traces (Nodo x Vazia Vazia) = [[x]]
traces (Nodo x e d) = map (x:) ((traces e)++(traces d))

{- Árvores Binárias de Procura -}

elemAB :: (Ord a) => a -> ArvBin a -> Bool
elemAB x Vazia = False
elemAB x (Nodo v e d) = x==v || if x<v
                                then (elemAB x e)
                                else (elemAB x d)

listOrd :: (Ord a) => [a] -> Bool
listOrd [] = True
listOrd l = and (zipWith (<=) l (tail l))

checkAB :: (Ord a) => ArvBin a -> Bool
checkAB = listOrd . in_order

balanAB :: ArvBin a -> Bool
balanAB a = let (min,max) = minmax (map length (traces a))
                in max-min < 2
            where minmax [x] = (x,x)
                  minmax (x:xs) = let (min,max) = minmax xs
                                      in (if x<min then x else min,
                                          if x>max then x else max)

{- HEAPs -}

checkHeap :: Ord a => ArvBin a -> Bool
checkHeap = and . (map listOrd) . traces

remHeap :: Ord a => a -> ArvBin a -> ArvBin a
remHeap x Vazia = Vazia
remHeap x (Nodo y e d)
  | x<y  = Nodo y e d
  | x>y  = Nodo y (remHeap x e) (remHeap x d)
  | True = case e of
           Vazia -> d
           (Nodo ye _ _) -> case d of
                            Vazia -> e
                            (Nodo yd _ _) -> if ye<yd
                                             then (Nodo ye
                                                   (remHeap ye e)
                                                   d)
                                             else (Nodo yd
                                                   e
                                                   (remHeap yd d))



José Carlos Bacelar
José Bernardo Barros
Fernando Luis Neves

1999-03-16