Baixe o app para aproveitar ainda mais
Prévia do material em texto
MC202 - Estruturas de Dados Emilio Francesquini francesquini@ic.unicamp.br Instituto de Computação - UNICAMP Aula 01 - 3 de março de 2017 francesquini@ic.unicamp.br Disclaimer • Esses slides foram preparados para um curso de Estrutura de Dados ministrado na UNICAMP • Este material pode ser usado livremente desde que sejam mantidos os créditos dos autores e da instituição. • Muitos dos exemplos apresentados aqui foram retirados de materiais preparados pelos Profs. Tomasz Kowaltowski e Orlando Lee da UNICAMP assim como do Prof. Paulo Feofiloff do IME-USP Objetivos • O objetivo fundamental de projetar um algoritmo é resolver um problema computacional de modo eficiente. • Muitas vezes, a organização dos dados em um programa (algoritmo) pode ser a diferença entre obter uma Ferrari e obter uma carroça. • A disciplina Estruturas de Dados tem por objetivo apresentar métodos e ideias para organizar dados e por conseguinte aumentar a eficiência de um programa. (educação Vs. treino) MC202 - Aula 1 Introdução 3 / 32 O que esperar deste curso • Vocês aprenderão como desenvolver programas eficientes e elegantes utilizando soluções refinadas ao longo de anos • Vocês NÃO vão aprender a usar programas e sites (como Office, Google, etc...) • Vocês vão, porém, entender como estes programas funcionam por baixo dos panos. MC202 - Aula 1 Introdução 4 / 32 Pré-requisitos • Entender ponteiros • Entender ponteiros • Entender ponteiros • Entender recursão • Entender e projetar algoritmos recursivos • Conhecimento da linguagem de programação C MC202 - Aula 1 Introdução 5 / 32 Pré-requisitos • Entender ponteiros • Entender ponteiros • Entender ponteiros • Entender recursão • Entender e projetar algoritmos recursivos • Conhecimento da linguagem de programação C MC202 - Aula 1 Introdução 5 / 32 Pré-requisitos • Entender ponteiros • Entender ponteiros • Entender ponteiros • Entender recursão • Entender e projetar algoritmos recursivos • Conhecimento da linguagem de programação C MC202 - Aula 1 Introdução 5 / 32 Pré-requisitos • Entender ponteiros • Entender ponteiros • Entender ponteiros • Entender recursão • Entender e projetar algoritmos recursivos • Conhecimento da linguagem de programação C MC202 - Aula 1 Introdução 5 / 32 Pré-requisitos • Entender ponteiros • Entender ponteiros • Entender ponteiros • Entender recursão • Entender e projetar algoritmos recursivos • Conhecimento da linguagem de programação C MC202 - Aula 1 Introdução 5 / 32 Pré-requisitos • Entender ponteiros • Entender ponteiros • Entender ponteiros • Entender recursão • Entender e projetar algoritmos recursivos • Conhecimento da linguagem de programação C MC202 - Aula 1 Introdução 5 / 32 Revisão relâmpago • Variáveis, tipos básicos (int, float, double, char, long), atribuições. • Vetores e registros • Ponteiros e alocação dinâmica de memória • Recursão Material adicional cobrindo estes pontos disponível em: http://www.ic.unicamp.br/~francesquini/mc102/ MC202 - Aula 1 Revisão 6 / 32 http://www.ic.unicamp.br/~francesquini/mc102/ Variáveis • Declaração de variáveis Tipo a, b; • Tipo pode ser um tipo pré-definido (int, char, double) ou um tipo definido pelo programador (struct, union). • Escrevendo a ou b podemos acessar ou modificar o conteúdo da variável correspondente. int a, b; a = 2; b = 3 * a + 1; MC202 - Aula 1 Revisão 7 / 32 Ponteiros • Declaração de variáveis ponteiros Tipo *p; • A variável p pode armazenar um endereço da memória que armazena uma informação do tipo Tipo. Dizemos que p aponta para aquele endereço da memória. int a, b; int *p; a = 2; p = &a; MC202 - Aula 1 Revisão 8 / 32 Ponteiros • O operador ∗ permite acessar ou modificar o conteúdo da posição de memória apontada por p. int a, b; int *p; a = 2; p = &a; b = *p; *p = 7; • Note a diferença entre o uso de ∗ na declaração e como operador. MC202 - Aula 1 Revisão 9 / 32 Ponteiros • Toda variável deve ser inicializada! Ainda mais variáveis ponteiros, pois senão podem ocorrer erros imprevisíveis! int a, b; int *p; a = 2; printf("a: %d b: %d p: %d", a, b, *p); /*surpresinha*/ b = *p; /*ruim*/ *p = 7; /*pior ainda*/ MC202 - Aula 1 Revisão 10 / 32 Ponteiros - O código abaixo funciona? void troca(int a, int b) { int t; t = a; a = b; b = t; } ... int a, b; a = 2; b = 7; troca(a,b); MC202 - Aula 1 Revisão 11 / 32 Ponteiros - O código abaixo funciona? void troca(int a, int b) { int t; t = a; a = b; b = t; } ... int a, b; a = 2; b = 7; troca(a,b); • Não! A função troca não troca os valores dos argumentos. • Em C, os argumentos são sempre passados por valor (são cópias). MC202 - Aula 1 Revisão 11 / 32 Ponteiros - O código abaixo funciona 2? void troca(int *pa, int *pb) { int t; t = *pa; *pa = *pb; } ... int a, b; *pb = t; a = 2; b = 7; troca(&a, &b); MC202 - Aula 1 Revisão 12 / 32 Ponteiros - O código abaixo funciona 2? void troca(int *pa, int *pb) { int t; t = *pa; *pa = *pb; } ... int a, b; *pb = t; a = 2; b = 7; troca(&a, &b); • Sim!! A função troca faz o serviço • Ao passar os endereços como argumentos é possı́vel acessar ou modificar as variáveis originais MC202 - Aula 1 Revisão 12 / 32 Structs • O tipo struct permite agregar variáveis e definir um novo tipo. struct Fruta { char nome[30]; float preco; } struct Fruta a = {"caqui", 2.0}, b, c; • Pode-se fazer atribuição direta entre variáveis do mesmo tipo struct, mas não comparação. c = a; b = {"mamao", 3.0}; /* errado! */ if (c == a) /* errado! */ printf("Mesma fruta!\n"); MC202 - Aula 1 Revisão 13 / 32 typedef • O operador typedef permite criar sinônimos para tipos. typedef float real; struct Fruta{ char nome[30]; real preco; } typedef struct Fruta Fruta; /*nao errei*/ Fruta a = {"caqui", 2.0}, b, c; MC202 - Aula 1 Revisão 14 / 32 Cadastro de frutas typedef struct Fruta { char nome[30]; float preco; } typedef struct Cadastro { Fruta fruta; int vazio; } TipoCadastro; TipoCadastro cadastro[MAX]; /*Funcoes de manipulacao*/ void inicializa(void); int insere(Fruta f); void remove(char *nome); int procura(char *nome); MC202 - Aula 1 Revisão 15 / 32 Cadastro de frutas void inicializa(void) { int i; for (i = 0; i < MAX; i++) cadastro[i].vazio = 1; } MC202 - Aula 1 Revisão 16 / 32 Cadastro de frutas int insere(Fruta f) { int i = 0; while (i < MAX && !cadastro[i].vazio) i++; if (i < MAX) cadastro[i].fruta = f; return (i < MAX); } MC202 - Aula 1 Revisão 17 / 32 Cadastro de frutas void remove(char *nome) { int i = 0; while (i < MAX) { if (!cadastro[i].vazio && !strcmp(cadastro[i].fruta.nome, nome)) { cadastro[i].vazio = 1; break; } MC202 - Aula 1 Revisão 18 / 32 Cadastro de frutas int procura(char *nome) { int i = 0; while (i < MAX) { if (!cadastro[i].vazio && !strcmp(cadastro[i].fruta.nome, nome)) { break; } else i++; if (i < MAX) return i; else return -1; } } MC202 - Aula 1 Revisão 19 / 32 Cadastro de frutas • A implementação da função procura devolve um índice do vetor cadastro. • Entretanto, isto não é totalmente satisfatório, pois o usuário teria acesso ao campo vazio da estrutura TipoCadastro. • O ideal seria esconder esta informação do usuário. Ele só se interessa pelo campo fruta e não precisa saber como o cadastro é implementado internamente. • Basta devolver um ponteiro para a estrutura do campo fruta. MC202 - Aula 1 Revisão 20 / 32 Cadastro de frutas • A implementação da função procura devolve um índice do vetor cadastro. • Entretanto, isto não é totalmente satisfatório, pois o usuário teria acesso ao campo vazio da estrutura TipoCadastro. • O ideal seria esconder esta informação do usuário. Ele só se interessa pelo campo fruta e não precisa saber como o cadastro é implementado internamente. • Basta devolver um ponteiro para a estrutura do campo fruta. MC202 - Aula 1 Revisão 20 / 32 Cadastro de frutas • A implementação da função procura devolve um índice do vetor cadastro. • Entretanto, isto não é totalmente satisfatório, pois o usuário teria acessoao campo vazio da estrutura TipoCadastro. • O ideal seria esconder esta informação do usuário. Ele só se interessa pelo campo fruta e não precisa saber como o cadastro é implementado internamente. • Basta devolver um ponteiro para a estrutura do campo fruta. MC202 - Aula 1 Revisão 20 / 32 Cadastro de frutas • A implementação da função procura devolve um índice do vetor cadastro. • Entretanto, isto não é totalmente satisfatório, pois o usuário teria acesso ao campo vazio da estrutura TipoCadastro. • O ideal seria esconder esta informação do usuário. Ele só se interessa pelo campo fruta e não precisa saber como o cadastro é implementado internamente. • Basta devolver um ponteiro para a estrutura do campo fruta. MC202 - Aula 1 Revisão 20 / 32 Ponteiros para structs Fruta* procura(char *nome) { int i = 0; while (i < MAX) { if (!cadastro[i].vazio && !strcmp(cadastro[i].fruta.nome, nome)) { break; } else i++; if (i < MAX) return &(cadastro[i].fruta); else return NULL; } MC202 - Aula 1 Revisão 21 / 32 Ponteiros para structs Fruta* procura(char *nome) { int i = 0; while (i < MAX) { if (!cadastro[i].vazio && !strcmp(cadastro[i].fruta.nome, nome)) { break; } else i++; if (i < MAX) return &(cadastro[i].fruta); else return NULL; } • É comum em C escrever p->preco em vez de (*p).preco. A maioria dos textos e códigos usa esta notação. MC202 - Aula 1 Revisão 22 / 32 Alocação dinâmica – malloc • A função malloc permite alocar uma quantidade de memória especificada pelo usuário. TipoCadastro inicializa(int n) { TipoCadastro *p; int i; p = malloc(n*sizeof(TipoCadastro); for (i = 0; i < MAX; i++) p[i].vazio = 1; return p; } ... TipoCadastro *cadastro; cadastro = inicializa(MAX); • O restante do código não muda. MC202 - Aula 1 Revisão 23 / 32 Alocação dinâmica – free • A função free desaloca memória alocada previamente. void finaliza(void) { free(cadastro); } • Todo malloc pede um free. Lembre-se disso ao programar. • Não existe free sem o malloc correspondente MC202 - Aula 1 Revisão 24 / 32 Vetores vs. ponteiros • Do ponto de programação, um vetor nada mais é do que o endereço do primeiro elemento do vetor. int vetor[MAX]; int *p; for (i = 0; i < MAX; i++) vetor[i] = 0; p = vetor; /* p = &(vetor[0]) */ for (i = 0; i < MAX; i++) p[i] = 0; /* *(p+i) = 0 */ MC202 - Aula 1 Revisão 25 / 32 Alocação dinâmica de matrizes Declaração estática float mat[MAXLIN][MAXCOL]; Alocação parcialmente dinâmica float *mat[MAXLIN]; /* vetor de ponteiros! */ for (i = 0; i < MAXLIN; i++) mat[i] = malloc(MAXCOL * sizeof(float)); ... mat[i][j] = 3.1416; MC202 - Aula 1 Revisão 26 / 32 Alocação dinâmica de matrizes Alocação dinâmica float **mat; /* vetor de ponteiros dinamico */ mat = malloc(MAXLIN * sizeof(float *)); for (i = 0; i < MAXLIN; i++) mat[i] = malloc(MAXCOL * sizeof(float)); ... mat[i][j] = 3.1416; MC202 - Aula 1 Revisão 27 / 32 Recursão MC202 - Aula 1 Revisão 28 / 32 Recursão MC202 - Aula 1 Revisão 29 / 32 Recursão - Fatorial • Problema: Calcular o fatorial de um número (n!). • Qual o caso base e o passo da indução? • Se n é igual a 1, então o fatorial é 1. • Qual seria o passo indutivo? • Temos que expressar a solução para n > 1, supondo que já sabemos a solução para algum caso mais simples. • n! = n ∗ (n − 1)! • Este caso é trivial pois a própria definição do fatorial é recursiva MC202 - Aula 1 Revisão 30 / 32 Recursão - Fatorial • Portanto a solução do problema pode ser expressa de forma recursiva como: • Se n = 1 então n! = 1 • Se n > 1 então n! = n ∗ (n − 1)! • Note como aplicamos o princípio da indução • Sabemos a solução para o caso base n = 1 • Definimos a solução do problema geral n! em termos do mesmo problema só que para um caso menor ((n − 1)!) MC202 - Aula 1 Revisão 31 / 32 Recursão - Fatorial long fatr(long n){ long x,r; if(n == 1) //Passo Basico return 1; else { x = n - 1; r = fatr(x); //Sabendo o fatorial de (n-1) return (n* r); //calculamos o fatorial de n } } • Para solucionar o problema é feita uma chamada para a própria função, por isso, esta função é chamada recursiva. • Recursividade geralmente permite uma descrição mais clara e concisa dos algoritmos, especialmente quando o problema é recursivo por natureza. MC202 - Aula 1 Revisão 32 / 32 Cover Section Aviso Introdução Revisão
Compartilhar