ESTRUTURADE DADOS Profa. J ane Mestre em Engenharia de Sistemas e Computação – COPPE /UFRJ Conteudista de Estrutura de Dados Aula 1 AULA 1 Unidade 1 : Introdução Unidade 2 : Funções 2 MOTIVAÇÃO PARA O ESTUDO DE ESTRUTURA DE DADOS Para a solução de um problema é importante determinarmos uma abstração da realidade, o que significa representar as informações (dados) que são relevantes para a solução deste problema. A abstração pode ser vista como uma simplificação dos dados. Exemplo : Considere um cadastro de alunos de uma escola. Existem dados relevantes (nome, matrícula, disciplinas, ano ...) e irrelevantes (cor dos olhos do aluno, cor da mochila, marca da borracha ...). 3 Como escolher os dados relevantes ? Analisando as características do problema a ser resolvido. Uma vez feito isto, como representar estas informações ? A escolha da forma de representar os dados não é trivial e vai depender das relações existentes entre tais dados, ou seja, da organização dos dados e também, da forma com que eles serão manipulados para a solução do problema. 4 Niklaus Wirth : programa = algoritmo + dados Para programar é fundamental sabermos como organizar (estruturar) os dados dos nossos programas e realizar operações (manipulações) sobre tais dados, através das instruções dos algoritmos. 5 PORTANTO : As estruturas de dados estudam as relações lógicas existentes entre os dados (ex: relação linear, relação hierárquica ..) e serão manipuladas através de operações sobre os dados (ex: consultar uma informação em um conjunto de fichas de alunos, remover um assinante de uma lista de assinantes, apagar um diretório em uma árvore de diretórios e subdiretórios...). A escolha da estrutura de dados a ser utilizada, refletirá diretamente na construção de uma solução mais eficiente ou menos eficiente para o problema. 6 1) Como representar a estrutura organizacional de uma empresa com 1 presidente, 1 vice-presidente, 2 diretores (Vendas e Finanças) e 3 sub-diretores ? 2) Como representar o conjunto de livros informados nesta disciplina ? 3) Como organizar o esquema de tele-entrega de pizzas ? Imagine uns 4 tipos de pizzas. Como devem ser organizadas, estruturadas para que o esquema de entrega seja mais adequado ? Imagine como as pizzas podem ser organizadas na garupa da moto de um moto-boy. 7 Exemplos : Como você representaria graficamente e de forma livre, sem formalismos, cada item a seguir ? 4) Como funciona o sistema de atendimento nas linhas de ônibus ? 5) Como funciona a entrega de cigarros de uma marca X na Tijuca, sabendo-se que existe uma Van que cobre 10 pontos de vendas, conectados por ruas de mão única e de mão dupla ? Como representar estes pontos e as ligações entre eles ? 8 CONCLUINDO .... Estrutura de dados linear lista, pilha, fila relação linear entre os dados (existe um 1º. elemento, um último elemento e dado um elemento qualquer (exceto o 1º. e o último), ele possui um antecessor e um sucessor.) Exemplos : 2, 3 e 4 Estrutura de dados não lineares árvore e grafo. No caso de árvore, existe uma relação de hierarquia, de subordinação. Já no caso do grafo, existe possibilidade de relação entre quaisquer elementos. Exemplos 1) e 5) – slides 20 e 21 9 Objetivo do curso : o estudo de listas lineares (lista, pilha e fila). Tais estruturas manipulam dados do mesmo tipo e existe uma linearidade, pois pode-se determinar o primeiro elemento da lista, seu último elemento, e uma vez determinado um elemento qualquer, que não seja o 1º. e nem o último, ele possui um antecessor e um sucessor. 10 Listas lineares: definição e identificação dos tipos quanto às formas de armazenamento (seqüencial e encadeada). Os elementos de uma lista linear são denominados nós ou nodos. Como representar na memória do computador os dados organizados de forma linear ? Há 2 formas : sequencial (contígua) : os dados estão dispostos de forma seqüencial na memória, um após o outro, em endereços seqüenciais ou contíguos. Devemos pré-definir o tamanho máximo da lista. (1ª. parte do curso) encadeada : os dados estão dispostos de forma encadeada na memória, não seguindo uma ordem seqüencial, mas sim um armazenamento aleatório. Não é preciso pré-definir um tamanho máximo. (2ª. parte do curso) 11 LISTAS LINEARES SEQUENCIAIS Que recurso devemos usar para implementar as listas sequencias já que os dados são todos do mesmo tipo, estão alocados de forma contígua na memória e há um tamanho máximo pré-definido ? Resposta : vetor Que manipulações poderão ser feitas com os dados das listas sequencias ? Ou seja, que operações iremos estudar ? 12 POSSÍVEIS OPERAÇÕES Imagine uma lista com as notas dos alunos de uma turma. Como posso manipular as notas ? Primeiramente, não há notas, ou seja, a lista está vazia. Depois, podemos ... adicionar uma nota, e mais outra, etc. (adicionar = operação de inserção). remover alguma nota (operação de remoção), substituir uma nota (operação de substituição), procurar por uma certa nota (operação de busca ou pesquisa), listar todas as notas armazenadas (operação de percurso), etc ... Todas as operações indicam como os dados vão ser manipulados e serão implementadas respeitando as representações lógica e física. 13 FUNÇÃO Cada operação de listas poderá ser programada por um módulo de código denominado FUNÇÃO, que poderá ser ativado a qualquer momento. O uso de função implica em reaproveitamento de código. 14 FUNÇÃO Funções pré-definidas Exemplos : abs pow sqrt system Criando nossas próprias funções para definir as operações das estruturas a serem estudadas. 15 MOTIVAÇÃO E DEFINIÇÃO DE FUNÇÕES Exemplo : Seja o trecho int x; x = -4; cout << “Valor absoluto de “ << x << “ = “ << abs(x) << endl; Note : x = -4 abs(x) é 4 x = 0 abs(0) é 0 x = 4 abs(4) é 4 16 Chamada para a função abs O que você faria se não houvesse uma função já programada como a abs e você tivesse que calcular o módulo de um número inteiro em diversas etapas do seu programa ? 17 Imagine que você não fizesse isso seguidamente, de forma a usar um loop, tendo que realmente, repetir código várias vezes em trechos distantes do seu programa. 18 POSSÍVEIS SOLUÇÕES : Solução (a pior): Repetir código Considerando que num é uma variável inteira e a entrada já foi lida, o trecho seria : if (num >= 0) cout << “Valor absoluto = “ << num << endl; else cout << “Valor absoluto = “ << -num << endl; Solução (a melhor): Se não existisse uma função abs na linguagem, a melhor solução seria que o trecho virasse uma função, pois desta forma, seria possível chamá-la toda vez que fosse necessário. 19 FUNÇÕES Vamos criar um programa, passo a passo, a fim de analisar várias possibilidades. Possibilidades : 1) Função sem parâmetros e sem retorno. //Definição da função void iniciar(void) { cout << “Autora do programa : Jane “ << endl << “Iniciando o programa .... “ << endl; } 20 Exemplo : //Declaração da função void iniciar(void); //Chamada na main iniciar(); 21 tipo do dado retornado pela função – neste caso, não há retorno parâmetros – neste caso não há parâmetros 2) Função sem parâmetros e que retorna um valor (inteiro ou real ou caracter) Exemplo : Vamos calcular algo com a função ? //Definição da função int somar1() { int x, y; //variáveis locais a função somar cout << “Digite dois valores para soma : “; cin >> x >> y; return x+y; // ou também : return (x+y); } 22 //Protótipo ou declaração da função int somar1(); //Pode ser também : int somar1(void); //Trecho da chamada na main Considere int resultado; //declaração feita na main resultado = somar1(); //chama a função somar1 23 TRECHO DO PROGRAMA: #include <iostream> using namespace std; //Protótipos das funções iniciar e somar void iniciar(void); int somar1(); //Prog. principal int main() { int resultado; //variável local a main iniciar(); //chama a função iniciar resultado = somar1(); cout << “Resultado : “ << resultado <<endl; } //Definições das funções iniciar e somar // como já mostrado ... Aqui ! 24 3) Função que recebe um ou mais parâmetros passados por valor, faz cálculos e retorna um valor. Exemplo : //Protótipo int somar2(int, int); // Trecho da main int resultado, a, b; //variáveis locais a main //Definir valores para a e b resultado = somar2(a,b); //chama a função somar2 cout << “Resultado = “ << resultado << endl; 25 a e b são argumentos da fç. //Definição da função int somar2(int p, int q) { int r; r = p + q; return r; } 26 p, q e r são variáveis locais à função somar2. p e q são os parâmetros da função somar2. Na chamada da função são passados apenas os valores armazenados nas variáveis a e b (argumentos da função) . O valor da variável r é retornado para o ponto da chamada da função. Atenção : Os parâmetros passados por valor funcionam como variáveis locais e são cópias dos argumentos da chamada da função. 27 4) Função que recebe parâmetros passados por valor, os usa e não retorna nada. Exemplo : void somar3(int a, int b) //Definição da função { cout << “Soma = “ << a+b << endl; } Como seria o protótipo ? void somar3(int , int); 28 Parâmetros a e b Indica que nada será retornado. 5) Função que recebe parâmetros passados por valor, modifica algum deles (ou todos) e não retorna valor algum. Atenção : Os argumentos da chamada não serão realmente modificados. Exemplo : //Definição da função void falsaMudanca(int a, int b) { a++; //incrementa a b--; //decrementa b } //Chamada da função – trecho na main : int x = 10, y = 20; falsaMudanca(x,y); cout << “X = “ << x << “ Y = “ << y << endl; 29 O que será impresso na tela ? X = 10 Y = 20 Os argumentos x e y não foram modificados. 6)Função que recebe parâmetro passado por referência, o modifica e nada retorna. Atenção para o uso de &. Exemplo : void mudar(int & a, int & b) { a++; b--; } //Trecho – chamada na main : int x = 10, y = 20; mudar(x,y); cout << “X = “ << x << “ Y = “ << y << endl; 30 Protótipo da função : void mudar (int &, int &); O que será impresso na tela ? X = 11 Y = 19 VARIÁVEIS GLOBAIS X VARIÁVEIS LOCAIS Variáveis globais : declaradas fora do escopo das funções. Variáveis locais : declaradas no escopo de qualquer função, seja a main ou qualquer outra função. 31 EXERCÍCIOS Assinale a estrutura de dados que pode ser usada para representar cada um dos casos descritos a seguir. Justifique, resumidamente, sua resposta. 1) Na maioria dos sistemas operacionais, os arquivos são organizados hierarquicamente em um esquema de diretórios (pastas) e sub-diretórios. Opções : A) ( ) pilha B) ( ) fila C) ( ) árvore D) ( ) grafo 32 2) Navegadores para internet armazenam os últimos endereços visitados em uma estrutura de dados. Cada vez que um novo site é visitado, o endereço do site é adicionado na estrutura de endereços. Quando se aciona o retorno (“back”), o navegador permite que o usuário retorne no último site visitado e retira o endereço do site da estrutura de dados. Opções : A) ( ) pilha B) ( ) fila C) ( ) árvore D) ( ) lista 33 3) Faça um programa em C++ para ler a largura e o comprimento de um retângulo, calcular e imprimir o valor da área. O cálculo da área deverá ser feito por uma função que receberá a largura e o comprimento como parâmetros e retornará o valor calculado da área. Protótipo da função : double calcularAreaVersao1(double, double); 34 4) Considere o exercício 3 e escreva uma função diferente para o cálculo da área de acordo com o seguinte protótipo : void calcularAreaVersao2(double, double, &double); A função receberá a largura e o comprimento passados por valor e receberá um parâmetro area passado por referência, cujo objetivo é armazenar o resultado do cálculo da área. 35