Estruturas de Dados - T.332 Capítulo 4.1 Tipos Abstratos de Dados INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 1 Abstração Abstrato tem sido definido como: dissociado de qualquer instância específica, ideal, expressando uma qualidade separadamente do objeto representado. Abstração envolve a descoberta de qualidades essenciais de um objeto concreto ou grupo de objetos, dando a estas um nome: descrevemos aspectos essenciais da estrutura de um objeto ou conceito, descrevemos o comportamento de um objeto ou conceito nomeando aspectos importantes deste. INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 2 Exemplo: 2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40 30,40,22,32,36,20,34,4,18,26,6,2,38,16,12,28,8,14,10,40 É fácil memorizarmos os números da 1ª série, pois precisamos apenas memorizar a sua regra de formação. Para a segunda série, necessitamos rememorar os números. A abstração facilita descrever fatos: teríamos muita dificuldade de lidar com o mundo, se lembrássemos sempre de todos os detalhes de coisas, ao invés de abstrair e generalizar. INE - UFSC O nível de abstração com que descrevemos algo é chamado de granularidade. - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 3 Abstração em Programação A idéia de abstração é aplicada ao idealizarmos um programa de computador. Quando queremos construir um programa de computador (sistema) estamos querendo resolver um problema real: Descrevemos que informação é necessária, Descrevemos, incialmente de forma sucinta, o comportamento que o programa deve possuir, para resolver este problema. Estamos abstraindo do problema real para tratar de seus aspectos esseciais, descrevendo-os. Em programação usamos diversos tipos de abstração: INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 4 Procedimento geral para a solução de um problema: Problema Solução P0 S0 decomposição composição P1 S1 P1-2 P2 INE - UFSC - S4 P3 solução Disciplina Estruturas de Dados S2 - Prof. Dr. Aldo von Wangenheim S3 Página 5 Abstração Procedural Um programa é um conjunto de instruções que executa uma tarefa: Esta tarefa geralmente vai ser complexa, mas pode ser descrita sucintamente em palavras, É lógico agrupar um conjunto de instruções que realiza uma tarefa especíca dentro do todo sob um nome: INE - UFSC - Facilita o projeto de um sistema, pois iniciamos com um descrição muito abstrata, que vamos detalhando. Facilita a compreensão de um sistema complexo, se organizarmos conjuntos de intruções para uma tarefa sob um nome. Chamamos a isso de procedimentos, funções (em "C") ou métodos (em OOP). Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 6 Abstração Procedural (definição): Nomear um conjunto de ações, instruções ou código de forma que ele possa ser manipulado ou executado simplesmente através de seu nome. Parametrização: Podemos separar o que é fixo ou interno em um procedimento do que é variável, dependente do mundo "exterior", parametrizando a parte variável: • normalmente os dados que o procedimento manipula. INE - UFSC - Através da parametrização podemos utilizar o mesmo procedimento em diferentes contextos, com diferentes dados. Como procedimentos podem ser chamados de outros, temos assim um mecanismo para abstrações de nível mais alto. A parametrização garante que procedimentos não terão efeitos indesejados sobre dados "externos". Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 7 Tipos Abstratos de Dados: ADTs ou TADs É muito mais conveniente descrever-se algoritmos e conjuntos de dados em termos das operações efetuadas mais intuitivo do que se descrever todos os detalhes de uma implementação, Podemos descrever uma estrutura de dados como uma pilha ou lista nestes termos, programando-a de acordo com esta idéia, isto é chamado tipo abstrato de dado. Uma característica básica é que nada externo às definições de dados e algoritmos de um TAD deva referenciar a sua estrutura interna e vice-versa. Mecanismo sistemático para facilitar o desenvolvimento de grandes sistemas. INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 8 Tipos Abstratos de Dados: Abstração de dados: Uma abstração de dados consiste das três partes seguintes: Um conjunto S de objetos, cuja estrutura de representação é irrelevante, Um conjunto P de operações defindas sobre os elementos de S, Um conjunto R de regras que definem as operações e os relacionamentos entre os elementos de S. Tipo Abstrato de Dado: Um conjunto de abstrações de dados, cada qual com seus elementos, operações e regras próprios. Exemplo clássico: pilha, lista INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 9 Tipos Abstratos de Dados X OOP Conceitos muito semelhantes TADs são uma técnica programação concisa e eficiente, semelhante à OOP, só que baseada em linguagens de programação de 3ª geração (estruturadas). Diferenças: em TADs, a tarefa de definir quais procedimentos são aplicáveis a quais estruturas de dados, é função do programador. em OOP a sintaxe da linguagem e o compilador garantem que um objeto (como conjunto de dados) "saiba" quais operações são aplicáveis a ele. INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 10 Procedimento organizacional em TADs Concepção: Semelhante à OOP Concebemos um Objeto (TAD) atraves da descrição do comportamento que queremos que tenha de de quais dados deve "conter" (Top-Down) Programação: Organizamos um programa em Módulos, cada qual contendo um ou mais TADs relacionados Um módulo contem a declaração de tipo de dados e as funções relativas a um TAD. INE - UFSC Ex.: Uma lista deve poder receber e devolver elementos, deve conter os elementos em um ordem, etc. Através de refinamentos sucessivos detalhamos esta descrição. - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 11 Organização Geral Programa principal: aplica.c #include <stdio.h> #include <stdio.h> typedef struct lista{ int elemento; lista *proximo; } main () { char *a, *b; lista *minhaLista, *outraLista; lista *criaLista(int tam) { - - } lista *retiraDaLista() { int localA, localB; localA = func_A(); localB = func_A(); } minhaLista = criaLista(20); ..... ..... } INE - UFSC - Disciplina Estruturas de Dados Módulo Lista: lista.c - Prof. Dr. Aldo von Wangenheim Página 12 Vantagens Reutilizabilidade Um TAD bem programado eu posso utilizar em muitos programas. Abstração Se eu uso um TAD simplesmente prestando atenção às qualidades e ao comportamento que ele exporta, a minha vida fica mais fácil. Manutenibilidade Se eu quiser que as Listas que eu uso no meu programa se comportem diferente, eu só preciso fazer alterações no TAD INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 13 Recursos de"C" para a criação de TADs Aspectos procedurais (comportamentais): Funções ou Procedimentos (funções tipo void). Aspectos de estruturas de dados: Declaração de tipos derivados estruturados: estruturas são tipos de dados definidos pelo programador que têm um nome e representam um conjunto de um ou mais tipos de dados. typedef struct Empregado { char nome[40]; char endereço[100]; char função[20]; int salário; - - } struct Empregado emp1, emp2, empX; INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 14 Usando Estruturas Estruturas podem ser declaradas e utilizadas diretamente, como se fossem variáveis: struct { char char char long nome[50]; rua[50]; cidade[30]; cep; } endereço; endereço.nome = "José Arantes"; endereço.rua = "Estrada Geral Canasvieiras"; nesse caso não estamos definindo um novo tipo, apenas declarando uma variável com uma estrutura complexa. para a referência e utilização dos campos usa-se o ponto "." imediatamente após o nome da variável. INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 15 Usando Estruturas II Estruturas são mais úteis quando utilizadas para a definição de tipos derivados estruturados typedef struct endereço { char nome[50]; char rua[50]; char cidade[30]; long cep; }; // Decl. Tipo Deriv. struct endereço meuEndereço, outroEndereço; // Decl. variáveis meuEndereço.nome = "Aldo"; meuEndereço.rua = "Rua Lauro linhares"; INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 16 Usando Ponteiros para Estruturas Uma estrutura, sendo uma variável pode ser referenciada normalmente através de um ponteiro: typedef struct endereço { char nome[50]; char rua[50]; }; // Decl. Tipo Deriv. struct endereço end1, end2; struct endereço *enderPointer; enderPointer = &end1; end2 = *enderPointer; // Decl. variáveis // Decl. ponteiro p/endereço Para acessar os campos de uma estrutura usando um ponteiro para a estrutura usamos o operador de derreferência de campo -> enderPointer->nome = "Aldo"; end2.cep = enderPointer->cep; Note que a derreferência "*" aqui não é mais necessária. INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 17 Módulo lista.h: typedef struct { char *elemento[30]; int ultimo; int max; } lista; #include <stdio.h> #include <stdlib.h> #include <lista.h> lista *criaLista () { struct lista nova; nova = malloc( sizeof(lista) ); nova->max = 30; nova->ultimo = -1; return (nova); } void destroiLista(lista *morta) { // Libera memória p/os strings for (i=0; morta->ultimo; i++) free (morta->elemento[i]); // Libera memória da lista free ( morta ); } Alguns compiladores aceitam como abaixo: typedef char int int }; INE - UFSC - struct lista{ *elemento[30]; ultimo; max; Disciplina Estruturas de Dados Módulo lista.c: - Prof. Dr. Aldo von Wangenheim Página 18 Forma de Proceder na Programação de TADs Cada TAD será escrito em arquivo separado e possuirá dois arquivos: Um arquivo <nome-do-TAD>.c contendo o código das operações realizadas sobre o TAD na forma de funções e visíveis para um programa de aplicação que o utiliza Um headerfile <nome-do-TAD>.h contendo a definição dos tipos derivados utilizados pelo TAD INE - UFSC Cada função terá sempre como seu primeiro parâmetro um ponteiro para uma instância do TAD Deve ser compilado junto com os outros arquivos Deve ser incluído através de diretiva de compilação #include em todos os arquivos Um programa principal possuirá uma função main() que utiliza as funções “exportadas” pelos TADs. - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 19 Estrutura Geral de Arquivos Programa Principal aplicacao.c #include TAD Lista Encadeada lista.c Tipos do TAD Lista Encadeada lista.h TAD Fila fila.c Tipos do TAD Fila fila.h Unidos para o compilador através de um “projeto” no NetBeans ou makefile INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 20 Exercício de Compilação em Aula INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 21 Trabalho: Sistema de Contabilidade Simples Você é um Mafioso informatizado. Você vai criar um sistema para gerenciar os seus débitos e também as pessoas que devem a você. Este sistema será baseado em duas listas encadeadas: 3 Créditos Dom Capone Scarbutt Dom Genaro 100.000,00 5,00 10.000,00 3 Débitos INE - UFSC - Dealer Kid Policial #1 Delegado Zé 500,00 5,00 100,00 Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 22 Detalhes INE - UFSC No programa principal você vai definir se vai realizar uma operação de débito ou de crédito e vai chamar as operações sobre listas necessárias, passando a lista correta como parâmetro (por referência) para a função que realiza a operação. Além das operações básicas que a Lista vai oferecer, você deve implementar uma operação adicional: totalização. Essa operação funciona assim: percorre a lista, escrevendo o nome e o valor correspondente a cada item (débito ou crédito) soma o valor em uma variável auxiliar escreve ao final o total de débitos ou de créditos, dependendo de qual lista você mandou totalizar. - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 23 Trabalho com Passagem de Parâmetros INE - UFSC Para isso você vai fazer um programa que manipula mais de uma lista; o programa fará isto com um único conjunto de funções e passagem das diversas listas como parâmetros; como aplicação imaginemos um sistema de contabilidade simples; você vai ter um Plano de Contas constituído por duas listas: débitos e créditos; o mesmo conjunto de funções (que você já implementou) vai poder ser utilizado para isso: você somente precisa ampliar o conjunto de parâmetros da função para passar por referência também a lista que você quer alterar. A passagem de parâmetro da lista deve ser por referência porque você deseja que as alterações sejam persistentes. - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 24 Modelagem de um Lançamento Cada lista de débitos ou créditos é constituída por lançamentos. Cada lançamento possui: um valor real (positivo); um nome. Por exemplo, “Pagar proteção à Mafia” Estrutura: tipo tLançamento { caracter *nome; real valor; }; INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 25 Modelagem da Lista A lista encadeada que conterá os lançamentos terá um elemento de lista definido da seguinte forma: Estrutura: tipo tLista { tLancamento* info; tLista* proximo; }; A cabeça de lista de cada lista será uma variável global contendo uma estrutura como abaixo: tipo cLista { tLista* lista; inteiro ultimo; }; INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 26 Usando (pseudo-código) Crie variáveis globais: tListaContábil débitos, créditos; Passe estas variáveis como parâmetros por referência: adiciona(&débitos, nomeLanc, valorLanc); Cabeçalho: Inteiro FUNÇÃO adiciona(tListaContábil *plano; caracter *nome; real valor); Importante: nome é passado como ponteiro para caracter. Use um buffer global para ler o nome do lançamento do usuário. INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 27 typedef struct { char texto[30]; int a; }escrita; #include <stdio.h> #include <string.h> #include "escreve.h“ void escreve(char* umTexto) { escrita meuTexto; strcpy(meuTexto.texto, umTexto); printf("%s\n\n", meuTexto.texto ); } INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 28 #include "escreve.h" main () { escreve("banana"); } gcc banana.c escreve.c -ansi -o banana -v INE - UFSC - Disciplina Estruturas de Dados - Prof. Dr. Aldo von Wangenheim Página 29 Reimplemente a lista ordenada utilizando um vetor de ponteiros para Strings como um TAD: A Lista passa a ser um TAD que possui uma representação interna do nº máximo de elementos e de qual é o último, sob a forma de um struct. Além das funções existentes, crie: a) uma que cria uma lista, alocando memória para uma estrutura com o vetor de ponteiros de tamanho max, último e max, devolvendo um ponteiro para esta e b) uma que destrói uma lista, dada por um ponteiro para ela, liberando a memória. A única variável global que um programa principal usando a lista possui, é um ponteiro apontando para esta. O progr.princ. só pode manipular a lista através das funções de acesso. INE - UFSC - Disciplina Estruturas de Dados - Elemento s Exercício-Exemplo (variante da aula de ponteiros) Lista Max Ultimo Memória alocada "Blalah" "Urgh" "Baaah " "Aaaah " main () { struct lista listaPtr; listaPtr = criaLista(); } Prof. Dr. Aldo von Wangenheim Página 30