Tipos Abstractos de Dados Luís Lopes DCC-FCUP Estruturas de Dados Tipos Abstractos de Dados (TAD) I um Tipo Abstracto de Dados ou TAD é um tipo caracterizado pelos itens de dados que agrega e pelas operações que podem ser realizadas sobre ele I diz-se abstracto porque a sua definição não carece de uma implementação concreta I de facto, para um mesmo TAD podem existir várias implementações possíveis I e.g., uma pilha pode ser implementada com arrays ou com listas (vamos ver este exemplo durante o semestre) I o C++, C#, Java e outras linguagens suportam TAD através do conceito de classe TAD Vector: um vector em R3 I caracterizado por 3 números (coordenadas) I double x, y, z operações incluem: I I I I I I I I I I Vector Vector Vector Vector double Vector double String minus(Vector) add(Vector, Vector) sub(Vector, Vector) scale(double, Vector) scalarProduct(Vector, Vector) crossProduct(Vector, Vector) norm(Vector) toString(Vector) vamos definir 2 classes: Vector para guardar as coordenadas e LibVector para implementar as operações sobre vectores Implementação: Vector.java // a 3d vector p u b l i c c l a s s Vector { // coordinates f i n a l double x; f i n a l double y; f i n a l double z; // constructor p u b l i c Vector ( d o u b l e x0 , d o u b l e y0 , d o u b l e z0 ) { x = x0 ; y = y0 ; z = z0 ; } } Implementação: LibVector.java p u b l i c c l a s s LibVector { p u b l i c s t a t i c Vector add ( Vector u , Vector v ) { r e t u r n new Vector ( u . x + v .x , u . y + v .y , u . z + v . z ); } p u b l i c s t a t i c Vector sub ( Vector u , Vector v ) { r e t u r n add ( u , minus ( v ) ); } p u b l i c s t a t i c Vector scale ( d o u b l e s , Vector u ) { r e t u r n new Vector ( s * u .x , s * u .y , s * u . z ); } p u b l i c s t a t i c d o u b l e scalarProduct ( Vector u , Vector v ) { r e t u r n u.x * v.x + u.y * v.y + u.z * v.z; } p u b l i c s t a t i c d o u b l e norm ( Vector u ) { r e t u r n java . lang . Math . sqrt ( scalarProd (u , u )); } p u b l i c s t a t i c String toString ( Vector v ) { r e t u r n " ( " + v . x + " ," + v . y + " ," + v . z + " ) " ; } ... } Implementação: TestVector.java p u b l i c c l a s s TestVector { p u b l i c s t a t i c v o i d main ( Vector u1 = new Vector Vector u2 = new Vector Vector u3 = new Vector String [] args ( -2.1 , 5.6 , ( 9.7 , 1.1 , ( -12.1 , -7.6 , ) { 3.3); 2.7); 5.1); Vector u4 = LibVector . add ( u1 , u2 ); Vector u5 = LibVector . sub ( u1 , u2 ); Vector u6 = LibVector . scale (2.6 , LibVector . minus ( u3 )); System . out . println ( LibVector . toString ( u4 ) + " \ n " + LibVector . toString ( u5 ) + " \ n " + LibVector . toString ( u6 ) + " \ n " ); } Compilação e execução I para compilar e executar este programa na linha de comando: $ javac Vector . java LibVector . java TestVector . java $ java TestVector I ou simplesmente chamar o compilador com o ficheiro que tem o main: $ javac TestVector . java $ java TestVector TAD Complex: números complexos C I caracterizado por 2 números, a parte real e imaginária I double x, y operações incluem: I I I I I I I I I I I Complex add(Complex, Complex) Complex sub(Complex, Complex) Complex mul(Complex, Complex) Complex div(Complex, Complex) Complex minus(Complex) Complex conj(Complex) doub abs(Complex) double arg(Complex) String toString(Complex) vamos definir 2 classes: Complex para guardar as coordenadas e LibComplex para implementar as operações Implementação: Complex.java p u b l i c f i n a l c l a s s Complex { f i n a l double x; // real f i n a l double y; // imaginary // constructor p u b l i c Complex ( d o u b l e x0 , d o u b l e y0 ) { x = x0 ; y = y0 ; } } Implementação: LibComplex.java p u b l i c c l a s s LibComplex { p u b l i c s t a t i c Complex add ( Complex z1 , Complex z2 ) { r e t u r n new Complex ( z1 . x + z2 .x , z1 . y + z2 . y ); } p u b l i c s t a t i c Complex sub ( Complex z1 , Complex z2 ) { r e t u r n new Complex ( z1 . x - z2 .x , z1 . y - z2 . y ); } p u b l i c s t a t i c Complex mul ( Complex z1 , Complex z2 ) { r e t u r n new Complex ( z1 . x * z2 . x - z1 . y * z2 .y , z1 . x * z2 . y + z1 . y * z2 . x ); } p u b l i c s t a t i c Complex div ( Complex z1 , Complex z2 ) { d o u b l e d = z2 . x * z2 . x + z2 . y * z2 . y ; r e t u r n new Complex (( z1 . x * z2 . x + z1 . y * z2 . y ) / d , ( z1 . y * z2 . x - z1 . x * z2 . y ) / d ); } p u b l i c s t a t i c String toString ( Complex z ) { r e t u r n z.x + "+" + z.y + "i"; } ... } Implementação: TestComplex.java p u b l i c c l a s s TestComplex { p u b l i c s t a t i c v o i d main ( String [] args ) { Complex z1 = new Complex (5.0 , 6.0); System . out . println ( " z1 = " + LibComplex . toString ( z1 )); Complex z2 = new Complex ( -2.0 , 3.0); System . out . println ( " z2 = " + LibComplex . toString ( z2 )); Complex z3 = LibComplex . mul ( z1 , z2 ); System . out . println ( " z3 = " + LibComplex . toString ( z3 )); Complex z4 = new Complex (0.0 ,0.0); System . out . println ( " z4 = " + LibComplex . toString ( z4 )); Complex z5 = LibComplex . div ( z3 , z4 ); System . out . println ( " z5 = " + LibComplex . toString ( z5 )); } } Cor Cor Cor Cor TAD Color: cor RGB I caracterizado por 3 números, as componentes nas 3 cores primárias R, G e B I int red, green, blue operações incluem: I I I I I I I Color getRed(Color) Color getGreen(Color) Color getBlue(Color) Color toGray(Color) String toString(Color) vamos definir 2 classes: Color para guardar as componentes e LibColor para implementar as operações Implementação: Color.java p u b l i c f i n a l c l a s s Color { f i n a l i n t red ; f i n a l i n t green ; f i n a l i n t blue ; // constructor p u b l i c Color ( i n t r , i n t g , i n t b ) { red = r; green = g ; blue = b ; } } Implementação: LibColor.java i m p o r t java . lang . Math ; p u b l i c c l a s s LibColor { p u b l i c s t a t i c Color getRed ( Color c ) { r e t u r n new Color ( c . red ,0 ,0); } p u b l i c s t a t i c Color getGreen ( Color c ) { r e t u r n new Color (0 , c . green ,0); } p u b l i c s t a t i c Color getBlue ( Color c ) { r e t u r n new Color (0 ,0 , c . blue ); } p u b l i c s t a t i c Color toGray ( Color c ) { d o u b l e lum = 0.299* c . red + 0.587* c . green + 0.114* c . blue ; i n t gray = ( i n t ) Math . round ( lum ); r e t u r n new Color ( gray , gray , gray ); } p u b l i c s t a t i c String toString ( Color c ) { r e t u r n " ( " + c . red + " : " + c . green + " : " + c . blue + " ) " ; } } Implementação: TestColor.java p u b l i c c l a s s TestColor { p u b l i c s t a t i c v o i d main ( String [] args ) { Color c = new Color (119 , 23 , 37); Color c1 = LibColor . getRed ( c ); System . out . println ( LibColor . toString ( c1 ) Color c2 = LibColor . getGreen ( c ); System . out . println ( LibColor . toString ( c2 ) Color c3 = LibColor . getBlue ( c ); System . out . println ( LibColor . toString ( c3 ) Color c4 = LibColor . getGray ( c ); System . out . println ( LibColor . toString ( c4 ) } } ); ); ); ); Imagem a Cores TAD Picture: imagem RGB I matriz de pontos, cada ponto é uma cor I o tamanho é dado 2 números I int width, height I Color[][] pixels operações incluem: I I I I I I I Color getColor(Picture, int, int) void setColor(Picture, int, int, Color) Picture load(String) void save(Picture, String) String toString(Picture) vamos definir 2 classes: Picture para guardar as coordenadas e LibPicture para implementar as operações Implementação: Picture.java p u b l i c f i n a l c l a s s Picture { f i n a l i n t width ; f i n a l i n t height ; Color [][] pixels ; // constructor p u b l i c Picture ( i n t w , i n t h ) { width = w ; height = h ; pixels = new Color [ width ][ height ]; } } Implementação: LibPicture.java p u b l i c c l a s s LibPicture { p u b l i c s t a t i c Color getColor ( Picture p , i n t i , i n t j ) { r e t u r n p . pixels [ i ][ j ]; } p u b l i c s t a t i c v o i d setColor ( Picture p , i n t i , i n t j , Color c ){ p . pixels [ i ][ j ] = c ; } p u b l i c s t a t i c Picture load ( String filename ) { ... } p u b l i c s t a t i c v o i d save ( Picture p , String filename ) { ... } p u b l i c s t a t i c String toString ( Picture p ) { r e t u r n p . width + " x " + p . height + " RGB image " ; } } Implementação: TestPicture.java p u b l i c c l a s s TestPicture { p u b l i c s t a t i c v o i d main ( String [] args ) { Picture q = LibPicture . load ( " ./ snake . png " ); LibPicture . save ( greyScale ( q ) , " ./ output . png " ); } p u b l i c s t a t i c Picture greyScale ( Picture p ) { Picture q = new Picture ( p . width , p . height ); f o r ( i n t i = 0; i < p . width ; i ++) f o r ( i n t j = 0; j < p . height ; j ++) { Color c = LibPicture . getColor (p , i , j ); LibPicture . setColor (q , i , j , LibColor . toGray ( c )); } r e t u r n q; } } Conjunto de Mandelbrot dada a recorrência: z = 0 0 2 z n+1 = zn + c com c, z ∈ C, o conjunto de Mandelbrot, M, é definido por: M = {c ∈ C | lim sup |zn+1 | ≤ 2} n→∞ Implementação: Mandelbrot.java public class static final static final static final static final static final Mandelbrot { d o u b l e xCenter d o u b l e yCenter d o u b l e width int picSize int maxIter = -0.70; = 0.0; = 2.6; = 1024; = 255; p u b l i c s t a t i c v o i d main ( String [] args ) { Picture p = new Picture ( picSize , picSize ); f o r ( i n t i = 0; i < picSize ; i ++) f o r ( i n t j = 0; j < picSize ; j ++) { d o u b l e x = xCenter - width / 2 + width * i / picSize ; d o u b l e y = yCenter - width / 2 + width * j / picSize ; i n t k = iterate (new Complex (x , y ) , maxIter ); LibPicture . setColor (p , i , picSize - 1 - j , pickColor ( k )); } LibPicture . save (p , " ./ mandelbrot . png " ); } ... } Implementação: Mandelbrot.java p u b l i c c l a s s Mandelbrot { ... p u b l i c s t a t i c i n t iterate ( Complex c , i n t maxIter ) { Complex z = c ; f o r ( i n t i = 0; i < maxIter ; i ++) { i f ( LibComplex . abs ( z ) > 2.0) r e t u r n i; z = LibComplex . add ( LibComplex . mul (z , z ) , c ); } r e t u r n maxIter ; } p u b l i c s t a t i c Color pickColor ( i n t k ) { r e t u r n new Color ( maxIter - k , maxIter - k , maxIter - k ); } } Conjunto de Mandelbrot